Skip to content

Commit f543f44

Browse files
bokelleyclaude
andauthored
feat(creative): Add typed asset requirements schemas (#955)
Introduce explicit requirement schemas for all asset types with proper discriminated unions. Assets in format.json now use oneOf with asset_type as the discriminator, producing clean types for code generation. Schemas added: - image-asset-requirements: dimensions, formats, animation constraints - video-asset-requirements: dimensions, duration, codecs, bitrate - audio-asset-requirements: duration, formats, sample rates, channels - html-asset-requirements: sandbox, external resources, allowed domains - javascript-asset-requirements: module type, external resources - text-asset-requirements: character/line limits, patterns - url-asset-requirements: protocols, domains, macro support - markdown/css/vast/daast/webhook: type-specific constraints Documentation updated with examples for HTML execution contexts (SafeFrame, fenced frames, native DOM). Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 6adfee9 commit f543f44

19 files changed

Lines changed: 1075 additions & 61 deletions
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
"adcontextprotocol": minor
3+
---
4+
5+
Add typed asset requirements schemas for creative formats
6+
7+
Introduces explicit requirement schemas for every asset type with proper discriminated unions. In `format.json`, assets use `oneOf` with `asset_type` as the discriminator - each variant pairs a specific `asset_type` const with its typed requirements schema. This produces clean discriminated union types for code generation.
8+
9+
- **image-asset-requirements**: `min_width`, `max_width`, `min_height`, `max_height`, `formats`, `max_file_size_kb`, `animation_allowed`, etc.
10+
- **video-asset-requirements**: dimensions, duration, `containers`, `codecs`, `max_bitrate_kbps`, etc.
11+
- **audio-asset-requirements**: `min_duration_ms`, `max_duration_ms`, `formats`, `sample_rates`, `channels`, bitrate constraints
12+
- **text-asset-requirements**: `min_length`, `max_length`, `min_lines`, `max_lines`, `character_pattern`, `prohibited_terms`
13+
- **markdown-asset-requirements**: `max_length`
14+
- **html-asset-requirements**: `sandbox` (none/iframe/safeframe/fencedframe), `external_resources_allowed`, `allowed_external_domains`, `max_file_size_kb`
15+
- **css-asset-requirements**: `max_file_size_kb`
16+
- **javascript-asset-requirements**: `module_type`, `external_resources_allowed`, `max_file_size_kb`
17+
- **vast-asset-requirements**: `vast_version`
18+
- **daast-asset-requirements**: `daast_version`
19+
- **promoted-offerings-asset-requirements**: (extensible)
20+
- **url-asset-requirements**: `protocols`, `allowed_domains`, `macro_support`, `role`
21+
- **webhook-asset-requirements**: `methods`
22+
23+
This allows sales agents to declare execution environment constraints for HTML creatives (e.g., "must work in SafeFrame with no external JS") as part of the format definition.

docs/creative/channels/display.mdx

Lines changed: 194 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,32 @@ Display formats in AdCP include:
2525
"id": "display_300x250"
2626
},
2727
"type": "display",
28+
"renders": [
29+
{
30+
"role": "primary",
31+
"dimensions": {
32+
"width": 300,
33+
"height": 250,
34+
"responsive": { "width": false, "height": false }
35+
}
36+
}
37+
],
2838
"assets": [
2939
{
40+
"item_type": "individual",
3041
"asset_id": "banner_image",
3142
"asset_type": "image",
3243
"asset_role": "hero_image",
3344
"required": true,
3445
"requirements": {
35-
"width": 300,
36-
"height": 250,
37-
"file_types": ["jpg", "png", "webp", "gif"],
38-
"max_file_size_kb": 200
46+
"min_width": 300,
47+
"max_width": 300,
48+
"min_height": 250,
49+
"max_height": 250,
50+
"formats": ["jpg", "png", "webp", "gif"],
51+
"max_file_size_kb": 200,
52+
"animation_allowed": true,
53+
"max_animation_duration_ms": 15000
3954
}
4055
}
4156
]
@@ -229,6 +244,155 @@ Display formats in AdCP include:
229244
}
230245
```
231246

247+
## HTML Display Formats with Execution Context
248+
249+
HTML display creatives run as executable code, not static media. Different publisher environments have different execution constraints - some allow full DOM access, others run in SafeFrame containers with restricted JavaScript capabilities.
250+
251+
AdCP defines explicit **HTML asset requirements** that specify the execution environment the HTML must be compatible with:
252+
253+
- **`sandbox`**: Execution environment (`none`, `iframe`, `safeframe`, `fencedframe`)
254+
- **`external_resources_allowed`**: Whether the creative can load external scripts, images, or fonts
255+
- **`allowed_external_domains`**: Permitted domains for external resources (when allowed)
256+
- **`max_file_size_kb`**: Maximum file size for the HTML asset
257+
258+
### SafeFrame-Compatible HTML Banner
259+
260+
SafeFrame is an IAB standard that provides secure isolation between ad creatives and publisher pages. SafeFrame-compatible creatives cannot use `document.write()`, must use SafeFrame expansion APIs, and cannot make arbitrary cross-origin requests.
261+
262+
```json
263+
{
264+
"format_id": {
265+
"agent_url": "https://creative.adcontextprotocol.org",
266+
"id": "display_300x250_html_safeframe"
267+
},
268+
"name": "SafeFrame HTML Banner 300x250",
269+
"type": "display",
270+
"renders": [
271+
{
272+
"role": "primary",
273+
"dimensions": {
274+
"width": 300,
275+
"height": 250,
276+
"responsive": { "width": false, "height": false }
277+
}
278+
}
279+
],
280+
"assets": [
281+
{
282+
"item_type": "individual",
283+
"asset_id": "banner_html",
284+
"asset_type": "html",
285+
"asset_role": "creative",
286+
"required": true,
287+
"requirements": {
288+
"max_file_size_kb": 150,
289+
"sandbox": "safeframe",
290+
"external_resources_allowed": false
291+
}
292+
},
293+
{
294+
"item_type": "individual",
295+
"asset_id": "landing_url",
296+
"asset_type": "url",
297+
"asset_role": "clickthrough",
298+
"required": true,
299+
"requirements": {
300+
"protocols": ["https"]
301+
}
302+
}
303+
]
304+
}
305+
```
306+
307+
### Native DOM HTML Banner
308+
309+
Some publishers allow full DOM access for trusted creatives. These formats can use standard JavaScript APIs and load external resources.
310+
311+
```json
312+
{
313+
"format_id": {
314+
"agent_url": "https://creative.adcontextprotocol.org",
315+
"id": "display_300x250_html_native"
316+
},
317+
"name": "Native HTML Banner 300x250",
318+
"type": "display",
319+
"renders": [
320+
{
321+
"role": "primary",
322+
"dimensions": {
323+
"width": 300,
324+
"height": 250,
325+
"responsive": { "width": false, "height": false }
326+
}
327+
}
328+
],
329+
"assets": [
330+
{
331+
"item_type": "individual",
332+
"asset_id": "banner_html",
333+
"asset_type": "html",
334+
"asset_role": "creative",
335+
"required": true,
336+
"requirements": {
337+
"max_file_size_kb": 200,
338+
"sandbox": "none",
339+
"external_resources_allowed": true,
340+
"allowed_external_domains": ["cdn.brand.com", "fonts.googleapis.com"]
341+
}
342+
},
343+
{
344+
"item_type": "individual",
345+
"asset_id": "landing_url",
346+
"asset_type": "url",
347+
"asset_role": "clickthrough",
348+
"required": true,
349+
"requirements": {
350+
"protocols": ["https"]
351+
}
352+
}
353+
]
354+
}
355+
```
356+
357+
### Fenced Frame HTML Banner (Privacy Sandbox)
358+
359+
Chrome's Privacy Sandbox introduces Fenced Frames for privacy-preserving ad rendering. These have the most restrictive execution environment.
360+
361+
```json
362+
{
363+
"format_id": {
364+
"agent_url": "https://creative.adcontextprotocol.org",
365+
"id": "display_300x250_html_fencedframe"
366+
},
367+
"name": "Fenced Frame HTML Banner 300x250",
368+
"type": "display",
369+
"renders": [
370+
{
371+
"role": "primary",
372+
"dimensions": {
373+
"width": 300,
374+
"height": 250,
375+
"responsive": { "width": false, "height": false }
376+
}
377+
}
378+
],
379+
"assets": [
380+
{
381+
"item_type": "individual",
382+
"asset_id": "banner_html",
383+
"asset_type": "html",
384+
"asset_role": "creative",
385+
"required": true,
386+
"requirements": {
387+
"max_file_size_kb": 100,
388+
"sandbox": "fencedframe",
389+
"external_resources_allowed": false
390+
}
391+
}
392+
]
393+
}
394+
```
395+
232396
## Third-Party Tag Formats
233397

234398
### JavaScript Tag Format
@@ -240,17 +404,27 @@ Display formats in AdCP include:
240404
"id": "display_300x250_3p"
241405
},
242406
"type": "display",
407+
"renders": [
408+
{
409+
"role": "primary",
410+
"dimensions": {
411+
"width": 300,
412+
"height": 250,
413+
"responsive": { "width": false, "height": false }
414+
}
415+
}
416+
],
243417
"assets": [
244418
{
419+
"item_type": "individual",
245420
"asset_id": "tag",
246421
"asset_type": "javascript",
247422
"asset_role": "third_party_tag",
248423
"required": true,
249424
"requirements": {
250-
"width": 300,
251-
"height": 250,
252425
"max_file_size_kb": 200,
253-
"https_required": true
426+
"external_resources_allowed": true,
427+
"strict_mode_required": false
254428
}
255429
}
256430
]
@@ -283,17 +457,27 @@ JavaScript tag manifest:
283457
"id": "display_728x90_html"
284458
},
285459
"type": "display",
460+
"renders": [
461+
{
462+
"role": "primary",
463+
"dimensions": {
464+
"width": 728,
465+
"height": 90,
466+
"responsive": { "width": false, "height": false }
467+
}
468+
}
469+
],
286470
"assets": [
287471
{
472+
"item_type": "individual",
288473
"asset_id": "tag",
289474
"asset_type": "html",
290475
"asset_role": "third_party_tag",
291476
"required": true,
292477
"requirements": {
293-
"width": 728,
294-
"height": 90,
295478
"max_file_size_kb": 200,
296-
"https_required": true
479+
"sandbox": "iframe",
480+
"external_resources_allowed": true
297481
}
298482
}
299483
]

docs/creative/formats.mdx

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,78 @@ The `assets` array enables comprehensive asset discovery. Each asset has a `requ
306306

307307
This unified approach helps creative tools and AI agents understand the full capabilities of a format, enabling richer creative experiences when optional assets are available while clearly indicating minimum requirements.
308308

309+
### Typed Asset Requirements
310+
311+
Each asset type has its own requirements schema that defines what constraints apply to that asset. The `requirements` object is typed based on the `asset_type`:
312+
313+
**Image assets** (`asset_type: "image"`):
314+
- `min_width`, `max_width`, `min_height`, `max_height` - Dimension constraints (set min=max for exact)
315+
- `aspect_ratio` - Required aspect ratio (e.g., '1:1')
316+
- `formats` - Accepted file formats (jpg, jpeg, png, webp, gif, svg, avif)
317+
- `max_file_size_kb` - Maximum file size
318+
- `animation_allowed` - Whether animated images are accepted
319+
- `max_animation_duration_ms` - Maximum animation duration
320+
321+
**Video assets** (`asset_type: "video"`):
322+
- `min_width`, `max_width`, `min_height`, `max_height` - Dimension constraints
323+
- `aspect_ratio` - Required aspect ratio (e.g., '16:9')
324+
- `min_duration_ms`, `max_duration_ms` - Duration constraints
325+
- `containers` - Accepted container formats (mp4, webm, mov)
326+
- `codecs` - Accepted codecs (h264, h265, vp9, av1)
327+
- `frame_rates` - Accepted frame rates (e.g., [24, 30, 60])
328+
- `max_file_size_kb`, `max_bitrate_kbps` - Size constraints
329+
330+
**HTML assets** (`asset_type: "html"`):
331+
- `max_file_size_kb` - Maximum file size
332+
- `sandbox` - Execution environment (`none`, `iframe`, `safeframe`, `fencedframe`)
333+
- `external_resources_allowed` - Whether external scripts/images can be loaded
334+
- `allowed_external_domains` - Permitted domains for external resources
335+
336+
**JavaScript assets** (`asset_type: "javascript"`):
337+
- `max_file_size_kb` - Maximum file size
338+
- `module_type` - Module format (`script`, `module`, `iife`)
339+
- `external_resources_allowed` - Whether dynamic resource loading is allowed
340+
- `allowed_external_domains` - Permitted domains for dynamic loading
341+
342+
**Audio assets** (`asset_type: "audio"`):
343+
- `min_duration_ms`, `max_duration_ms` - Duration constraints
344+
- `formats` - Accepted audio formats (mp3, aac, wav, ogg, flac)
345+
- `sample_rates` - Accepted sample rates in Hz (e.g., [44100, 48000])
346+
- `channels` - Accepted channel configurations (mono, stereo)
347+
- `min_bitrate_kbps`, `max_bitrate_kbps` - Bitrate constraints
348+
- `max_file_size_kb` - Maximum file size
349+
350+
**Text assets** (`asset_type: "text"`):
351+
- `min_length`, `max_length` - Character limits
352+
- `min_lines`, `max_lines` - Line count limits
353+
- `character_pattern` - Regex for allowed characters
354+
- `prohibited_terms` - Words/phrases not allowed
355+
356+
**URL assets** (`asset_type: "url"`):
357+
- `role` - Standard purpose (clickthrough, impression_tracker, click_tracker, etc.)
358+
- `protocols` - Allowed protocols (https, http)
359+
- `allowed_domains` - Permitted destination domains
360+
- `macro_support` - Whether macro substitution is supported
361+
362+
**Example with HTML execution context:**
363+
364+
```json
365+
{
366+
"asset_id": "banner_html",
367+
"asset_type": "html",
368+
"required": true,
369+
"requirements": {
370+
"max_file_size_kb": 150,
371+
"sandbox": "safeframe",
372+
"external_resources_allowed": false
373+
}
374+
}
375+
```
376+
377+
This tells creative agents: "Build HTML that works in a SafeFrame container with no external resource loading."
378+
379+
See [Display Ads - HTML Display Formats](/docs/creative/channels/display#html-display-formats-with-execution-context) for complete examples.
380+
309381
### Rendered Outputs and Dimensions
310382

311383
Formats describe one or more rendered outputs, each with defined dimensions and semantic roles.

0 commit comments

Comments
 (0)