ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Civitai 广告位系统深度解析:Snigel / Civitai Ads 多提供商编排、响应式尺寸与页面级投放策略

Civitai 广告位系统深度解析:Snigel / Civitai Ads 多提供商编排、响应式尺寸与页面级投放策略 Civitai 广告位系统深度解析Snigel / Civitai Ads 多提供商编排、响应式尺寸与页面级投放策略【免费下载链接】civitaiA repository of models, textual inversions, and more项目地址: https://gitcode.com/GitHub_Trending/ci/civitai本指南以 docs/features/ad-placements.md 为核心结合 Civitai 前端源码完整讲解项目当前正在使用的广告基础设施三家广告提供商的职责划分、全局广告开关的判定逻辑、七个 Snigel 广告位的响应式尺寸表、各页面的投放矩阵以及 Civitai 自有广告系统的回退映射与印象追踪链路。读完你将掌握这套第三方程序化广告 自有直投广告 AI 上下文广告三轨并行的广告架构是如何在 React/Next.js 代码库中落地运行的。广告提供商矩阵Civitai 目前同时接入三家广告服务各司其职Provider用途ScriptSnigel主要程序化广告主域 .com 上的 GPT/Prebid 广告链cdn.snigelweb.com/adengine/civitai.com/loader.jsCivitai Ads回退广告ad-blocked、NSFW、无 consent 场景advertising.civitai.com/api/v1/serveKontext (Megabrain)AI 驱动的上下文广告server.megabrain.co/sdk/js从源码看这套三轨设计的核心思路是按域名与场景分流Snigel 是主域.com上的主程序化流量变现通道Civitai Ads 是自有广告服务既承担第三方广告被拦截 / 内容涉 NSFW / 用户未授权 consent时的回退也承担 .red 域名的直投direct adsKontext 则只在图像生成队列等特定页面以 feature flag 控制启用。全局广告开关逻辑在 AdsProvider.tsx 中adsEnabled是全局广告的总闸门需要同时满足全部条件才开启非 dev 模式isDev false本地开发环境直接关闭广告features.isGreen为 OFFisGreen 对应 .com 域features.isBlue为 ON站点处于蓝色运营状态用户允许广告allowAds或用户不是会员isMember false当前 URL 不在屏蔽清单中当前页面路径不以/edit结尾屏蔽 URL 清单源码中的blockedUrls数组与文档完全一致const blockedUrls: string[] [ /collections/6503138, /collections/7514194, /collections/7514211, /moderator, ];判定方式是router.asPath.includes(url)即路径包含上述片段即命中此外router.asPath.split(?)[0].endsWith(/edit)会把所有编辑态页面去掉 query 后以/edit结尾排除在广告之外。源码中比文档多出的两道闸门阅读 AdsProvider.tsx 的实际实现可以发现文档之外还存在两个重要条件共同参与adsEnabled的运算browserBlocked浏览器级静默拦截部分浏览器如 Brave会通过 cosmetic filter 悄悄剔除广告元素此时 Snigel loader 的onError根本不会触发adsBlocked不可靠。因此源码在挂载时调用navigator.brave?.isBrave()一旦确认是 Brave 就直接禁用整个广告系统不加载 Snigel 脚本、不插入任何广告位。consentAllowedCIPA 同意在需要 consent 的地区Snigel loader 及其背后的 prebid/ad-tech 级联必须等用户接受后才能启动。NSFW 处理当浏览等级browsing level不是 safe 时第三方广告会被替换为 Civitai 自有广告系统——后者通过browsingLevel参数感知当前内容分级从而尊重内容浏览级别。这一点在CivitaiAdUnit的请求构造中可以直接看到/api/v1/serve会把browsingLevel${browsingLevel}随请求发出见 AdUnitFactory.tsx。每页附加条件页面附加条件图片详情页Image Detailimage.poi、image.minor或collection.metadata.hideAds任一为真则隐藏模型版本详情页Model Version Detailsmodel.nsfw或model.poi为真则隐藏瀑布流网格Masonry Grid仅当adsEnabled safeBrowsingLevel withAds三者同时成立图片详情页的条件在 ImageDetail2.tsx 中有完整实现const actualCollection collection || collectionItems[0]?.collection; const hideAds (image.poi || image.minor || actualCollection?.metadata?.hideAds) ?? false;即集合collection的metadata.hideAds字段可以在集合维度上整体屏蔽广告。域名分流.com 与 .red 的useDirectAds源码中还有一个文档之外的顶层开关useDirectAds features.isRed.comisGreen→ 走 Snigel 程序化广告.redisRed→ 只渲染CivitaiAdUnit直投广告。adsEnabled是域名无关的useDirectAds负责决定最终渲染哪套广告系统。对直投模式由于 Snigel 脚本不加载、其onLoad/onError回调不会触发源码专门用一次探针请求来探测广告拦截器——向advertising.civitai.com/api/v1/serve?placementprobenamefootercontainer1531browsingLevel1发起带 cookie 的 fetch成功则认为广告未被拦截失败则置adsBlocked: true。广告位Ad Units与响应式尺寸七个 Snigel 广告位的启停配置在 AdsProvider.tsx 的snigelPubConf.adengine.activeAdUnits中incontent_1, outstream, side_1, side_2, side_3, top, adhesive每个广告位的尺寸定义集中在 AdUnit.tsx通过adUnitFactory生成。尺寸分两种形态sizes固定尺寸列表与lutSizes按容器宽度分档的查询表。汇总如下Unit移动端0–759px平板760–1023px桌面1024pxTop320x100, 320x50, 300x250, 300x100, 300x50, 336x280468x60, 728x90728x90, 970x90, 970x250, 980x90Incontent_1320x100, 320x50, 300x250, 300x100, 300x50——Side_1——300x600, 300x250, 336x280≥1200pxSide_2——200x200, 250x250, 300x250, 336x280≥1200pxSide_3——200x200, 250x250, 300x250, 336x280Adhesive1x1, 320x50, 300x508x1, 728x908x1, 728x90, 970x90, 980x90, 970x250Outstream1x1视频1x1视频1x1视频几点源码层面的细节补充Side_1 / Side_2 的桌面档带 1200px 下限它们使用lutSizes只有容器宽度 ≥1200px 时才投放且Side_1的 120x600、160x600 超长尺寸在源码中已被注释停用实际可用的是 300x600、300x250、336x280AdUnit.tsx。Incontent_1 的 336x280 被注释当前仅保留 320x100、320x50、300x250、300x100、300x50。Outstream 用[1,1]占位尺寸真正的视频由 Snigel/Anyclip 渲染且固定广告位 id 为adngin-outstream-0卸载时会主动清理页面中所有含anyclip的脚本与 DOM 元素避免视频残留AdUnitOutstream.tsx。Adhesive粘性底条固定maxHeight{90移动端实际按 50px 高度加var(--safe-area-inset-bottom)安全区内边距渲染保证在viewport-fitcover的全面屏设备上广告不被 Home Indicator 遮挡AdhesiveAd.tsx。页面级投放矩阵全站 — AppLayout位置组件说明粘性页脚AdhesiveAd视口底部展示后有印象可关闭桌面端AdhesiveAd挂在 AppLayout.tsx通过preserveLayout{!currentUser}为未登录用户预留高度。其关闭逻辑在 AdhesiveAd.tsx设置 10 秒宽限期LOAD_FALLBACK_DELAY若期间未登记印象则视为填充失败、允许关闭回收空间广告被拦截时也可立即关闭桌面端在登记印象后同样允许关闭移动端则只在拦截/失败时可关。首页/home位置组件说明首页区块之间AdUnitTop在首页区块列表的交替位置展示信息流内AdUnitIncontent_1通过ImagesInfinite的showAds属性源码实现于 pages/home/index.tsxconst showAds i % 2 1 i 0;——即从第 2 个 home block 起每逢奇数索引1、3、5…在区块后插入AdUnitTop。模型页/models/[id]位置组件说明顶部横幅AdUnitTop位于相关资源suggested resources区域侧栏AdUnitSide_1仅当!model.poi且用户未禁用广告时模型页的侧栏条件见 pages/models/[id]/[[...slug]].tsxconst showRail !model.poi !adsDisabledByUser;随后{showRail div className{classes.rail}{canShowRail AdUnitSide_1 /}/div}。该页面还通过RenderAdUnitOutstream minContainerWidth{2800}在超宽屏投放 outstream 视频广告。帖子详情Post Detail位置组件说明左侧栏AdUnitSide_1尊重浏览级别右侧栏AdUnitSide_2尊重浏览级别视频位AdUnitOutstreamOutstream 视频广告帖子图片Post Images位置组件说明图片之间AdUnitTop每第 3 张图片后插入最大宽度 760px源码在 PostImages.tsx{i 0 (i - 1) % 3 0 AdUnitTop maxWidth{760} preserveLayout{false} /}即第 2、5、8… 张图片之后插入且preserveLayout{false}表示不预留固定高度、避免在图片流中制造空白。图片详情页/images/[id]位置组件说明右侧栏AdUnitSide_2POI、minor 或集合hideAds时隐藏底部粘性条AdhesiveAd不可关闭保持布局稳定对应 ImageDetail2.tsx{!hideAds AdUnitSide_2 /}以及{!hideAds AdhesiveAd closeable{false} preserveLayout /}——这里显式传入closeable{false}因为图片详情页的底条要始终保留占位、不能关闭。瀑布流网格Feed 页位置组件说明信息流内AdUnitIncontent_1密度随列数变化每 5–9 项插入一条网格广告的插入密度由 ads.utils.ts 的adDensity表驱动按列数给出 [min, max] 随机间隔列数间隔条15–725–735–845–95–76–9useCreateAdFeed会把数据数组与广告位交错成AdFeed{ type: data | ad }联合类型且第一条广告的落点固定随机在索引 3–5 之间后续则在上一条基础上叠加间隔区间同一列数组合的间隔矩阵会被缓存复用保证滚动过程中广告分布稳定。虚拟化网格 MasonryGridVirtual.tsx 中广告真正启用的条件比文档更严adsEnabled getIsSafeBrowsingLevel(browsingLevel) withAds (!useDirectAds || isMobile)——直投广告.red在移动端之外不参与瀑布流插播并且只在确实会渲染广告时才交错插入否则虚拟列表的行切分中会出现空单元格。聊天入口Chat Portal位置组件说明左下角浮层AdUnitOutstream仅桌面端、聊天窗口关闭时展示源码在 ChatPortal.tsx聊天未打开且非移动端时在左下角渲染AdUnitOutstreamWithCloseButton。该组件通过 adUnit.store.ts 的enableAdUnit(outstream)全局启用 outstream 位登出时自动 disable且直投模式.red下视频广告直接跳过Snigel 视频位不支持自有回退。超宽屏信息流布局Feed Layout位置组件说明OutstreamAdUnitOutstream仅在超宽屏容器 ≥3200px时启用对应 FeedLayout.tsxRenderAdUnitOutstream minContainerWidth{3200} /由useContainerLargerThan判定容器宽度。图像生成队列位置组件说明队列项之间KontextAdAI 上下文广告受 feature flagkontextAds控制Civitai 广告回退映射当第三方广告无法投放广告拦截、NSFW、未授权 consent时Civitai 自有广告系统会按以下映射接管各 Snigel 广告位。该映射在 AdUnitFactory.tsx 中以adunitToCivitaiMap常量实现Snigel UnitCivitai Placementincontent_1feedside_1side_skyside_2sideside_3sidetopbanneradhesivefooterCivitaiAdUnit拿到映射后的 placement 名后会携带placementuuid、name映射名、container容器宽度 px、browsingLevel四个参数请求advertising.civitai.com/api/v1/serve随后渲染返回的广告图片并把trace参数用于后续的view印象上报与engagement点击跳转两个接口。广告被拦截时的兜底SupportUs当adsBlocked true或consent false时AdUnitFactory.tsx 不再渲染广告容器而是直接渲染SupportUs组件——一个指向/pricing的支持 Civitai 创作者图片。这里有一个刻意的反广告过滤设计SupportUs的标记中不携带任何广告槽结构、类名、id 或尺寸因此 adblock 的 cosmetic filter按广告容器特征剥离元素不会误伤它。配图取自 ads.utils.ts 的中性文件名图片如/images/creators/wide.jpg选择规则是取能塞进槽位的最大图——先比高度再比宽度getSupportUsImage。adsBlocked采用三态设计undefined表示检测中检测窗口期内渲染空槽位占位避免约 95% 未拦截用户看到兜底图的闪烁。广告渲染与竞价流程adUnitFactory生成的每个广告组件最终都走 AdUnitFactory.tsx 的统一渲染管线首渲染生成占位 div iduuid保证竞价入队时 DOM 已存在避免 late-mounting 槽位填充失败广告位进入视口useInView且广告系统ready后向window.adngin.queue压入startAuction([{ adUnit, placement, gpIdUniquifier, sizes }])发起竞价卸载时通过googletag.pubads().getSlots()找到对应槽位并destroySlots清理lutSizes型广告位由useAdSizes依据滚动容器/窗口宽度匹配分档表选中的尺寸还会叠加maxWidth/maxHeight过滤默认preserveLayout开启用minHeight预留最大可用尺寸的高度防止广告加载时页面跳动。印象跟踪Impression Tracking广告印象通过两类自定义事件上报GPT 广告Snigel loader 就绪后googletag.pubads().addEventListener(impressionViewable)中解析 slot 的getAdUnitPath()派发civitai-ad-impression事件detail 为广告单元名Civitai 自定义广告图片加载且广告可见、页面可见后POST/api/v1/view?trace...body 携带当前匹配的 pathname成功后派发civitai-custom-ad-impression事件。两条链路最终汇入 AdsProvider.tsx 的ImpressionTracker监听civitai-ad-impression将广告单元记入adUnitsLoaded表并通过 SignalR worker 发送recordAdImpression({ userId, adId })其中 userId 为当前登录用户 idadId 为广告单元名。AdUnitAdhesive/AdUnitOutstream的可关闭能力正是依赖useImpressionTracked判断对应单元是否已登记印象。关键文件清单文件用途src/components/Ads/AdsProvider.tsx全局开关、TCF/CMP consent、Snigel 脚本加载、印象追踪src/components/Ads/AdUnit.tsx七个广告位的定义与响应式尺寸表src/components/Ads/AdUnitFactory.tsx统一渲染逻辑、竞价入队、Civitai 回退与映射src/components/Ads/AdhesiveAd.tsx粘性页脚广告含安全区与关闭宽限期src/components/Ads/AdUnitOutstream.tsx视频 outstream 广告与 Anyclip 清理src/components/Ads/ads.utils.ts信息流广告密度矩阵与 SupportUs 配图选择src/components/Ads/adUnit.store.tsoutstream 等广告位的全局启停 storesrc/components/MasonryColumns/MasonryGridVirtual.tsx瀑布流网格中广告的交错插入实现src/pages/models/[id]/[[...slug]].tsx模型页广告位含 rail 条件src/components/Image/DetailV2/ImageDetail2.tsx图片详情页广告条件poi/minor/hideAds综上Civitai 的广告体系是一个三层防御结构Snigel 程序化广告作为主变现通道Civitai Ads 承担 NSFW / 被拦截 / 无 consent 场景下的自有广告回退Kontext 则补充 AI 上下文广告全局adsEnabled总闸 每页hideAds/nsfw/poi细粒度条件 browsingLevel内容分级共同约束广告的可见性最终所有印象统一汇入 SignalR 的recordAdImpression上报链路。这一整套设计对需要在敏感内容社区中合规投放广告的同类项目具有直接参考价值。【免费下载链接】civitaiA repository of models, textual inversions, and more项目地址: https://gitcode.com/GitHub_Trending/ci/civitai创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表