Skip to content

RFC: declare the DOOH impression basis — typed tier, effective multiplier, and derivation link, at delivery and discovery #7253

Description

@bokelley

Summary

A DOOH impressions figure is never an observed event. It is plays × audience multiplier, where the multiplier comes from a measurement currency, a traffic study, the seller's own model, or — increasingly — an on-site sensor. AdCP already knows this (plays is documented as "raw play count before any impression multiplier is applied"; dooh_metrics.calculation_notes exists to explain the multiplier in prose) but gives a buyer no typed way to learn which kind of number impressions is. Two DOOH products at the same CPM — one on a 2019 traffic study, one on per-play sensor counts — are different products, and today they are indistinguishable on the wire.

Classic OOH already solved this for itself. ooh_metrics.estimation_basis (experimental in 3.2) is a closed tier enum, currency_measured | seller_modeled, with provider identity on the row-level measurement_source slug and a schema dependencies rule that makes the basis mandatory whenever the estimate is reported. This RFC extends that pattern to DOOH, adds the tier that sensors make possible, and exposes the basis at discovery time so buyers can compare before they buy.

Split out of #7150 (§3) per the discussion there; #7177 deliberately did not carry it. Supersedes the audience_multiplier line item from #5537, which closed without it.

What exists today

Surface DOOH Classic OOH
Raw unit plays (top-level) none — static units have no play event
Delivery number impressions (top-level, modelled) ooh_metrics.estimated_impressions
Basis tier none ooh_metrics.estimation_basis (currency_measured / seller_modeled), required when estimated_impressions present
Provider identity row-level measurement_source slug (shared) same
Methodology prose dooh_metrics.calculation_notes ooh_metrics.calculation_notes
Discovery-time declaration dooh_placement_attributes (slot/loop duration, resolution, motion) — no basis n/a
Product-level vendors delivery_measurement.vendors[] + deprecated provider + notes prose same

Proposal

1. Shared basis enum — enums/impression-estimation-basis.json

Hoist ooh_metrics.estimation_basis's inline enum to a shared file and add the tiers DOOH needs:

Value Meaning Provider identity
currency_measured An audience-measurement currency's estimate for the unit and period (Geopath, Route, COMMB, MOVE, and their DOOH products) measurement_source slug
seller_modeled The seller's own model — traffic study, venue-attendance factor, historical footfall. The honest fallback. the seller
sensor_measured Audience derived from an on-site instrument observing presence per play — camera, WiFi/BLE, radar, turnstile, ticketing. Measured, not modelled, though the instrument has its own error. the vendor_metric_values[] row it derives from (see basis_metric)
hybrid A model calibrated by sensors: sensor counts on a sample of screens scale a currency or seller model across the network measurement_source and/or basis_metric

Tier, not provider, not instrument. Currencies change and instruments are an open corpus (DR-0004) — both stay as data (measurement_source, the vendor catalog's methodology_url), not enum values. Four closed tiers is the same shape the OOH block already committed to.

2. dooh_metrics.impression_basis (delivery)

{
  "plays": 964984,
  "impressions": 1481441,
  "dooh_metrics": {
    "impression_basis": "sensor_measured",
    "audience_multiplier": 1.535,
    "basis_metric": { "vendor": { "domain": "dooh-seller.example" }, "metric_id": "people_in_frame" },
    "loop_plays": 964984,
    "screens_used": 1894,
    "calculation_notes": "Per-play detected-person counts; screens with <10 plays fall back to venue model."
  },
  "vendor_metric_values": [
    { "vendor": { "domain": "dooh-seller.example" }, "metric_id": "people_in_frame",
      "value": 1481441, "unit": "persons", "measurable_plays": 964984, "vendor_relationship": "first_party" }
  ]
}
  • impression_basis — the tier. SHOULD be present whenever a DOOH row reports impressions; proposed as a sales-dooh storyboard requirement once stable (mirrors OOH's dependencies rule, expressed on the parent since DOOH impressions is top-level).
  • audience_multiplier (number ≥ 0) — the effective impressions / plays for the row, declared, not inferred. Lets a verifier check impressions ≈ plays × audience_multiplier within tolerance and lets a buyer compare rows. For sensor_measured it is the realised ratio for the period, which will vary by row — that is the point.
  • basis_metric (optional { vendor, metric_id }) — when sensor_measured or hybrid, the vendor_metric_values[] row the audience figure derives from. This turns "impressions came from our cameras" into a join: the row carries coverage (measurable_plays), the seller–vendor relationship (vendor_relationship, feat(schema): typed vendor_relationship and play-based coverage denominators for vendor metrics #7177), and, via the vendor catalog, methodology_url / methodology_version / accreditations[]. No methodology prose is duplicated here.

venue_breakdown[] rows MAY carry impression_basis and audience_multiplier when the basis differs by venue (a mixed network: currency-measured roadside, sensor-measured retail).

3. dooh_placement_attributes.impression_basis (discovery)

Same enum, on the placement, with the same product-level-default / publisher-inheritance rule the block already uses for slot_duration_seconds. Optional audience_multiplier here is the planning value (what the seller's forecast will use). This is the half that changes buying: a buyer agent can filter or weight products by basis before create_media_buy, and get_products can grow a required_impression_basis filter later if demand appears (same filter-not-fail convention as required_vendor_metrics).

4. Forecast symmetry

delivery-forecast points already carry measurement_source and plays; add optional impression_basis so forecast and delivery reconcile on the same declaration, the way measurement_source already does.

5. Reuse, not duplication

  • ooh_metrics.estimation_basis switches its inline enum to the shared file. Renaming the OOH field to impression_basis is available while the block is experimental (Editorial-class under the experimental downgrade) — recommended for symmetry, WG's call.
  • delivery_measurement.notes and calculation_notes stay as row-specific prose. General methodology remains at the measurement catalog.

Non-goals

  • No new pricing_model. Billing stays CPM; what changes is that the CPM's basis is legible. A sensor_measured CPM and a seller_modeled CPM are different products at the same rate, and that is now visible.
  • No attention metric promotion. People-present and people-looking remain vendor_metric_values[] rows (RFC: verified attention as a reportable vendor metric #7150 §5).
  • No instrument or vendor enum (DR-0004).

Open questions for the WG

  1. Is hybrid load-bearing, or does every hybrid collapse to "whichever tier the majority of impressions came from" plus calculation_notes? Place-based audio (RFC: Support place-based audio as DOOH inventory, not screen-only or generic streaming audio #5878) is the test case: presence sensing exists but is sparse.
  2. Should impression_basis be required for the sales-dooh claim at 3.3, or SHOULD-only for one release? OOH chose required-by-dependency from day one.
  3. Is a declared audience_multiplier acceptable to sellers whose multipliers are contractual with a currency provider? If not, the tier alone still carries most of the value.
  4. Rename ooh_metrics.estimation_basisimpression_basis while experimental, or keep both names and share only the enum?

Release target

3.3. 3.2 is at rc.1 with a feature already landing in that candidate; this is a new normative surface the WG has not seen, and the OOH field it mirrors is itself experimental until 3.3. Interim path for sellers is unchanged: calculation_notes prose plus, for sensor networks, vendor_metric_values[] with vendor_relationship: "first_party" and measurable_plays (#7177, rc.1).

Related

cc @snehdhruv (Trillboards — the sensor_measured case), @geneticallymodifiedfoodforthought (place-based audio)

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    claude-triagedIssue has been triaged by the Claude Code triage routine. Remove to re-triage.media-buyIssue concerns the media-buy protocol domainneeds-wg-reviewBlocked on a working-group decision — surface in WG meeting agendasrfcProtocol change — auto-adds to roadmap boardspec / protocol

    Type

    No type

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions