RTB Architecture

    CTV SSAI and ad serving: how VAST, VMAP and OpenRTB pod bidding fit together

    Published · Last updated
    Next scheduled review:

    Server-side ad insertion (SSAI) stitches ads into a CTV content stream on a server, so the TV app plays one continuous video. The SSAI service asks an ad server or exchange for ads, receives VAST, transcodes the creative and fires tracking on the device's behalf. This page explains each step, the fields that matter and the usual failure points.

    Contents

    Key facts

    • CTV is the biggest slice of tracked programmatic spend. Connected TV took 41.6% of spend in the ANA's Q2 2026 Programmatic Transparency Benchmark, released on 6 August 2026 (Fiducia on the ANA benchmark, 6 August 2026).
    • VAST 4.4 adds CTV formats beyond the ad break. It supports pause, screensaver, overlay, squeezeback and in-scene ads through <NonLinearAds>. IAB Tech Lab's repository says it has been considered released since 22 July 2026 (VAST4.x repository, commit of 8 September 2026).
    • SSAI must forward the viewer's device details. VAST requires X-Device-IP and X-Device-User-Agent headers on server-side requests and tracking, and calls X-Forwarded-For deprecated (VAST 4.4, section 1.1.3).
    • OpenRTB 2.6 bids on whole ad breaks. Pod fields such as podid, poddur, maxseq, rqddurs and mincpmpersec let a seller offer a break and let buyers bid per slot (OpenRTB implementation guide, section 7.6). The latest release, 2.6-202606 of 11 June 2026, added realtime and firstbroadcast to signal live programming (openrtb2.x releases).
    • Prebid.js no longer fills pods. The adpod module was removed in Prebid.js 11.0, released on 12 March 2026; long-form pods now go through Prebid Server (Prebid.org, Adpod module; Prebid.js 11.0.0).
    Jump to the table

    Definition

    SSAI: the delivery of in-stream ads in which a server, not the media player, requests the ads, conditions the creative to match the content and splices it into the stream manifest. The player receives one stream and may not know where the ads begin. See the glossary entries for SSAI and CSAI.

    VAST calls the same process "ad stitching" and holds SSAI systems to the same playback expectations as media players (VAST 4.4, section 2.2). In practice, SSAI is the default on connected TV and FAST channels, because many TV apps cannot run a second player for ads.

    SSAI vs CSAI: what moves to the server

    In client-side ad insertion, the player fetches VAST, plays the ad file and fires the tracking pixels itself. In SSAI, a server does all three. That shift fixes playback and creates a measurement problem, because every request now comes from one server.

    8 of 8 rows

    Columns (3)

    Who requests ads

    The player or app SDK

    The stitching server

    Playback

    Player switches to an ad file

    One continuous stream; ads are segments in the manifest

    Buffering between content and ads

    Possible

    Avoided by design

    Ad blockers

    Can block ad calls

    Harder to block, since ads share the stream

    Who fires tracking

    The device

    The server, or the device if the SDK supports it

    Device data reaching buyers

    Direct from the device

    Only if the server forwards it

    Interactive formats

    VPAID (deprecated) or SIMID

    SIMID with an SDK; often none

    OpenRTB imp.ssai

    1

    2 (stitched, client tracking) or 3 (all server-side)

    Who requests ads

    Client-side (CSAI)

    The player or app SDK

    Server-side (SSAI)

    The stitching server

    Playback

    Client-side (CSAI)

    Player switches to an ad file

    Server-side (SSAI)

    One continuous stream; ads are segments in the manifest

    Buffering between content and ads

    Client-side (CSAI)

    Possible

    Server-side (SSAI)

    Avoided by design

    Ad blockers

    Client-side (CSAI)

    Can block ad calls

    Server-side (SSAI)

    Harder to block, since ads share the stream

    Who fires tracking

    Client-side (CSAI)

    The device

    Server-side (SSAI)

    The server, or the device if the SDK supports it

    Device data reaching buyers

    Client-side (CSAI)

    Direct from the device

    Server-side (SSAI)

    Only if the server forwards it

    Interactive formats

    Client-side (CSAI)

    VPAID (deprecated) or SIMID

    Server-side (SSAI)

    SIMID with an SDK; often none

    OpenRTB imp.ssai

    Client-side (CSAI)

    1

    Server-side (SSAI)

    2 (stitched, client tracking) or 3 (all server-side)

    Download JSON

    Table by AdSovereign, CC BY 4.0.

    The imp.ssai values come from OpenRTB 2.6, where 0 means unknown (OpenRTB 2.6, Object: Imp). Buyers use them to decide how far to trust the impression signal, so send the true value.

    How an SSAI ad break is filled, step by step

    The sequence below combines the stitching flow in VAST 4.4 with the long-form workflow Prebid Server documents (VAST 4.4, section 1.1.2; Prebid Server long-form video).

    1. The app starts a session. It asks the SSAI service for a stream and passes device and consent data.
    2. The stitcher finds the break. For live streams it reads a cue marker, often SCTE-35; for video on demand it reads a schedule such as VMAP.
    3. It requests ads for the whole break. The request goes to the publisher ad server, which may call an exchange with an OpenRTB pod request.
    4. Buyers bid per slot. The seller builds the pod from the bids and may mix buyers or take fewer bids than were sent.
    5. VAST comes back. The response lists the ads in sequence, each with a creative ID and media files.
    6. The stitcher conditions the creative. If it has a transcoded rendition for that creative ID, it uses it. If not, it starts a transcode from the mezzanine file and skips the ad for now.
    7. It writes the ads into the manifest. HLS or DASH segments for the ads replace the break in the content.
    8. Tracking fires. The server, or the app's SDK, sends impression and quartile beacons with the device's IP and user agent attached.

    VAST 4.x for CTV: the elements that matter

    VAST 4.0 was released in January 2016, 4.1 in November 2018 and 4.2 in June 2019 (IAB Tech Lab VAST repository). From 4.3 the text moved to a separate repository, where 4.4 is the current version (VAST4.x repository). In OpenRTB requests, you declare which versions you accept with AdCOM protocol codes, such as 7 for VAST 4.0, 11 for VAST 4.1, 13 for 4.2 and 15 for 4.3 (AdCOM 1.0, Creative Subtypes).

    6 of 6 rows

    Columns (3)

    <Ad sequence="n">

    Orders ads in a pod; sequence values must be unique

    <UniversalAdId>

    Required creative ID kept across systems, for example from Ad-ID in the US or Clearcast in the UK; the stitcher's cache key

    <Mezzanine>

    Raw high-quality file for transcoding; required in ad-stitched executions; error 406 if missing

    <MediaFile>

    Ready-to-serve files; VAST 4.x asks for an adaptive stream or at least three quality levels

    <AdVerifications>

    Loads measurement code such as OM SDK scripts

    <NonLinearAds>

    In 4.4, carries pause, screensaver, overlay, squeezeback and in-scene ads

    <Ad sequence="n">

    What it does in SSAI

    Orders ads in a pod; sequence values must be unique

    <UniversalAdId>

    What it does in SSAI

    Required creative ID kept across systems, for example from Ad-ID in the US or Clearcast in the UK; the stitcher's cache key

    <Mezzanine>

    What it does in SSAI

    Raw high-quality file for transcoding; required in ad-stitched executions; error 406 if missing

    <MediaFile>

    What it does in SSAI

    Ready-to-serve files; VAST 4.x asks for an adaptive stream or at least three quality levels

    <AdVerifications>

    What it does in SSAI

    Loads measurement code such as OM SDK scripts

    <NonLinearAds>

    What it does in SSAI

    In 4.4, carries pause, screensaver, overlay, squeezeback and in-scene ads

    Download JSON

    Table by AdSovereign, CC BY 4.0.

    Older tags still circulate. The VAST CTV Addendum 2024 adds non-breaking extensions so VAST 2 and 3 tags can carry a registered UniversalAdId, Open Measurement resources and a mezzanine file (VAST CTV Addendum 2024). A two-ad pod in VAST 4 looks like this, trimmed to the parts a stitcher reads:

    <VAST version="4.2">
      <Ad id="pod-ad-1" sequence="1">
        <InLine>
          <AdSystem>ExampleAdServer</AdSystem>
          <AdTitle>Brand A 30s</AdTitle>
          <Impression><![CDATA[https://adserver.example/imp?c=cr-30s-01]]></Impression>
          <Creatives>
            <Creative id="cr-30s-01">
              <UniversalAdId idRegistry="ad-id.org">ABCD1234000H</UniversalAdId>
              <Linear>
                <Duration>00:00:30</Duration>
                <MediaFiles>
                  <MediaFile delivery="progressive" type="video/mp4" width="1920" height="1080"><![CDATA[https://cdn.example/a30_1080.mp4]]></MediaFile>
                  <Mezzanine delivery="progressive" type="video/quicktime" width="1920" height="1080"><![CDATA[https://cdn.example/a30_prores.mov]]></Mezzanine>
                </MediaFiles>
              </Linear>
            </Creative>
          </Creatives>
        </InLine>
      </Ad>
      <Ad id="pod-ad-2" sequence="2">
        <!-- second ad, same structure -->
      </Ad>
    </VAST>

    VMAP: describing where the breaks go

    VMAP 1.0 is an XML playlist that tells a player, or a stitcher, where ad breaks sit in a piece of content. Its schema notes that the current version is 1.0.1 (IAB VMAP repository, vmap.xsd). Each <AdBreak> has a required timeOffset, written as a time code, a percentage, "start" or "end", or a position such as #2. A breakType hint says whether the break takes linear, nonlinear or display ads, and an <AdSource> carries either inline VAST or an ad tag URI.

    For video on demand, a VMAP document is a clean way to say "pre-roll, two mid-rolls, post-roll" once per title. Live streams rarely use it. There, the stitcher waits for cue markers in the stream, and AWS Elemental MediaTailor, for example, reads the duration of each break from those markers (MediaTailor ad insertion behaviour).

    Pod bidding in OpenRTB 2.6

    Pod bidding lets an exchange sell an ad break as a unit. OpenRTB 2.6 describes three shapes (OpenRTB implementation guide, section 7.6). A structured pod has fixed slots, each its own impression. A dynamic pod fixes only the total time and the maximum number of ads. A hybrid pod mixes both.

    10 of 10 rows

    Columns (3)

    podid

    Video, Audio

    Impressions with the same value belong to the same break

    podseq

    Video, Audio

    Position of the break in the stream: 1 first, -1 last, 0 any

    slotinpod

    Video, Audio, Bid

    Seller can guarantee a slot: 1 first, -1 last, 2 first or last, 0 any

    poddur

    Video, Audio

    Total seconds buyers may fill in a dynamic pod

    maxseq

    Video, Audio

    Maximum number of ads in a dynamic pod

    rqddurs

    Video, Audio

    Exact allowed ad lengths, for live TV where a short ad leaves dead air

    mincpmpersec

    Video, Audio, Deal

    Floor per second of ad duration

    durfloors

    Video, Audio, Deal

    Floors by duration range

    poddedupe

    Video

    How the seller removes duplicates: 1 by advertiser domain, 3 by creative ID

    dur

    Bid

    Length of the creative the buyer is bidding with

    podid

    Object

    Video, Audio

    Meaning

    Impressions with the same value belong to the same break

    podseq

    Object

    Video, Audio

    Meaning

    Position of the break in the stream: 1 first, -1 last, 0 any

    slotinpod

    Object

    Video, Audio, Bid

    Meaning

    Seller can guarantee a slot: 1 first, -1 last, 2 first or last, 0 any

    poddur

    Object

    Video, Audio

    Meaning

    Total seconds buyers may fill in a dynamic pod

    maxseq

    Object

    Video, Audio

    Meaning

    Maximum number of ads in a dynamic pod

    rqddurs

    Object

    Video, Audio

    Meaning

    Exact allowed ad lengths, for live TV where a short ad leaves dead air

    mincpmpersec

    Object

    Video, Audio, Deal

    Meaning

    Floor per second of ad duration

    durfloors

    Object

    Video, Audio, Deal

    Meaning

    Floors by duration range

    poddedupe

    Object

    Video

    Meaning

    How the seller removes duplicates: 1 by advertiser domain, 3 by creative ID

    dur

    Object

    Bid

    Meaning

    Length of the creative the buyer is bidding with

    Download JSON

    Table by AdSovereign, CC BY 4.0.

    Field definitions are from OpenRTB 2.6 and AdCOM 1.0 (OpenRTB 2.6, Object: Video; AdCOM 1.0 lists). Here is a dynamic two-minute mid-roll in a live sports stream on a TV, with every request field the stitcher should fill. Identifiers and the user agent are placeholders.

    {
      "id": "req-7f3c",
      "at": 1,
      "tmax": 800,
      "imp": [
        {
          "id": "1",
          "ssai": 3,
          "video": {
            "mimes": ["video/mp4"],
            "protocols": [7, 11, 13, 15],
            "plcmt": 1,
            "linearity": 1,
            "startdelay": -1,
            "podid": "break-2",
            "podseq": 0,
            "poddur": 120,
            "maxseq": 4,
            "rqddurs": [15, 30],
            "mincpmpersec": 0.5,
            "poddedupe": [1, 3],
            "w": 1920,
            "h": 1080
          },
          "bidfloorcur": "USD"
        }
      ],
      "app": {
        "bundle": "com.example.sportsapp",
        "content": { "livestream": 1, "realtime": 1, "firstbroadcast": 1 }
      },
      "device": {
        "devicetype": 3,
        "ip": "203.0.113.24",
        "ua": "ExampleTV/7.1 (SmartTV; Linux)",
        "ifa": "6d92078a-8246-4ba4-ae5b-76104861e7dc",
        "lmt": 0
      }
    }

    startdelay -1 marks a generic mid-roll, plcmt 1 is instream and devicetype 3 is connected TV (AdCOM 1.0). A buyer answers with one bid per ad it wants in the break, each with its duration:

    {
      "id": "req-7f3c",
      "seatbid": [
        {
          "seat": "buyer-42",
          "bid": [
            { "id": "b1", "impid": "1", "price": 18.0, "dur": 30, "mtype": 2, "crid": "cr-30s-01", "adomain": ["brand-a.example"], "adm": "<VAST version=\"4.2\"></VAST>" },
            { "id": "b2", "impid": "1", "price": 9.5, "dur": 15, "mtype": 2, "crid": "cr-15s-07", "adomain": ["brand-b.example"], "adm": "<VAST version=\"4.2\"></VAST>" }
          ]
        }
      ]
    }

    Check the floors yourself. With mincpmpersec of $0.50, a 30-second ad must bid at least $15.00 CPM and a 15-second ad at least $7.50. Both bids clear. The seller may still use one, both or neither, and may fill the other 75 seconds with other buyers (OpenRTB implementation guide, section 7.6). Floor tactics for pods, including duration floors, are covered in floor price strategy, and the full bid request in OpenRTB 2.6 explained.

    Ad servers apply pod floors differently. Google Ad Manager applies floors on podded app traffic to the combined CPM of the pod, so single ads can report CPMs below the floor (Google Ad Manager Help, pricing rules).

    SSAI headers: forwarding IP and user agent

    When a stitcher fires every request from its own servers, the ad server sees thousands of impressions from one address. VAST notes that such traffic "look[s] similar to invalid traffic" (VAST 4.4, section 1.1.3). The fix is to forward the viewer's device details in headers, and to keep them identical to the ones in the original request.

    GET /vast?pod=break-2&cb=81723 HTTP/1.1
    Host: adserver.example
    User-Agent: ExampleStitcher/3.2
    X-Device-IP: 203.0.113.24
    X-Device-User-Agent: ExampleTV/7.1 (SmartTV; Linux)
    X-Device-Accept-Language: en-US
    X-Device-Referer: https://sportsapp.example/live

    VAST makes the first two headers mandatory for ad stitching providers and recommends X-Device-Referer, X-Device-Accept-Language and X-Device-Requested-With when available. Other client headers may travel with an X-Device- prefix. X-Forwarded-For is accepted for backward compatibility but deprecated (VAST 4.4, section 1.1.3). In OpenRTB, the same values go in device.ip, device.ua and, where available, the structured user agent device.sua.

    Headers can be faked, so the OpenRTB guide adds a second layer. It recommends that a server sending impression notifications sign them with ads.cert Authenticated Connections, so recipients can check who sent them (OpenRTB implementation guide, section 7.8). For supply-chain checks on CTV apps, see SupplyChain object, ads.txt and sellers.json. Invalid traffic detection vendors are compared in ad fraud detection tools.

    Measurement: impressions, quartiles and verification

    Measurement rules favour the device. VAST quotes the MRC video guidelines: ad counting must use a client-initiated approach, and server-initiated counting is not acceptable, though pass-through of client-side events to a server is (VAST 4.4, section 1.1.3). That is why imp.ssai 2, stitched ads with tracking fired by the device, is the stronger signal for buyers.

    Many stitchers still beacon from the server. AWS Elemental MediaTailor defaults to server-side reporting. When the player requests an ad segment, the service sends start and quartile beacons to the ad server and redirects the player to the segment (MediaTailor server-side reporting). Because the beacon follows a real segment request, the event starts at the device, but the report itself comes from the server.

    For billing, the OpenRTB guide names the VAST <Impression> event as the official billable signal for video. It discourages the billing notice URL, burl, for video and audio, and says win notices must never count impressions (OpenRTB implementation guide, section 7.8). Verification vendors load through <AdVerifications>, which most CTV players run only through an OM SDK integration. The vendors themselves are reviewed in CTV measurement companies.

    Creative transcoding and fitting ads to the break

    A TV stream has its own bitrate ladder, codec and loudness. An ad that does not match looks and sounds wrong next to the show. So stitchers transcode each creative into the same renditions as the content, starting from the best source they can get.

    That source is the mezzanine file. The IAB Tech Lab's guidelines recommend a .mov container with Apple ProRes and 10-bit colour where possible. Keep native resolution and frame rate, use PCM audio at 48 kHz and add no slate (IAB Tech Lab, Ad Format Guidelines for Digital Video and CTV). Standard linear lengths are 6, 15, 20 and 30 seconds, and transcoding may shift duration by no more than 1 second.

    Transcoding takes time, so the first request for a new creative usually loses. VAST describes the flow: if the creative ID has never been seen, the stitcher extracts the mezzanine, starts the transcode, skips the ad and returns error code 407 (VAST 4.4, section 1.1.2). If the creative changes, it needs a new UniversalAdId, or the stitcher will keep playing the old rendition.

    Duration fit is the other trap. MediaTailor's documentation gives two cases. A 70-second break offered two 40-second ads plays one ad and then the slate or content. A 30-second break offered only 40-second ads plays no ads at all (MediaTailor ad insertion behaviour). This is why live sellers use rqddurs and buyers should send the exact dur of the creative.

    Where Prebid fits in long-form video

    Prebid.js removed its adpod module in version 11.0, released on 12 March 2026, and its documentation now says long-form pods are no longer supported in Prebid.js (Prebid.org, Adpod module; Prebid.js 11.0.0). Prebid Server documents the server route. The SSAI server sends pod requirements to Prebid Server, which collects bids, translates categories for competitive separation and caches the creatives. It then returns key-values for the ad server, and the stitcher fetches the winning creatives from the cache (Prebid Server long-form video).

    If you run Prebid Server yourself, the Prebid Server self-hosting guide covers deployment. The choice of CTV ad server, which decides most of this flow, is compared in CTV ad server options, and the FAST channel business in FAST channels advertising.

    Common mistakes

    1. Sending ssai 0 when you know the answer. Buyers treat unknown as the weakest case. Send 2 or 3.
    2. Forwarding the stitcher's own IP. Put the device IP in X-Device-IP and device.ip, never the server's.
    3. Mismatched headers and payload. The headers must match the original request; mismatches look like fraud.
    4. Reusing a creative ID after an edit. The stitcher serves the cached old version. Issue a new UniversalAdId.
    5. No mezzanine file. Publishers that require one may drop the ad with error 406.
    6. Bidding without dur. The seller cannot place the ad, or places it badly.
    7. Ignoring rqddurs in live breaks. A 20-second ad in a break built from 15- and 30-second slots is rejected.
    8. Counting win notices as impressions. In video, the VAST impression event is the billable signal.
    9. Assuming every SSAI vendor beacons the same way. Ask whether events start at the device or the server, and test with your verification vendor.

    The RTB architecture hub links the related pages on bid requests, latency and supply-chain checks.

    FAQ

    What is SSAI in CTV?
    It is server-side ad insertion: a server requests the ads, transcodes them to match the show and stitches them into the stream, so the TV app plays one continuous video. The server also fires tracking, and must forward the device's IP and user agent when it does (VAST 4.4).
    What is the difference between SSAI and CSAI?
    In CSAI the player fetches and plays the ad and fires the pixels. In SSAI a server does all three, which avoids buffering and ad blockers but moves measurement away from the device. OpenRTB signals the difference in imp.ssai (OpenRTB 2.6).
    What VAST version should CTV use?
    Use VAST 4.x where your stitcher and buyers support it, because it carries UniversalAdId, mezzanine files and verification. VAST 4.4 adds pause and other non-interruptive CTV formats. For older tags, the VAST CTV Addendum 2024 adds the key fields to VAST 2 and 3 (IAB Tech Lab).
    What is pod bidding?
    It is selling an ad break as a unit in OpenRTB 2.6. The seller describes the break with fields such as podid, poddur and maxseq, buyers bid per ad with a duration, and the seller assembles the pod (OpenRTB implementation guide, section 7.6).
    Why do SSAI impressions get flagged as invalid traffic?
    Because all requests come from a few server IPs. Forward the device IP and user agent in X-Device-IP and X-Device-User-Agent, keep them consistent with the bid request, and sign server-side notifications where partners support ads.cert (OpenRTB implementation guide, section 7.8).

    How this works on owned infrastructure

    In SSAI the stitcher sees everything: the device IP, the user agent, the pod structure and which ads actually played. Whoever runs that layer controls the evidence buyers rely on. AdSovereign, an enterprise RTB stack with DSP, SSP, exchange, DMP and clean room components, can sit inside your own cloud or data centre next to the stitcher. Its SSP and exchange are built to accept pod requests from your stitcher, apply duration floors and keep impression and quartile logs in your own environment, so a disputed impression can be traced from beacon to bid. The architecture page shows where the exchange sits beside a stitcher, and integrations lists the ad servers and SSAI services it connects to.

    Sources

    1. IAB Tech Lab, VAST 4.4 specification, sections 1.1.2, 1.1.3, 1.2, 1.3, 1.9, 2.2, 3.3.1, 3.7.1, 3.9.2 (repository version, accessed 9 November 2026). https://github.com/InteractiveAdvertisingBureau/VAST4.x/blob/main/4.4.md
    2. IAB Tech Lab, VAST4.x repository and commit history (4.4 "considered released since July 22, 2026", commit of 8 September 2026). https://github.com/InteractiveAdvertisingBureau/VAST4.x
    3. IAB Tech Lab, VAST repository README and release notes (VAST 4.0 to 4.2 dates). https://github.com/InteractiveAdvertisingBureau/vast
    4. IAB Tech Lab, "VAST CTV Addendum 2024". https://github.com/InteractiveAdvertisingBureau/vast/blob/master/VAST%20CTV%20Addendum%202024.md
    5. IAB, VMAP 1.0 repository and schema (vmap.xsd). https://github.com/InteractiveAdvertisingBureau/vmap
    6. IAB Tech Lab, OpenRTB 2.6 specification, Objects Imp, Video, Content, Device, Bid (accessed 9 November 2026). https://github.com/InteractiveAdvertisingBureau/openrtb2.x/blob/main/2.6.md
    7. IAB Tech Lab, OpenRTB 2.x implementation guide, sections 7.6, 7.8 and 7.11 (accessed 9 November 2026). https://github.com/InteractiveAdvertisingBureau/openrtb2.x/blob/main/implementation.md
    8. IAB Tech Lab, openrtb2.x releases, 2.6-202606 (11 June 2026). https://github.com/InteractiveAdvertisingBureau/openrtb2.x/releases
    9. IAB Tech Lab, AdCOM 1.0, lists for creative subtypes, device types, slot position in pod and pod deduplication (accessed 9 November 2026). https://github.com/InteractiveAdvertisingBureau/AdCOM/blob/main/AdCOM%20v1.0%20FINAL.md
    10. IAB Tech Lab, "Ad Format Guidelines for Digital Video and CTV", v2.0 (repository updated 20 July 2026). https://github.com/InteractiveAdvertisingBureau/Ad-Format-Guidelines-for-Digital-Video-CTV/blob/main/v2.0.md
    More sources (7)
    1. Amazon Web Services, "MediaTailor server-side ad tracking and reporting" (accessed 9 November 2026). https://docs.aws.amazon.com/mediatailor/latest/ug/ad-reporting-server-side.html
    2. Amazon Web Services, "MediaTailor ad insertion behavior" (accessed 9 November 2026). https://docs.aws.amazon.com/mediatailor/latest/ug/ad-behavior.html
    3. Prebid.org, "Module: Adpod" (accessed 9 November 2026). https://docs.prebid.org/dev-docs/modules/adpod.html
    4. Prebid.org, Prebid.js release 11.0.0 (12 March 2026). https://github.com/prebid/Prebid.js/releases/tag/11.0.0
    5. Prebid.org, "Use Case: Prebid Server, Long Form Video" (accessed 9 November 2026). https://docs.prebid.org/prebid-server/use-cases/pbs-lfv.html
    6. Fiducia, "ANA Programmatic Transparency Benchmark: Q2 2026" (6 August 2026). https://www.fiducia.eco/post/ana-programmatic-transparency-benchmark-q2-2026-working-media-efficiency-reaches-a-record-45
    7. Google Ad Manager Help, "Pricing rules" (accessed 9 November 2026). https://support.google.com/admanager/answer/9298008?hl=en