Skip to content

Server-side ad templates design spec#641

Open
jevansnyc wants to merge 2 commits intomainfrom
server-side-ad-templates-spec
Open

Server-side ad templates design spec#641
jevansnyc wants to merge 2 commits intomainfrom
server-side-ad-templates-spec

Conversation

@jevansnyc
Copy link
Copy Markdown
Collaborator

Summary

  • Adds design spec for server-side ad templates, replacing client-side SDK slot discovery (Prebid.js, Smart Slots) with edge-configured creative opportunities
  • TS matches URL patterns to pre-configured slot templates, fires the full auction (PBS + APS + all providers) at request receipt in parallel with origin fetch, and injects winning bids into head before the browser receives HTML
  • Estimated ~2,000ms improvement in time-to-ad-visible (from ~3,200ms to ~1,200ms)

Test plan

  • Review spec for accuracy against current auction pipeline
  • Validate creative-opportunities.toml schema covers publisher slot inventory
  • Confirm open questions with publisher (URL patterns, homepage slot count, PBS stored request setup)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@prk-Jr
Copy link
Copy Markdown
Collaborator

prk-Jr commented Apr 29, 2026

Design questions — needed before implementation planning

We did a full review of the spec against the current codebase. The implementation is ready to start once the following 8 questions are answered. All are product/architecture decisions that can't be resolved from the code alone.


❓ 1 — /auction POST role after this ships

Goal 4 (line 42) says "return pre-collected winning bids to the browser's lightweight /auction POST." Sections 4.4 and 4.5 say "no /auction POST needed — bids are already in the page." These are contradictory. The JS client currently always POSTs to /auction. We need a definitive answer: does __ts_bids replace the POST entirely, or does /auction remain as a fallback for URLs that don't match any slot template?


❓ 2 — slot.id as GPT adUnitPath

googletag.defineSlot(slot.id, slot.formats, slot.id)

GPT's first argument must be the full GAM network path (e.g., /21765378893/homepage-banner). Using a short key like atf_sidebar_ad silently produces a non-functional slot. Is slot.id intended to be the full GAM path, or does creative-opportunities.toml need a separate field (e.g., gam_unit_path)?


❓ 3 — hb_pb price bucketing: granularity table and full key set

{ "hb_pb": "2.50", "hb_bidder": "kargo", "hb_adid": "abc123" }

hb_pb is a Prebid price bucket string (discretized CPM bin), not a raw price. No bucketing logic exists in the codebase — this is a net-new component. Which granularity table is used: low / medium / high / auto / dense / custom? Is it per-publisher configurable? And what is the complete __ts_bids key set — just hb_pb, hb_bidder, hb_adid, or also hb_size, hb_deal, hb_format?


❓ 4 — APS in Phase 1: included or excluded, and param source

The spec says "all providers: PBS, APS" are dispatched for server-triggered auctions. APS bidder params currently flow from the browser's AdRequest POST — there's no client for a server-triggered auction. creative-opportunities.toml has no [slot.providers.aps] section and APS doesn't use PBS stored requests. Is APS in scope for Phase 1? If yes, where do per-slot APS params come from?


❓ 5 — Win notifications (nurl/burl): fire server-side or defer?

When GAM renders the creative, TS is out of the render path. The nurl/burl fields from PBS/APS responses are known to TS at auction time but have no path to the client or to a server-side firing mechanism. SSP win counting breaks silently for server-auctioned impressions. Should TS fire nurl as a background HTTP request at bid-selection time, or is this explicitly deferred to a later phase?


❓ 6 — creative-opportunities.toml: compile-time include_str!() or Fastly KV at runtime?

include_str!() bakes the file into the WASM binary — every slot config change requires a full rebuild + Fastly deploy (~15 min). The phrase "ad ops can edit this file independently" doesn't hold under that model. The RuntimeServices abstraction already exposes services.kv_store(). Which model is intended: compile-time (fast reads, deploy required per change) or runtime KV (live edits, no rebuild)?


❓ 7 — Streaming mode </head> boundary: Phase 1 or deferred?

The current streaming pipeline buffers until end-of-document when post-processors run. "Buffer only until </head>, inject bids, then resume streaming immediately" is a new mode not currently implemented — it requires new infrastructure in the HTML processor. Is this streaming-mode behavior required for Phase 1 launch, or is injecting at document end acceptable as an initial release?


❓ 8 — Auction timeout: new config key or reuse existing? (Section 9, Q4)

The spec recommends 500ms for server-triggered auctions vs the current 1,000ms client-side budget. There are currently three overlapping timeout values: [auction].timeout_ms, [integrations.prebid].timeout_ms, [integrations.aps].timeout_ms. Does the server-triggered path get a new dedicated key (e.g., [creative_opportunities].auction_timeout_ms) or does it override an existing one?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Create Spec for Server-Side Ad-Templates

2 participants