Skip to main content

TMP for CTV

Connected TV apps compose ad pods — sequences of ads that fill commercial breaks during streaming content. Pod composition means activating multiple packages simultaneously while respecting competitive separation, frequency limits, and duration constraints. TMP handles package activation and identity eligibility; the broadcaster’s ad server handles pod assembly.

How It Works Today

Broadcasters manage CTV deals through their ad server (FreeWheel, Google Ad Manager, SpringServe). Each deal is configured with targeting rules, competitive separation constraints, and creative rotation logic. Pod composition is handled by the ad server’s pod optimization engine. There is no standard way for buyer agents to provide real-time input on which packages to activate or which creative variants to prefer for a specific pod.

The Four Messages

A CTV ad break involves four TMP messages: a context match request and response (what content is playing, which packages match), then an identity match request and response (is this household eligible). The publisher joins the results locally to compose the pod.

Context Match Request

When a pod break approaches, the broadcaster sends a context match request. The placement_id identifies the ad break position (e.g., pre_roll, mid_roll_1, pod_break_2). The artifact_refs reference the show and episode, which buyer agents use for content-level targeting. No package list is sent — the provider uses its synced package set for this placement.
{
  "type": "context_match_request",
  "request_id": "ctx-9f3a-e7b2",
  "property_rid": "01916f3a-a1d3-7000-8000-000000000020",
  "property_id": "riverview-streaming",
  "property_type": "ctv_app",
  "placement_id": "mid_roll_1",
  "artifact_refs": [
    { "type": "gracenote", "value": "SH032541890000" },
    { "type": "eidr", "value": "10.5240/B1A2-C3D4-E5F6-7890-1234-X" }
  ]
}
Key points:
  • Artifacts reference show and episode by industry ID. The buyer agent can match on the show (“The Night Kitchen” is a cooking drama, good fit for food brands) via its Gracenote ID, the specific episode via its EIDR, or both.
  • No package list is sent per request. The provider evaluates all eligible packages for this placement using its synced package set from media buy setup. The same packages are evaluated for every household — filtering by household happens in identity match.
  • Creative support is declared on the product’s trusted_match config. When a product’s config includes creative response types, buyer agents return creative manifests so the broadcaster can render directly.

Context Match Response

Each buyer agent evaluates the content context and responds with offers for packages it wants to activate. The router merges all responses. Here two buyers activated:
{
  "type": "context_match_response",
  "request_id": "ctx-9f3a-e7b2",
  "offers": [
    {
      "package_id": "pkg-sparklean-30s",
      "brand": { "domain": "sparklean.example.com" },
      "summary": "Kitchen cleaning product — contextual fit with cooking drama",
      "creative_manifest": {
        "format_id": { "agent_url": "https://riverview.example.com", "id": "video_30s" },
        "assets": {
          "video": {
            "delivery_type": "url",
            "url": "https://creatives.sparklean.example/vast/kitchen-30s.xml"
          }
        }
      }
    },
    {
      "package_id": "pkg-greenleaf-15s",
      "summary": "Organic grocery — recipe content alignment",
      "creative_manifest": {
        "format_id": { "agent_url": "https://riverview.example.com", "id": "video_15s" },
        "assets": {
          "video": {
            "delivery_type": "url",
            "url": "https://creatives.greenleaf.example/vast/spring-15s.xml"
          }
        }
      }
    }
  ]
}
Vaultline (financial services) and Driftmoto (motorcycle brand) did not match the cooking drama context and are absent from the offers. For CTV creatives, the creative_manifest typically references a VAST URL rather than including the creative inline. Video assets are large; the manifest points to the external asset and the broadcaster’s ad server fetches it at render time.

Identity Match Request

Separately, the broadcaster sends an identity match request with a household token. The package_ids list includes ALL active packages for each buyer — not just the ones in this pod break. This prevents a buyer from correlating the identity request with a specific context request by comparing package sets.
{
  "type": "identity_match_request",
  "request_id": "id-7k2m-p4w1",
  "user_token": "tok_household_q7w2",
  "uid_type": "publisher_first_party",
  "consent": {
    "us_privacy": "1YNN"
  },
  "package_ids": [
    "pkg-sparklean-30s",
    "pkg-sparklean-display-web",
    "pkg-sparklean-native-mobile",
    "pkg-greenleaf-15s",
    "pkg-greenleaf-display-web",
    "pkg-vaultline-30s",
    "pkg-vaultline-audio",
    "pkg-driftmoto-15s",
    "pkg-driftmoto-30s"
  ]
}
The list includes packages from other surfaces (web display, mobile native, audio). The broadcaster maintains a cached list of all active packages per buyer and sends the full set every time.

Identity Match Response

Each buyer agent evaluates the household token against its own data (frequency caps, audience membership, purchase history) and returns the IDs of eligible packages plus a TTL. The buyer does not disclose the reasons — the publisher only needs to know whether the household qualifies.
{
  "type": "identity_match_response",
  "request_id": "id-7k2m-p4w1",
  "eligible_package_ids": [
    "pkg-sparklean-30s",
    "pkg-sparklean-display-web",
    "pkg-greenleaf-15s",
    "pkg-greenleaf-display-web",
    "pkg-vaultline-30s",
    "pkg-vaultline-audio",
    "pkg-driftmoto-30s"
  ],
  "ttl_sec": 90
}
The response covers all packages, not just CTV ones. The ttl_sec: 90 covers the duration of the ad break — the router uses cached eligibility to fill all pod slots without re-querying. The publisher extracts only the package IDs relevant to the current pod.

Pod Composition

The broadcaster now has two sets of results and composes the pod locally:
  1. Filter by context activation. Only packages with offers from context match are candidates: Sparklean (30s) and Greenleaf (15s). Vaultline and Driftmoto did not activate.
  2. Filter by identity eligibility. Of the context-activated packages, check household eligibility: Sparklean is eligible, Greenleaf is eligible. Both pass.
  3. Rank eligible offers. Use the ad server’s own priority and pacing rules to rank the eligible offers.
  4. Apply competitive separation. The broadcaster’s ad server enforces competitive separation rules — two brands in the same advertiser category cannot appear in the same pod. Sparklean (cleaning) and Greenleaf (grocery) are in different categories, so no conflict.
  5. Assemble the pod. Fill the available duration. A typical mid-roll pod might be 60 seconds:
    • Slot 1 (30s): Sparklean — context match, household eligible
    • Slot 2 (15s): Greenleaf — context match, household eligible
    • Remaining 15s: filled by other demand sources (programmatic, house ads)
Competitive separation is the publisher’s responsibility. TMP provides the activation and eligibility signals; the broadcaster’s ad server applies business rules about which brands can appear together. This keeps the protocol simple and avoids encoding category taxonomies into TMP messages.

SSAI Integration

Server-side ad insertion (SSAI) is the dominant CTV delivery model. The TMP Router runs server-side alongside the SSAI engine, keeping the entire activation flow off the client device.
  • Flow. The SSAI engine receives a pod break signal from the content stream, queries the TMP Router for context and identity matches, receives offers, and stitches VAST creatives into the stream before delivery.
  • Creative delivery. The creative_manifest in Context Match responses includes VAST URLs that the SSAI engine can fetch and splice directly. No client-side ad loading is required.
  • Latency budget. The SSAI engine’s overall ad insertion budget is typically 200-500ms (larger than client-side insertion), since stitching happens before stream delivery. The TMP Router still targets sub-50ms for its portion; the extra budget gives the SSAI engine time for VAST fetching and stream stitching.
  • Companion ads. If the VAST response includes companion creatives, the SSAI engine can pass them to the CTV app’s display layer for rendering alongside the video content.

Show and Episode Artifact Refs

CTV artifacts typically reference both a show and a specific episode using industry-standard identifiers:
"artifact_refs": [
  { "type": "gracenote", "value": "SH032541890000" },
  { "type": "eidr", "value": "10.5240/B1A2-C3D4-E5F6-7890-1234-X" }
]
EIDR (Entertainment Identifier Registry) provides globally unique IDs for shows, seasons, and episodes. Gracenote TMS IDs are equally valid. The key requirement: the identifier must be publicly resolvable so buyers can independently look up metadata. A buyer agent can use these at different granularities:
  • Show-level targeting. “Activate on any episode of The Night Kitchen” — the agent checks whether the Gracenote show ID is in its targeting rules.
  • Episode-level targeting. “Activate only on the season premiere” — the agent checks the specific EIDR episode ID.
  • Genre or topic targeting. The agent resolves genre and topic metadata from its cached artifact data. This works for broad category targeting without hard-coding specific show IDs in targeting rules.

Example Flow

Mid-roll break in "The Night Kitchen" S02E07

  Context Match
  --> Broadcaster sends request: show + episode artifacts, placement context
  --> Sparklean agent: activate pkg-sparklean-30s (VAST creative, cooking context fit)
  --> Greenleaf agent: activate pkg-greenleaf-15s (VAST creative, food content)
  --> Vaultline agent: no activation (financial services, no context fit)
  --> Driftmoto agent: no activation (motorcycle brand, no context fit)

  Identity Match (after temporal decorrelation delay)
  --> Broadcaster sends request: all 9 active packages across all buyers
  --> Response: eligible_package_ids includes Sparklean, Greenleaf, Vaultline, Driftmoto-30s
  --> ttl_sec: 90 (covers the ad break)

  Pod Assembly (broadcaster's ad server)
  --> Join: Sparklean and Greenleaf both activated and eligible
  --> Competitive separation: different categories, no conflict
  --> Pod: Sparklean 30s + Greenleaf 15s + 15s backfill
  --> Fetch VAST creatives from manifest URLs
  --> Serve pod during commercial break