Skip to content

[Change] § 5.2, § 5.5 — DOOH properties: venue type, screens, operating hours, and loop #96

Open

Description

@KonstantinMirin

What kind of change?

Change a field's type or shape

Which section?

5.2 — Inventory composition

Current text

§ 5.2: | `properties` | Object | selectable | `available[]` of `{ id, name, domains, supported_formats }`, `included[]`, `pricing`, `max_select` |

§ 5.5: | `frequency_cap` | Object | settable | `{ max: { min, max }, period, basis: device \| household \| listener }`. Basis matters: CTV typically caps at household, audio at listener |

§ 5.6: | `availability` | Object | derived | `{ unit, basis, as_of, granularity, type: forecast \| reservable, quantity }`. Recomputed against the buyer's selection |

§ 5.9: | `serving_mode` | Enum | seller-set | `client_side` \| `ssai` \| `dai` |

Proposed text

§ 5.2, `properties` row: add `venue_type, allocation, screens, min_screens,
slots_per_loop, sync_groups` to the `available[]` keys.

Add after the table:

**DOOH properties.** When `channel` is `dooh`, a property is a set of
screens of one venue type, `domains` holds the inventory owner's domain (as
OpenRTB 2.6 `dooh.domain`), and `venue_type` is REQUIRED. `screens` is
REQUIRED when `allocation` is `all`.

| Key | Meaning |
| :--- | :--- |
| `venue_type` | `{ taxonomy, ids[] }`. `taxonomy` is a value of AdCOM 1.0 List: DOOH Venue Taxonomies; `ids[]` holds exactly one id in that taxonomy, which covers only itself, not its descendants. The values OpenRTB 2.6 `dooh.venuetypetax` and `dooh.venuetype` carry |
| `allocation` | `all` (default) or `seller_allocated`. With `all`, the line item runs on every listed screen. With `seller_allocated`, the seller picks the screens: `screens`, when present, is the pool it picks from and is seller-set, and the proof-of-play log names the screens used |
| `min_screens` | With `seller_allocated`, the fewest screens the seller allocates to the line item |
| `screens` | Array of `{ screen_id, lat, lon, movable, time_zone, operating_hours, loop }`. `screen_id` is the seller's id for the screen, as its proof-of-play log carries it. When the bid request's `device.ifa_type` is `ppid`, `device.ifa` carries the same id. `lat` and `lon` are absent when `movable` is true |
| `operating_hours` | `{ days[], start, before }` windows, in the screen's IANA `time_zone`. `before` is the first minute after the window |
| `loop` | `{ length_s, slot_s }`: loop length and slot length. Absent when the screen schedules ads without a loop |
| `slots_per_loop` | The slots per loop the line item buys on each screen of the property that has a `loop` |
| `sync_groups` | Array of `{ sync_group_id, screen_ids[], min_screens_per_play }`: screens that show the same ad at the same moment, sold as one. `min_screens_per_play` is the fewest of the group's screens that must show a display for it to count as one play |

With `seller_allocated`, a buyer value MUST NOT name or exclude individual
screens.

The committed quantity is in the committed `pricing[]` entry's unit: `PLAY`
commits plays, and `CPM` commits impressions. The other count is
informative. With `seller_allocated`, or on a screen that schedules without
a loop, plays are also reported. A `committed_metrics[]` tuple commits its
own level either way.

With a `loop`, a screen delivers `slots_per_loop` × 3,600 ÷ `length_s` plays per
operating hour.

§ 5.5, `frequency_cap` row: replace `max: { min, max }` with `count`, and
`basis: device \| household \| listener` with `per`, a core term or an
extension term `<domain>:<term>`.

After the table:

**Frequency cap `per`.** The core terms are `device`, `household`,
`listener`, and `screen`. `screen` caps plays per DOOH screen, counted by `screen_id`, or by `sync_group_id` for a sync group's screens; in
the bid stream, the screen is the OpenRTB 2.6 `device` with `devicetype` 8.

§ 5.6, `availability` row, append:

The `unit` core terms are the cost methods' units, such as `impressions`
and `plays`, and `slots_per_loop` and `unit_periods` (one unit for one period,
such as a board for a 4-week cycle). Extension terms are `<domain>:<term>`.
An `availability` compares with a commitment only in the committed entry's
unit.

§ 5.9, `serving_mode` row: add the core term `scheduled`, where the media
owner's scheduler pushes plays to the player.

§ 2.1, Summary Representation: add `properties.available[].venue_type`.

Why

A DOOH line item can name a screen as a property, but not its venue, location, operating hours, or loop. § 5.2 gives a property only an id, a name, domains, and formats.

Those four terms set the plays, and through the multiplier (our plays and impressions filing) the price. One 10-second slot in a 60-second loop, 06:00–24:00, gives 1,080 plays per screen-day. A buyer counting 18 hours on a mall screen open 10:00–21:00 expects 7 hours too many. This change drafts the loop and hours terms of #79.

Transit sellers also sell stations or lines and pick the screens, as #81 and #83 ask. allocation: seller_allocated covers that sale. As @premesh (OUTFRONT Media) explains on #79, a buyer who picks screens in a pooled product defeats the product. So a pool's screens are seller-set, and its impression goal is a CPM entry.

Venue sellers sell synchronized screens as one play, as @premesh explains on our plays and impressions filing; sync_groups names them. @premesh suggests folding them into this model.

The bid stream has these keys:

As @premesh (OUTFRONT Media) points out on #8, device | household | listener has no meaning on a one-to-many screen, so the change adds screen, with plays as the unit. per, the draft's basis, becomes an open vocabulary, as our cost-method filing (#94) makes cost_method, so a later term needs no revision.

@jaanijuk asks on #134 for core terms for availability.unit. @premesh lists the units sellers use on #8, and notes that serving_mode doesn't describe a media owner's scheduler. The cost methods' units are in our pricing PR, and the serving_mode core terms in our video and audio PR.

The MRC Out-of-Home Measurement Standards, Phase 1 & 2 Combined count plays per Loop and require: "Display operating times must be defined and factored into impression counts".

Details and examples: DOOH properties: full rationale and examples

Knock-on effects

Open questions for the working group

  1. When device.ifa_type is ppid, should device.ifa be REQUIRED to equal screen_id or only RECOMMENDED, and when it's sspid, should the exchange's id map to screen_id through device.eids or another way?
  2. Answered by @premesh on #8. On a dooh line item, should device mean the screen, as proposed, or should the cap gain an explicit screen term? The proposed text adds screen, and device keeps its own meaning.
  3. When a buyer's frequency_cap allows fewer plays than the bought slots_per_loop and loop deliver, should the cap lower the expected plays and units, or should the seller reject the selection as inconsistent?
  4. Should one line item be able to select both an all property and a seller_allocated property, or should every selected property share one allocation?
  5. When a DOOH inventory owner publishes no ads.txt at its domains entry, should the check in our seller relationship filing run through sellers.json and OpenRTB 2.6 dooh.publisher, or should the claim stay unverifiable, as that filing proposes?
  6. Should operating_hours carry dated exceptions, such as holiday closures, or should the proof-of-play log alone show the plays those days lose? This is open question 4 of our screen loop reply on #79.
  7. Should a screen cap count plays of each creative, or of all the line item's creatives together? @jaanijuk raises it.
  8. Answered in our shared types PR and our buyer writes PR. Which period values should frequency_cap take, and is each a calendar period or a rolling window? As @jaanijuk reports, a GAM mapping writes a day as "1 day", where their line item writes "day". The PRs make period one of hour, day, week, month, or flight, and every value but flight a calendar period in time_zone.
  9. How does a line item identify a taxonomy version that AdCOM 1.0 List: DOOH Venue Taxonomies doesn't list yet, such as OpenOOH 1.2.1? And does one version's taxonomy value cover later versions? AdCOM expects an entry to "refer to a specific version, unless a given taxonomy has explicit semantics for forward compatibility and handling updates". @jaanijuk raises both in #134.
  10. On a dooh line item, does a FLAT day count plays or impressions? Our rules issue asks implementers whether they need a rule.

Would this break an implementation already built to this draft?

Yes — breaking (a dooh property without venue_type, or sold whole without screens, no longer conforms)

Alternatives you considered and rejected

  • One line item per screen. Thousands of line items, and no package price.
  • One property per screen, with no new keys. The buyer still can't see venue, hours, or loop.
  • Venue type as a string. OpenOOH 1.1 deprecates strings.

You are commenting as

Other — IAB Tech Lab member (Postindustria).

Before you submit

  • I have read CONTRIBUTING.md and agree my contribution may be published under this repository's licence.
  • This contains no confidential or commercially sensitive information.

Revised 2026-11-03: Our shared types PR gives per and count, and drops catalog_ref, so screens are listed inline. Our buyer writes PR gives before, our DOOH PR slots_per_loop and sync_group_id, and our property option PR venue_type.ids[]. The committed quantity is in the committed entry's unit. Adds core unit terms and scheduled, from @jaanijuk on #134 and @premesh on #8. Answers open question 8, and adds 10.

Analyzed and generated with the help of Claude, fully reviewed by me.

Activity

  1. KonstantinMirin commented on Oct 23, 2026

    @KonstantinMirin
    Author

    Revision, from seller input on #79. @premesh (OUTFRONT Media) answered two of our open questions from how they sell. A pooled product and a fixed loop commit different units. A buyer who picks screens in a pooled product defeats the product.

    We revise the allocation row to:

    | `allocation` | `all` (default) or `seller_allocated`. With `all`, the line item runs on every listed screen. With `seller_allocated`, the seller picks the screens: `screens`, when present, is the pool it picks from and is seller-set, and the proof-of-play log names the screens used |
    
    With `seller_allocated`, a buyer value MUST NOT name or exclude individual
    screens.
    
    The committed quantity follows the product:
    
    - `allocation: all`, screens with a `loop`: plays are committed, verified by
      `proof_of_play`; impressions are informative.
    - `allocation: seller_allocated`: impressions are committed against the
      controlling measurement; plays are informative and reported.
    - A screen that schedules without a loop: impressions are committed; plays
      are reported.

    This replaces "delivery is counted in plays or impressions across the pool". The play and impression definitions are in our plays and impressions change request (#92). The controlling measurement is in our settlement change request (#95) and measurement source per committed metric (#38). The matching share-of-voice basis is on our delivery type change request (#93).

    Open question 4 of our reply on #79 stays open: should operating_hours carry dated exceptions, such as holiday closures, or should the proof-of-play log alone show the plays those days lose?

    Analyzed and generated with the help of Claude, fully reviewed by me.

  2. esteininger commented on Oct 23, 2026

    @esteininger

    Commenting as a content classification vendor (Mixpeek). Cites v3.0-draft-1.

    Support the property shape here. One gap for buyers who care about adjacency: the
    property says where the screen is and how the loop runs, but not what else plays in the
    loop. A transit screen that runs news headlines and one that runs sports highlights look
    identical in the proposal.

    #48 proposes content_categories.declared[] on inventory with a version-pinned
    taxonomy_ref (IAB Content Taxonomy 3.1 maps to AdCOM cattax 9). For DOOH it would sit
    on the property, or per screen when screens in one property run different loops, and
    classification.method: model covers the case where the categories come from
    classifying the loop's editorial content rather than a seller label. The same ids can
    then travel in the bid request, so discovery and execution agree.

    Suggest #96 notes that content_categories (if accepted) applies to DOOH properties, at
    property or screen level.

  3. KonstantinMirin commented on Oct 25, 2026

    @KonstantinMirin
    Author

    Thank you, @esteininger. Agreed, as a knock-on of this filing. Your content categories on inventory (#48) puts content_categories on the line item. We'll add this to the filing as a knock-on: if the working group accepts #48, content_categories, in #48's shape, joins the DOOH property keys. Categories sit on the property only. Screens that show different content around the ad are a separate property, as screens of different venue types are, so nothing combines under the no-inheritance rule (§ 2). This matches the bid stream: a DOOH bid request can carry what plays on its screen in OpenRTB 2.6 dooh.content, as cat with cattax.

    Following @premesh's answer on #8, this revision also makes frequency_cap.basis an open vocabulary, as our cost-method filing (#94) does for cost_method, and adds screen as a core term for DOOH.

    Analyzed and generated with the help of Claude, fully reviewed by me.

  4. jaanijuk commented on Oct 28, 2026

    @jaanijuk

    Implementation evidence for this change's basis revision, which we support: screen as a core term, and extension terms written <domain>:<term>. From IAB Australia's AAMP lab: an unreleased seller-agent branch (IABTechLab/seller-agent, feat/openproposal-mapping at e77022e), synthetic data, three runs across two environments with byte-identical results. #134 has the details.

    • The branch's line-item model types basis and period as free strings. It accepted basis: "screen" on our DOOH line item, but it would accept any other string too. The revision's rule, a core term or <domain>:<term>, gives an implementation something to check.
    • Its GAM mappings report the gap from the ad-server side: "frequency_cap.basis: GAM caps per user; OpenProposal wants device, household or listener". They leave basis unset.
    • The same mappings write period as "1 day", from GAM's one-day time unit, where our DOOH line item used "day". The model accepted both.
    • Against draft 1, the independent schema from [Impl] A schema can't be derived from the tables yet: seven authoring rules and a CI lint would fix that #121 rejects a bare "screen" and accepts a namespaced term (checked with Python jsonschema 4.26.0): the rule the revision now writes into § 5.5.

    Two points § 5.5 still leaves open:

    1. Scope. Whether a screen cap counts plays of one creative or of all the line item's creatives.
    2. Period. The period values, and whether each is a calendar period or a rolling window. GAM's one-day unit and a hand-written line item already write a day differently.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions