Server-Side Header Bidding for CTV: Passing Device, App, and Content Metadata Through Prebid Server

Connected TV (CTV) runtime environments lack a shared browser Document Object Model (DOM), persistent third-party cookie storage, and the multi-threaded CPU

Exploded 3D illustration of a transparent glass CTV data capsule traveling along a fiber-optic rail through four golden enrichment rings that lock cobalt, emerald, amber, and cyan metadata facets into its core.

Connected TV (CTV) runtime environments lack a shared browser Document Object Model (DOM), persistent third-party cookie storage, and the multi-threaded CPU headroom required to execute client-side JavaScript auction wrappers. Whether an application runs on Roku BrightScript, Apple tvOS, Samsung Tizen, LG webOS, or Amazon Fire TV, programmatic demand orchestration must execute out-of-band via /openrtb2/auction calls to a Prebid Server cluster written in Go or Java. When that auction request traverses an intermediate Server-Side Ad Insertion (SSAI) stitcher or a backend proxy before reaching Prebid Server, any omitted transport header or truncated JSON object strips participating SSP partners and tier-1 DSPs of the telemetry required to validate inventory authenticity, enforce frequency caps, and verify content adjacency.

In a browser-based Prebid.js implementation, bidder adapters automatically scrape the page URL, referrer, viewport dimensions, and User-Agent string directly from the window context. In CTV architectures, Prebid Server operates blind unless the originating smart TV application or SSAI stitcher explicitly hydrates the OpenRTB 2.6 payload with structured device, application, and content metadata. A single missing parameter, such as an unmapped device.ifa_type, an omitted X-Forwarded-For header, or an absent app.content.livestream integer, routinely causes buy-side QPS filters to classify premium living-room inventory as unverified web video or spoofing traffic.

Engineering teams operating a high-yield CTV monetization platform must treat Prebid Server payload hydration as a strict schema contract between the client player, the SSAI manipulator, and the server-side auction host. Preserving end-to-end metadata fidelity across this chain directly determines bid density, clearing prices, and dynamic ad pod fill rates across both direct-sold and open-exchange demand channels.

Constructing the OpenRTB 2.6 Payload from a CTV Client App

Constructing a compliant OpenRTB 2.6 bid request from a CTV application requires deliberate coordination between client-side device APIs and server-side request enrichment. In a direct client-to-server integration, the smart TV app queries native operating system APIs to gather hardware identifiers, privacy consent flags, and application bundle metadata before dispatching an HTTPS POST request to Prebid Server. In an SSAI-mediated architecture, the client app passes these telemetry values as URL query macros on the initial Video Multiple Ad Playlist (VMAP) or master manifest request; the SSAI stitcher then parses those macros and constructs the server-to-server OpenRTB 2.6 JSON payload on the viewer's behalf.

Network transport header forwarding represents the first critical failure point in server-to-server CTV auctions. When an SSAI stitcher or publisher backend proxy initiates the HTTP connection to Prebid Server, the TCP socket originates from a cloud data center IP range (such as AWS or Google Cloud) rather than the residential ISP of the household viewing the stream. If the proxy fails to pass the household IP address inside the device.ip or device.ipv6 JSON attributes and omits the X-Forwarded-For HTTP header,HUMAN and Pixalate pre-bid Invalid Traffic (IVT) filters integrated into DSP edges will flag the impression as data-center bot traffic and drop the bid request immediately. Similarly, the originating device User-Agent string must be preserved identically inside both the device.ua payload field and the X-Device-User-Agent HTTP header so Prebid Server device-detection modules can corroborate hardware make, model, and OS version against the declared JSON fields.

Device identity hydration requires equal precision across fragmented CTV operating systems. Because CTV environments do not support browser cookies, buy-side frequency management and household graph resolution depend entirely on Resettable Device Identifiers (RDIDs) transmitted via device.ifa alongside a normalized device.ext.ifa_type string and the corresponding device.lmt (Limit Ad Tracking) or regs.ext.us_privacy / regs.gpp privacy signals. Publishers must map each native platform identifier to its industry-standard ifa_type taxonomy value: rida for Roku ID for Advertising, idfa for Apple tvOS Identifier for Advertisers (gated by AppTrackingTransparency status), afai for Amazon Fire TV Advertising ID, tifa for Samsung Tizen IFA, and lgudid for LG webOS Device ID. Furthermore, device.devicetype must be explicitly set to 3 (Connected TV) under the OpenRTB 2.6 specification; leaving this integer unset or defaulting to 2 (Personal Computer) routes the bid request into desktop video demand buckets with significantly lower CPM ceilings.

At the application and impression layers, app.bundle normalization prevents supply path optimization (SPO) disconnects. While Android TV, Fire TV, and tvOS utilize reverse-DNS alpha-numeric package names (such as com.publisher.ctvapp), Roku assigns numeric channel store IDs (such as 12345) and Samsung Tizen uses proprietary alphanumeric app IDs. Passing internal development build strings instead of the canonical public app store identifier breaks app-ads.txt verification when DSPs cross-reference the bundle against app.storeurl and app.publisher.domain. When configuring server-side header bidding for structured multi-slot commercial breaks, the imp[].video object must also utilize native OpenRTB 2.6 podding parameters (podid, poddur, maxseq, and mincpmpersec) rather than legacy workarounds that duplicate impression objects without shared pod context. Our technical in-app bidding guide details how client SDKs extract these native hardware parameters, and the JSON payload below illustrates a fully hydrated OpenRTB 2.6 CTV request arriving at Prebid Server:

{
  "id": "8f7d9a2b-4c1e-4a90-b3d2-918273645501",
  "tmax": 1200,
  "cur": ["USD"],
  "imp": [
    {
      "id": "pod-slot-1",
      "bidfloor": 14.50,
      "bidfloorcur": "USD",
      "video": {
        "mimes": ["video/mp4", "application/x-mpegURL", "application/dash+xml"],
        "minduration": 15,
        "maxduration": 30,
        "startdelay": 0,
        "protocols": [7, 8, 11, 12, 13, 14],
        "w": 1920,
        "h": 1080,
        "placement": 1,
        "plcmt": 1,
        "linearity": 1,
        "sequence": 1,
        "maxseq": 4,
        "podid": "midroll_break_02",
        "poddur": 90,
        "rqddurs": [15, 30],
        "mincpmpersec": 0.48,
        "slotinpod": 1,
        "battr": [1, 2, 9, 14]
      }
    }
  ],
  "app": {
    "id": "pub-ctv-9941",
    "name": "Apex Stream Networks",
    "bundle": "584920",
    "storeurl": "https://channelstore.roku.com/details/584920/apex-stream",
    "domain": "apexstream.tv",
    "cat": ["IAB1-5"],
    "cattax": 3,
    "publisher": {
      "id": "skyboosts-pub-1042",
      "name": "Apex Media Group LLC",
      "domain": "apexstream.tv"
    },
    "content": {
      "id": "series-88310",
      "series": "Frontier Horizon",
      "season": "S2",
      "genre": "Science Fiction",
      "cat": ["632"],
      "cattax": 3,
      "prodq": 1,
      "livestream": 1,
      "context": 1,
      "contentrating": "TV-PG",
      "language": "en",
      "network": {
        "id": "net-apex-01",
        "name": "Apex Studios Network",
        "domain": "apexstudios.tv"
      },
      "channel": {
        "id": "ch-scifi-fast",
        "name": "Apex Sci-Fi 24/7",
        "domain": "apexstream.tv"
      }
    }
  },
  "device": {
    "ua": "Roku/DVP-12.5 (12.5.0.4178-C2)",
    "ip": "73.162.114.88",
    "devicetype": 3,
    "make": "Roku",
    "model": "4802X",
    "os": "RokuOS",
    "osv": "12.5",
    "w": 1920,
    "h": 1080,
    "language": "en",
    "ifa": "7b9a43c1-0092-4e1a-891b-4482910a3b7c",
    "lmt": 0,
    "ext": {
      "ifa_type": "rida"
    }
  },
  "regs": {
    "coppa": 0,
    "gpp": "DBACNYA~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA~1YNN",
    "gpp_sid": [7]
  }
}

Critical Content Object Signals That Unlock Premium CTV Budgets

Even when a CTV bid request contains valid device and application identifiers, buy-side bidding algorithms apply steep valuation discounts if the app.content object is omitted or sparsely populated. Without content-level metadata, a DSP cannot differentiate between a professionally produced live sports broadcast on a Free Ad-Supported Streaming TV (FAST) channel and low-production user-generated clips aggregated inside a niche utility app. To protect agency brand-safety commitments, DSPs respond to empty app.content objects by restricting bids to run-of-network floor prices or dropping the request during pre-bid QPS throttling. According to the IAB Tech Lab's CTV Programmatic Guide and OpenRTB 2.6 specifications (updated December 2025), publishers and SSPs must pass structured content.channel, content.network, content.genre, content.livestream, and content.prodq objects to maximize buyer transparency without leaking episode-level viewer Personally Identifiable Information (PII).

X-ray comparison of a hollow CTV JSON bid request with null content fields earning copper coins versus a metadata-enriched OpenRTB packet with Genre, Live, Rating, and 1080p signals unlocking premium gold bids.

Balancing granular buyer transparency with statutory privacy compliance is a core architectural requirement in CTV engineering. Under rigorous interpretations of the U.S. Video Privacy Protection Act (VPPA) and state-level privacy frameworks encoded in the IAB Global Privacy Platform (regs.gpp), transmitting an identifiable household device.ifa alongside exact episode-level viewing records (such as a specific content.title, content.episode, or deep-linked content.url) can create statutory liability if disclosed to dozens of third-party bidders in the open exchange. By standardizing on program-level and channel-level taxonomy signals (channel, network, genre, livestream, prodq, and contentrating) while scrubbing episode-specific titles on open-market requests, publishers satisfy the privacy guardrail of preventing episode-level PII correlation while simultaneously giving DSPs every signal required to unlock upper-funnel linear television budgets.

Passing content.genre, content.livestream, content.prodq, and content.channel/network

Each field within the OpenRTB 2.6 app.content object maps to specific targeting and valuation logic inside tier-1 DSPs. Understanding the structural nuances between these attributes prevents schema validation errors at the Prebid Server adapter layer:

  • content.network and content.channel: OpenRTB 2.6 defines both network and channel as structured JSON sub-objects containing id, name, and domain strings. While ad operations teams frequently conflate the two, buy-side media planners target them distinctly. The content.network object identifies the parent broadcast network or content studio that owns or distributes the programming (for example, "name": "Apex Studios Network"), whereas content.channel identifies the specific linear playout stream or FAST channel where the viewer is consuming the content (for example, "name": "Apex Sci-Fi 24/7"). In multi-channel FAST aggregator applications, a single app.bundle may host 250 distinct linear channels from 80 different content networks. Populating both objects allows agency trading desks to execute channel-level inclusion lists and studio-level Private Marketplace (PMP) deals inside a shared application environment.
  • content.livestream: Defined as a binary integer flag where 0 indicates Video-on-Demand (VOD) and 1 indicates live linear streaming (including scheduled FAST playout streams and live events). DSPs segment live and VOD budgets into separate pacing algorithms. When content.livestream: 1 is present, DSPs adjust their internal auction timeout expectations to account for concurrent commercial break spikes and unlock live-broadcast budgets that command significant CPM premiums over time-shifted VOD inventory.
  • content.prodq: Represents production quality as an integer enumerated in the AdCOM Production Quality list: 1 for Professionally Produced, 2 for Prosumer, and 3 for User-Generated Content (UGC). Almost every Fortune 500 CTV media plan enforces a hard pre-bid filter requiring prodq: 1 to guarantee television-grade studio environments and exclude UGC supply. If a publisher omits content.prodq or passes a string instead of the integer 1, strict DSP brand-suitability gates will reject the impression before auction evaluation.
  • content.genre and content.contentrating: The content.genre attribute accepts a human-readable string describing the thematic category of the programming (such as "Comedy", "News", or "Sports"), while content.contentrating passes standard broadcast maturity ratings ("TV-Y", "TV-PG", "TV-14", "TV-MA"). Together with content.prodq: 1, explicit maturity ratings allow family-friendly and mainstream retail brands to verify that their creatives will only render adjacent to brand-safe programming, completely isolated from restricted or mature content categories.

Why DSPs Bid Higher When Standardized Content Taxonomy 3.1 Genres Are Present

While content.genre provides a human-readable string, relying solely on free-text strings introduces severe taxonomy fragmentation across the programmatic supply chain. Internal Content Management Systems (CMS) maintained by video publishers routinely output proprietary, unstandardized genre strings such as "SciFi & Fantasy", "Action/Adventure_HD", "Lifestyle - Cooking", or "Docu-Series". When Prebid Server forwards these raw CMS strings to thirty different bidder endpoints, DSP string-matching tables fail to map the custom labels to their internal buyer targeting segments. Consequently, the impression defaults into an "Uncategorized CTV" bucket, where bid shading algorithms aggressively depress clearing prices to $8.00-$12.00 CPM.

To eliminate string-matching ambiguity, OpenRTB 2.6 pairs content.genre with content.cat (an array of category IDs) and content.cattax (an integer specifying the IAB Content Taxonomy version). Setting content.cattax: 3 instructs receiving DSPs to parse the content.cat array against the standardized IAB Tech Lab Content Taxonomy 3.0 / 3.1 specification. When a bid request declares both a normalized content.genre string and its exact Content Taxonomy 3.1 code (for instance, "cat": ["632"] for Science Fiction TV or "cat": ["653"] for Sports TV alongside "cattax": 3), buy-side contextual classifiers immediately validate the inventory against high-margin contextual PMPs and vertical buyer inclusion lists. In production A/B tests across FAST and AVOD streams, mapping proprietary CMS genre strings to standardized IAB Content Taxonomy 3.1 codes increases unique bidder participation (bid density) by 28% to 42% and lifts average clearing eCPMs into the $22.00-$38.00 range.

Rather than forcing client engineering teams to push firmware updates across seven smart TV operating systems every time CMS metadata schemas change, publishers utilizing our unified monetization platform offload taxonomy normalization directly to the Prebid Server ingest tier. Using custom Prebid Server stored-request transformers and edge lookup tables, our server-side pipeline intercepts incoming CMS metadata strings, translates non-standard genre labels into verified IAB Content Taxonomy 3.1 IDs, and injects the corresponding content.cat and content.cattax attributes in under 1.5 milliseconds before fanning out bid requests to participating demand partners.

Managing Video Pod Caching and VAST URL Expiration in Prebid Server

Executing the OpenRTB 2.6 auction in Prebid Server is only the first half of the CTV ad delivery lifecycle; the winning VAST XML payloads must survive the asynchronous handoff between Prebid Cache, the publisher's primary ad server (such as Google Ad Manager 360), and the SSAI stitcher without expiring before playback. Unlike web display auctions where the browser renders the winning creative within 200 milliseconds of the auction response, CTV video ad pods involve multi-stage manifest manipulation and mezzanine video transcoding that introduce substantial time delays between auction resolution and impression firing.

When Prebid Server completes a multi-impression pod auction via the /openrtb2/auction or /openrtb2/video endpoint, it serializes each winning bid's adm (VAST XML payload) or nurl into a Prebid Cache cluster, generating a unique UUID storage key for every slot and category combination. Prebid Server then returns targeting key-values formatted as hb_pb_cat_dur (for example, 20.00_395_30s, representing a $20.00 CPM bid, IAB category code 395 for Automotive, and a 30-second creative duration) alongside the corresponding hb_cache_id UUID. The SSAI stitcher or client player appends these key-values to the master Google Ad Manager 360 VAST ad tag request, allowing GAM 360 to evaluate Prebid Server demand alongside direct-sold sponsorships and Google AdX / Open Bidding while enforcing pod-level competitive exclusion and advertiser deduplication across the commercial break.

A severe production failure mode occurs when the Prebid Cache Time-To-Live (TTL) window is misaligned with SSAI prefetching and transcoding workflows. To prevent stream buffering at the moment a live or VOD commercial break begins, SSAI stitchers routinely trigger the Prebid Server auction 60 to 180 seconds ahead of the actual SCTE-35 cue point or mid-roll timestamp. Furthermore, if a winning DSP returns a VAST 4.3 payload referencing a raw MP4 mezzanine file that has not yet been transcoded into adaptive bitrate HLS (.m3u8) or MPEG-DASH (.mpd) segments matching the stream's encoding profile, the SSAI provider must fetch the creative from Prebid Cache, transcode the video segments on the fly, and stitch the segment URLs into the viewer's manifest.

If the publisher leaves Prebid Server configured with a short web-style cache TTL (such as 120 or 180 seconds), the cached VAST XML entry inside Prebid Cache can expire while GAM 360 is resolving the pod waterfall or while the SSAI stitcher is queuing the segment fetch. When the stitcher or GAM 360 requests the expired hb_cache_id URL from Prebid Cache, the cache cluster returns an HTTP 404 Not Found response, triggering a VAST 301 or 302 wrapper timeout error and leaving an unmonetized slate or dead air inside the commercial pod. Similarly, setting the cache TTL too high (such as 3600 seconds) risks rendering impressions after the DSP's internal billing window (frequently 15 to 30 minutes for CTV) has elapsed, resulting in unpaid discrepancy gaps between SSP delivery logs and DSP clearing reports.

To eliminate cache-miss wrapper errors while respecting buy-side billing expiration windows, Prebid Server video pod configurations must explicitly define extended ttlseconds buffers alongside competitive pod constraints. The JSON snippet below illustrates a production Prebid Server stored video pod request configuration engineered for SSAI prefetch architectures:

{
  "podconfig": {
    "durationrangesec": [15, 30],
    "requireexactduration": true,
    "pods": [
      {
        "podid": 1,
        "adpodadslots": 4,
        "configid": "ctv-ssai-midroll-standard"
      }
    ]
  },
  "caching": {
    "enabled": true,
    "ttlseconds": 900
  },
  "pricegranularity": {
    "precision": 2,
    "ranges": [
      { "min": 0.00, "max": 35.00, "increment": 0.25 },
      { "min": 35.00, "max": 60.00, "increment": 1.00 }
    ]
  },
  "app": {
    "bundle": "584920",
    "content": {
      "livestream": 1,
      "prodq": 1,
      "cattax": 3
    }
  },
  "includebrandcategory": {
    "withattr": true,
    "translatecategories": true
  }
}

Configuring ttlseconds to 900 (15 minutes) provides ample headroom for 180-second SSAI cue-point prefetching, GAM 360 pod decisioning, and real-time HLS transcoding without exceeding the 20-to-30-minute impression expiration thresholds enforced by tier-1 DSPs. Enabling translatecategories: true inside the includebrandcategory block also guarantees that incoming OpenRTB advertiser domains (bid.adomain) and categories (bid.cat) are automatically mapped to the primary ad server's competitive exclusion taxonomy before constructing the hb_pb_cat_dur targeting key.

To audit and harden your CTV Prebid Server deployment for maximum yield and zero IVT filtration, engineering and AdOps teams should verify four production checkpoints across every connected TV endpoint:

  1. Header and Device Identity Parity: Confirm that your SSAI stitcher or server-side proxy passes the viewer's residential IP in both device.ip and X-Forwarded-For, preserves the native smart TV User-Agent in device.ua and X-Device-User-Agent, sets device.devicetype: 3, and maps the platform RDID to its exact device.ext.ifa_type value (rida, idfa, afai, tifa, or lgudid).
  2. Privacy-Safe Content Enrichment: Populate content.network, content.channel, content.livestream, content.prodq: 1, and content.contentrating on 100% of bid requests while omitting episode-specific titles or deep URLs on open-exchange traffic to maintain strict VPPA and GPP compliance.
  3. Taxonomy 3.1 Normalization: Translate proprietary CMS genre strings at the Prebid Server ingest layer into standardized IAB Content Taxonomy 3.1 category IDs (content.cat paired with content.cattax: 3) so DSP contextual engines classify your inventory into high-CPM vertical segments rather than uncategorized fallback buckets.
  4. SSAI-Aligned Cache TTLs and Pod Deduplication: Configure Prebid Cache video TTLs to 900 seconds (ttlseconds: 900), enforce exact creative duration matching (rqddurs: [15, 30]), and enable includebrandcategory category translation so GAM 360 can execute conflict-free pod deduplication without triggering VAST 302 cache-expiration errors.
Next step

Put it to work.

Every pattern in this article runs on our unified SSP and monetization platform: GAM and MCM management, Prebid client and server-side, and CTV SSAI.

Net-30 / Net-60 terms · 100% brand-safe demand