Skip to main content

Creative Manifests

Complete guide to AdCP creative manifest structure, asset types, and validation.

Overview

AdCP creative manifests provide a standardized way to describe creative assets and their requirements. Instead of sending pre-assembled markup, bidders provide a manifest that publishers use to assemble and render the creative.

Manifest Structure

AdCP creative manifests follow a standardized structure where assets are keyed by asset_id:

{
"format_id": {
"agent_url": "https://creative.adcontextprotocol.org",
"id": "display_300x250"
},
"promoted_offering": "Spring Sale Collection",
"assets": {
"banner_image": {
"url": "https://cdn.brand.com/banner.jpg",
"width": 300,
"height": 250,
"format": "jpg"
},
"headline": {
"content": "50% Off Spring Sale"
},
"clickthrough_url": {
"url": "https://brand.com/spring?campaign={MEDIA_BUY_ID}"
},
"impression_tracker": {
"url": "https://track.brand.com/imp?buy={MEDIA_BUY_ID}&cb={CACHEBUSTER}"
}
}
}

Root-Level Fields

FieldTypeRequiredDescription
format_idobjectYesFormat identifier matching request
format_id.agent_urlstringYesCreative agent URL
format_id.idstringYesFormat ID
promoted_offeringstringNoProduct/service being advertised
assetsobjectYesCreative assets keyed by asset_id

Asset Structure

Assets are keyed by asset_id (which matches the format's assets_required array). Each asset has type-specific fields:

Image Assets

{
"banner_image": {
"url": "https://cdn.brand.com/banner.jpg",
"width": 300,
"height": 250,
"format": "jpg",
"alt_text": "Spring Sale Banner"
}
}

Fields:

FieldTypeRequiredDescription
urlstringYesImage URL
widthintegerYesImage width in pixels
heightintegerYesImage height in pixels
formatstringYesImage format (jpg, png, gif)
alt_textstringNoAlternative text for accessibility

Text Assets

{
"headline": {
"content": "50% Off Spring Sale"
},
"description": {
"content": "Limited time offer on all spring items"
}
}

Fields:

FieldTypeRequiredDescription
contentstringYesText content

URL Assets

{
"clickthrough_url": {
"url": "https://brand.com/spring?campaign={MEDIA_BUY_ID}"
}
}

Fields:

FieldTypeRequiredDescription
urlstringYesURL (may include universal macros)

Tracking Assets

{
"impression_tracker": {
"url": "https://track.brand.com/imp?buy={MEDIA_BUY_ID}&cb={CACHEBUSTER}"
},
"click_tracker": {
"url": "https://track.brand.com/click?buy={MEDIA_BUY_ID}&cb={CACHEBUSTER}"
}
}

Fields:

FieldTypeRequiredDescription
urlstringYesTracking URL (may include macros)

Complete Example

Display Banner Manifest

{
"format_id": {
"agent_url": "https://creative.adcontextprotocol.org",
"id": "display_728x90"
},
"promoted_offering": "Premium Travel Package",
"assets": {
"banner_image": {
"url": "https://cdn.travel.com/banner-728x90.jpg",
"width": 728,
"height": 90,
"format": "jpg",
"alt_text": "Luxury beach resort"
},
"headline": {
"content": "Escape to Paradise"
},
"description": {
"content": "All-inclusive luxury resort from $299/night"
},
"clickthrough_url": {
"url": "https://travel.com/resort?campaign={MEDIA_BUY_ID}&device={DEVICE_TYPE}"
},
"impression_tracker": {
"url": "https://track.travel.com/imp?buy={MEDIA_BUY_ID}&cb={CACHEBUSTER}"
},
"click_tracker": {
"url": "https://track.travel.com/click?buy={MEDIA_BUY_ID}&cb={CACHEBUSTER}"
}
}
}

Native Ad Manifest

{
"format_id": {
"agent_url": "https://creative.adcontextprotocol.org",
"id": "native_article"
},
"promoted_offering": "Smart Home Security System",
"assets": {
"title": {
"content": "Protect Your Home with AI-Powered Security"
},
"description": {
"content": "24/7 monitoring with facial recognition and instant alerts"
},
"main_image": {
"url": "https://cdn.security.com/product.jpg",
"width": 1200,
"height": 628,
"format": "jpg",
"alt_text": "Smart security camera"
},
"icon": {
"url": "https://cdn.security.com/logo.png",
"width": 100,
"height": 100,
"format": "png",
"alt_text": "SecureHome logo"
},
"sponsor": {
"content": "SecureHome"
},
"cta_text": {
"content": "Learn More"
},
"clickthrough_url": {
"url": "https://securehome.com/product?campaign={MEDIA_BUY_ID}"
},
"impression_tracker": {
"url": "https://track.securehome.com/imp?buy={MEDIA_BUY_ID}&cb={CACHEBUSTER}"
}
}
}

Bid Response Integration

Creative manifests are included in bid responses within bid.ext.aura.adcpFormat:

{
"bid": {
"id": "bid-001",
"impid": "imp-1",
"price": 2.5,
"adm": "<a href='https://brand.com'><img src='https://cdn.com/banner.jpg'/></a>",
"ext": {
"aura": {
"adcpFormat": {
"formatId": {
"agent_url": "https://creative.adcontextprotocol.org",
"id": "display_300x250"
},
"creativeManifest": {
"format_id": {
"agent_url": "https://creative.adcontextprotocol.org",
"id": "display_300x250"
},
"promoted_offering": "Product Name",
"assets": {
"banner_image": {
"url": "https://cdn.brand.com/banner.jpg",
"width": 300,
"height": 250,
"format": "jpg"
},
"clickthrough_url": {
"url": "https://brand.com/product?campaign={MEDIA_BUY_ID}"
},
"impression_tracker": {
"url": "https://track.brand.com/imp?buy={MEDIA_BUY_ID}&cb={CACHEBUSTER}"
}
}
}
}
}
}
}
}

Validation

Publishers should validate creative manifests against format definitions:

1. Format ID Validation

function validateFormatId(manifest, requestedFormats) {
const formatId = `${manifest.format_id.agent_url}/${manifest.format_id.id}`
const requested = requestedFormats.map(f => `${f.agent_url}/${f.id}`)

if (!requested.includes(formatId)) {
throw new Error(`Format ${formatId} not requested`)
}
}

2. Required Assets Validation

function validateRequiredAssets(manifest, formatDefinition) {
const requiredAssets = formatDefinition.assets_required
.filter(a => a.required)
.map(a => a.asset_id)

for (const assetId of requiredAssets) {
if (!manifest.assets[assetId]) {
throw new Error(`Required asset ${assetId} missing`)
}
}
}

3. Asset Type Validation

function validateAssetTypes(manifest, formatDefinition) {
for (const [assetId, asset] of Object.entries(manifest.assets)) {
const assetDef = formatDefinition.assets_required.find(
a => a.asset_id === assetId
)

if (!assetDef) {
console.warn(`Unknown asset ${assetId}`)
continue
}

// Validate based on asset type
switch (assetDef.asset_type) {
case 'image':
validateImageAsset(asset, assetDef.requirements)
break
case 'text':
validateTextAsset(asset, assetDef.requirements)
break
case 'url':
validateUrlAsset(asset)
break
}
}
}

4. Image Asset Validation

function validateImageAsset(asset, requirements) {
// Check dimensions
if (requirements.width && asset.width !== requirements.width) {
throw new Error(
`Image width ${asset.width} doesn't match required ${requirements.width}`
)
}

if (requirements.height && asset.height !== requirements.height) {
throw new Error(
`Image height ${asset.height} doesn't match required ${requirements.height}`
)
}

// Check format
if (
requirements.acceptable_formats &&
!requirements.acceptable_formats.includes(asset.format)
) {
throw new Error(`Image format ${asset.format} not acceptable`)
}

// Check URL is valid
if (!isValidUrl(asset.url)) {
throw new Error(`Invalid image URL: ${asset.url}`)
}
}

Brand Manifest

Brand Manifests provide brand identity and context for creative generation. They can be included inline or referenced by URL.

Inline Brand Manifest

{
"brand_manifest": {
"url": "https://mybrand.com",
"name": "My Brand",
"colors": {
"primary": "#FF6B35",
"secondary": "#004E89"
},
"fonts": {
"primary": "Helvetica Neue",
"secondary": "Georgia"
},
"tone": "professional and trustworthy",
"tagline": "Innovation You Can Trust"
}
}

Brand Manifest by URL Reference

{
"brand_manifest": "https://cdn.mybrand.com/brand-manifest.json"
}

Minimal Brand Manifest

{
"brand_manifest": {
"url": "https://mybrand.com"
}
}

Best Practices

1. Always Provide Fallback

Include standard OpenRTB adm field as fallback:

{
"bid": {
"adm": "<a href='...'><img src='...'/></a>",
"ext": {
"aura": {
"adcpFormat": {
"creativeManifest": {
/* ... */
}
}
}
}
}
}

2. Validate Before Sending

Validate manifests against format definitions before including in bid responses:

function validateManifest(manifest, formatDefinition) {
validateFormatId(manifest, formatDefinition)
validateRequiredAssets(manifest, formatDefinition)
validateAssetTypes(manifest, formatDefinition)
return true
}

4. Optimize Asset URLs

Use CDN URLs for all assets to ensure fast loading:

{
"banner_image": {
"url": "https://cdn.brand.com/banner.jpg" // ✅ CDN URL
}
}

5. Include Alt Text

Always include alt text for images for accessibility:

{
"banner_image": {
"url": "https://cdn.brand.com/banner.jpg",
"alt_text": "Luxury beach resort with palm trees"
}
}

Next Steps