> ## Documentation Index
> Fetch the complete documentation index at: https://docs.adcontextprotocol.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Targeting

> AdCP targeting — how natural language briefs replace taxonomy-based audience selection, with geographic overlays and real-time decisioning at impression time.

AdCP's targeting philosophy centers on **brief-based targeting** where targeting requirements are communicated through natural language briefs, and publishers return products that include all necessary targeting capabilities.

## Core Principle: Targeting Through Briefs

The primary way to specify targeting in AdCP is through campaign briefs. Instead of configuring complex targeting parameters, buyers describe their audience requirements in plain language:

```json theme={null}
{
  "brief": "We want to reach millennial parents (ages 25-40) in major US metro areas who are interested in sustainable products. Focus on mobile and desktop during evening hours when families are planning purchases."
}
```

Publishers then return products that include the targeting capabilities to reach this audience, with targeting costs built into the media pricing.

When the buyer wants package-level control over specific selectable signals that the seller offers, use `targeting_overlay.signal_targeting_groups` on the package. Buy-time eligibility comes from the selected product's signal targeting contract: `signal_targeting_allowed`, inline `Product.signal_targeting_options` when present, the seller's `get_signals` feed for wholesale products that omit inline options, and `signal_targeting_rules`. Signals are named targetable dimensions, referenced with `signal_ref`: `scope: "product"` for product-local signal options, `scope: "data_provider"` with `data_provider_domain` for signals defined in a data provider's published adagents.json `signals[]`, or `scope: "signal_source"` with `signal_source_url` for source-native signals that are not published in adagents.json `signals[]`. `signal_ref.scope` is the buy-time resolution path, not provenance, and authoritative enrichment lives on the seller, data provider, or source signal definition. Do not overload `audience_include` or `audience_exclude` for this purpose; those fields are only for first-party audiences registered through `sync_audiences`.

Products can also expose `included_signals` for signals already bundled into or planned into the product. Those signals are descriptive product metadata, not package-level targeting controls, and buyers do not echo them in `signal_targeting_groups`.

## Why Brief-Based Targeting?

### Eliminates Targeting Conflicts

* **Single source**: All targeting comes from the publisher's product definition
* **No layering conflicts**: Avoids multiple targeting systems competing
* **Pricing consistency**: Targeting costs are transparent and included in media prices

### Simplifies Implementation

* **Natural language**: Buyers describe needs in familiar terms
* **Publisher expertise**: Publishers know their inventory and audience capabilities best
* **Reduced complexity**: No need to learn platform-specific targeting syntax

### Enables Accurate Pricing

* **Inclusive pricing**: All targeting costs are built into the product price
* **No surprises**: Buyers know the complete cost upfront
* **Market-driven**: Pricing reflects true market value of targeted inventory

## Real-Time Decisioning with TMP

For targeting decisions that must happen at impression time, AdCP uses the **[Trusted Match Protocol (TMP)](/docs/trusted-match)**. TMP is the real-time execution layer that evaluates pre-negotiated packages at serve time across any surface.

TMP gives the buyer a real-time look at each eligible impression through two structurally separated operations — Context Match (content relevance) and Identity Match (user eligibility) — without exposing user identity and page context to the buyer simultaneously.

**Key capabilities:**

* **Cross-publisher frequency capping**: Manage user exposure across multiple publishers via the Identity Match path
* **Dynamic audience targeting**: Evaluate audience membership at impression time without sharing PII
* **Brand suitability enforcement**: Real-time content evaluation through the Context Match path
* **First-party data activation**: Use your customer data without exposing it to publishers

**When to use TMP:**

* Cross-publisher frequency caps
* Suppression lists (existing customers, past converters)
* Audience segments that can't be expressed in a brief
* Real-time brand suitability beyond static rules
* Any impression-time decision across web, mobile, CTV, AI assistants, or retail media

See the [TMP documentation](/docs/trusted-match) for the full specification and surface-specific integration guides.

## How Publishers Include Targeting

Publishers incorporate targeting capabilities directly into their product definitions:

### Geographic Targeting

Products specify geographic coverage:

```
"Chicago metro premium display package" 
"US national mobile video inventory"
"California lifestyle sites network"
```

### Demographic Targeting

Audience characteristics are built into products:

```
"Millennial-focused social media placements"
"Premium business professional network"
"Family-oriented content sites"
```

### Contextual Targeting

Content alignment is inherent in product descriptions:

```
"Sports content premium video inventory"
"Financial news site network"
"Entertainment property display package"
```

### Device & Platform Targeting

Technical specifications included in product format:

```
"Mobile-optimized video formats"
"Connected TV premium inventory"
"Desktop display network"
```

## Brief Examples for Common Targeting Needs

### Geographic Targeting

```json theme={null}
{
  "brief": "Target users in New York, Los Angeles, and Chicago metro areas with premium display advertising for our luxury retail brand."
}
```

### Demographic Targeting

```json theme={null}
{
  "brief": "Reach parents with children under 10 who are interested in educational content, focusing on weekend and evening viewing times."
}
```

### Contextual Targeting

```json theme={null}
{
  "brief": "Place financial services ads adjacent to business and investment content, targeting affluent professionals during business hours."
}
```

### Behavioral Targeting

```json theme={null}
{
  "brief": "Target users who have shown interest in sustainable products and eco-friendly brands, particularly those researching major purchases."
}
```

## Product Response Targeting Information

When publishers return products, they include targeting information buyers need:

```json theme={null}
{
  "$schema": "/schemas/media-buy/get-products-response.json",
  "status": "completed",
  "cache_scope": "public",
  "products": [
    {
      "product_id": "premium_millennial_mobile",
      "name": "Premium Millennial Mobile Package",
      "description": "Mobile display inventory reaching adults 25-40 across lifestyle and entertainment apps in the top 25 US metro areas.",
      "publisher_properties": [
        {
          "publisher_domain": "pinnacle-media.example",
          "selection_type": "by_tag",
          "property_tags": ["lifestyle", "entertainment", "mobile_app"]
        }
      ],
      "channels": ["display"],
      "delivery_type": "guaranteed",
      "format_ids": [
        {
          "agent_url": "https://creative.adcontextprotocol.org",
          "id": "display_300x250_image"
        }
      ],
      "pricing_options": [
        {
          "pricing_option_id": "premium_mobile_cpm",
          "pricing_model": "cpm",
          "currency": "USD",
          "fixed_price": 8.50
        }
      ],
      "forecast": {
        "forecast_range_unit": "availability",
        "method": "modeled",
        "currency": "USD",
        "reach_unit": "individuals",
        "points": [
          {
            "metrics": {
              "audience_size": { "mid": 2500000 },
              "impressions": { "mid": 12000000 }
            }
          }
        ]
      },
      "included_signals": [
        {
          "signal_ref": {
            "scope": "product",
            "signal_id": "lifestyle_entertainment_interest"
          },
          "name": "Lifestyle and entertainment interest",
          "value_type": "binary",
          "description": "Seller-modeled users with recent lifestyle or entertainment content engagement."
        }
      ],
      "reporting_capabilities": {
        "available_reporting_frequencies": ["daily"],
        "expected_delay_minutes": 240,
        "timezone": "America/New_York",
        "supports_webhooks": false,
        "available_metrics": ["impressions", "clicks", "spend", "ctr"],
        "date_range_support": "date_range"
      },
      "brief_relevance": "Matches the requested millennial audience, mobile app environment, lifestyle/entertainment context, and major US metro coverage."
    }
  ]
}
```

## Product Filters vs Targeting Overlays

Some targeting dimensions appear in both `get_products` filters and `create_media_buy` targeting overlays. These serve different purposes at different stages:

| Filter (`get_products`) | Overlay (`create_media_buy`)            | Filter: what it does                         | Overlay: what it does                 |
| ----------------------- | --------------------------------------- | -------------------------------------------- | ------------------------------------- |
| `countries`             | `geo_countries` / `_exclude`            | Show products serving these countries        | Deliver only in these countries       |
| `regions`               | `geo_regions` / `_exclude`              | Show products serving these regions          | Deliver only in these regions         |
| `metros`                | `geo_metros` / `_exclude`               | Show products serving these metros           | Deliver only in these metros          |
| `postal_areas`          | `geo_postal_areas` / `_exclude`         | Show products serving these postal codes     | Deliver only in these postal codes    |
| `geo_proximity`         | `geo_proximity`                         | Show products with inventory near this point | Deliver only to users near this point |
| `keywords`              | `keyword_targets` / `negative_keywords` | Show products supporting these search terms  | Bid on these specific terms           |

**Filters** tell the sell-side agent what matters to the buyer so it can curate relevant products. Without a proximity filter, a seller might recommend products that don't support geo\_proximity — and the buyer wouldn't discover the gap until `create_media_buy`.

**Overlays** apply the precise functional constraint at execution time. The overlay is what the seller's ad server enforces.

Value filters (`countries`, `regions`, `metros`, `postal_areas`, `geo_proximity`, `keywords`) narrow by coverage area — "show me inventory in these places." Capability filters (`required_geo_targeting`, `required_features`) narrow by what the seller can enforce — "only sellers that support zip-level targeting." These compose: use both when you need inventory in a specific area from sellers that can target at that granularity.

For buyers: pass filters at discovery time, then apply the same values (or refined versions) as overlays at buy time. Note that overlay schemas are stricter — for example, `keyword_targets` requires `match_type` while the `keywords` filter defaults to `broad`.

### Example: discovery to buy

```json theme={null}
// Step 1: get_products — signal intent with filters
{
  "brief": "Coffee shop promotion in downtown Seattle",
  "filters": {
    "geo_proximity": [{
      "lat": 47.6062,
      "lng": -122.3321,
      "label": "Downtown Seattle",
      "radius": { "value": 5, "unit": "mi" }
    }],
    "keywords": [{ "keyword": "coffee" }]
  }
}
```

```json theme={null}
// Step 2: create_media_buy — apply precise constraints as overlays
{
  "targeting": {
    "geo_proximity": [{
      "lat": 47.6062,
      "lng": -122.3321,
      "label": "Downtown Seattle",
      "radius": { "value": 5, "unit": "mi" }
    }],
    "keyword_targets": [{ "keyword": "coffee", "match_type": "broad" }]
  }
}
```

Note that `keywords` (filter) becomes `keyword_targets` (overlay), and `match_type` becomes required.

## When to Use Targeting Overlays

Targeting overlays in `create_media_buy` and `update_media_buy` are **rare** and should only be used for:

### Geographic Restrictions

Use geo fields **only** for:

* **RCT testing**: Randomized control trials requiring specific geographic splits
* **Regulatory compliance**: Legal requirements for geographic restrictions
* **Product refinement**: When a product spans multiple regions and you need to restrict to a subset

**Inclusion fields** (restrict delivery to these locations):

* `geo_countries`: ISO 3166-1 alpha-2 country codes (e.g., `["US", "GB"]`)
* `geo_regions`: ISO 3166-2 subdivision codes (e.g., `["US-CA", "GB-SCT"]`)
* `geo_metros`: Structured metro areas with explicit system (e.g., `nielsen_dma`, `uk_itl2`) — not all publishers support metro-level targeting
* `geo_postal_areas`: Structured postal areas with explicit country and system (e.g., `US` / `zip`, `GB` / `outward`, `ZA` / `postal_code`) — not all publishers support postal-level targeting

**Exclusion fields** (exclude these locations from delivery):

* `geo_countries_exclude`: Same format as `geo_countries`
* `geo_regions_exclude`: Same format as `geo_regions`
* `geo_metros_exclude`: Same format as `geo_metros`
* `geo_postal_areas_exclude`: Same format as `geo_postal_areas`

**Note**: Inclusion and exclusion can be combined. Metro and postal targeting require specifying the classification system, enabling international support. Not all geographic granularities are supported by all publishers. Country and region are most widely supported.

### Age Restrictions (Compliance)

Use for **legal compliance** requirements:

* **Alcohol advertising**: Require verified 21+ in the US
* **Gambling/Gaming**: Require verified 18+ or 21+ depending on jurisdiction
* **Cannabis**: Require verified age per local regulations

```json theme={null}
{
  "$schema": "/schemas/core/targeting.json",
  "age_restriction": {
    "min": 21,
    "verification_required": true,
    "accepted_methods": ["facial_age_estimation", "id_document", "world_id"]
  }
}
```

**Verification methods** (defined in [`age-verification-method.json`](https://adcontextprotocol.org/schemas/v3/enums/age-verification-method.json), based on ISO/IEC 27566-1 age assurance standards):

* `facial_age_estimation` - AI-based age estimation (Yoti, etc.)
* `id_document` - Government ID scan
* `digital_id` - Verified digital identity credentials
* `credit_card` - Payment card age gate
* `world_id` - World ID orb verification

**Note**: "Inferred" age (guessing from behavior/profile) is **not** accepted for regulatory compliance. Platforms declare their supported verification methods in `get_adcp_capabilities`.

### Device Platform (Technical Compatibility)

Use for **technical requirements**:

* **App install campaigns**: iOS-only app requires `device_platform: ["ios"]`
* **CTV campaigns**: Target specific TV operating systems

```json theme={null}
{
  "$schema": "/schemas/core/targeting.json",
  "device_platform": ["ios", "android"]
}
```

**Available platforms** (defined in [`device-platform.json`](https://adcontextprotocol.org/schemas/v3/enums/device-platform.json), based on Sec-CH-UA-Platform standard extended for CTV):

* Browser: `ios`, `android`, `windows`, `macos`, `linux`, `chromeos`
* CTV: `tvos`, `tizen`, `webos`, `fire_os`, `roku_os`
* Other: `unknown`

### Device type (form factor)

Use for **performance optimization** targeting by hardware category rather than OS:

* **Mobile campaigns**: Target all mobile devices regardless of OS
* **CTV campaigns**: Target connected TVs across all platforms
* **Exclude form factors**: Skip CTV for app-install campaigns

```json theme={null}
{
  "$schema": "/schemas/core/targeting.json",
  "device_type": ["mobile", "tablet"]
}
```

**Exclusion** — use `device_type_exclude` to exclude specific form factors:

```json theme={null}
{
  "$schema": "/schemas/core/targeting.json",
  "device_type_exclude": ["dooh"]
}
```

**Available types** (defined in [`device-type.json`](https://adcontextprotocol.org/schemas/v3/enums/device-type.json)):

* `desktop`, `mobile`, `tablet`, `ctv`, `dooh`, `unknown`

**Device type vs device platform**: `device_type` targets form factors (mobile, desktop, CTV). `device_platform` targets operating systems (iOS, Android, tvOS). Use `device_type` for performance optimization; use `device_platform` for technical compatibility.

### Language (Localization)

Use for **localization requirements**:

* Creative is in a specific language
* Campaign targets specific language speakers

```json theme={null}
{
  "$schema": "/schemas/core/targeting.json",
  "language": ["es", "en"]
}
```

**Format**: ISO 639-1 two-letter language codes (e.g., `en`, `es`, `fr`, `de`, `zh`).

### Frequency Capping

Two frequency controls can be used independently or together:

**Cooldown between exposures** — `suppress` prevents back-to-back delivery:

```json theme={null}
{
  "$schema": "/schemas/core/targeting.json",
  "frequency_cap": {
    "suppress": { "interval": 60, "unit": "minutes" }
  }
}
```

**Impression cap per entity per window** — `max_impressions` + `per` + `window` limits total exposure:

```json theme={null}
{
  "$schema": "/schemas/core/targeting.json",
  "frequency_cap": {
    "max_impressions": 5,
    "per": "households",
    "window": { "interval": 7, "unit": "days" }
  }
}
```

Both can be combined. The `per` field uses the same entity types as `reach_unit` on reach optimization goals — use matching values when layering a hard cap on top of a reach campaign.

### Example Geographic Overlay (RCT Testing)

For RCT testing, exclusion targeting is often simpler than inclusion. Instead of listing hundreds of DMAs to include, exclude the holdout markets from a national campaign. When inclusion and exclusion are combined, exclusion fields subtract from the included set (e.g., "US minus these 3 DMAs"):

```json theme={null}
{
  "packages": [
    {
      "product_id": "national_video",
      "targeting_overlay": {
        "geo_countries": ["US"],
        "geo_metros_exclude": [
          { "system": "nielsen_dma", "values": ["501", "803", "602"] }
        ]
      }
    },
    {
      "product_id": "national_video",
      "targeting_overlay": {
        "geo_metros": [
          { "system": "nielsen_dma", "values": ["501", "803", "602"] }
        ]
      }
    }
  ]
}
```

Inclusion targeting works the same way for cases where you want to specify exact markets:

```json theme={null}
{
  "packages": [
    {
      "product_id": "national_video",
      "targeting_overlay": {
        "geo_metros": [
          { "system": "nielsen_dma", "values": ["501", "602", "803"] }
        ]
      }
    },
    {
      "product_id": "national_video",
      "targeting_overlay": {
        "geo_metros": [
          { "system": "nielsen_dma", "values": ["504", "505", "506"] }
        ]
      }
    }
  ]
}
```

## What NOT to Use Targeting Overlays For

**Express these in briefs instead:**

* **Demographic preferences** (age, gender, income) - "Target millennials" or "high-income households" in brief text
* **Device preferences** - "Mobile users" or "CTV viewers" in brief text (use `device_platform` overlay only for technical compatibility)
* **Content categories** - "Sports content" or "News sites" in brief text
* **General audience preferences** - "Auto intenders" or "Luxury shoppers" in brief text. If the buyer wants specific named signals applied to this package, use `signal_targeting_groups`.
* **Daypart preferences** - "Morning commute hours" or "prime time evening" in brief text

**Overlays vs Briefs:**

| Use Case                                                       | Overlay                                   | Brief                              |
| -------------------------------------------------------------- | ----------------------------------------- | ---------------------------------- |
| Age for compliance (alcohol, gambling)                         | ✅ `age_restriction`                       |                                    |
| Age for audience targeting                                     |                                           | ✅ "Target millennials"             |
| Device for app compatibility                                   | ✅ `device_platform`                       |                                    |
| Device for audience preference                                 |                                           | ✅ "Mobile users"                   |
| Language for creative localization                             | ✅ `language`                              |                                    |
| Language for audience preference                               |                                           | ✅ "Spanish-speaking audiences"     |
| First-party CRM audience (retargeting, suppression)            | ✅ `audience_include` / `audience_exclude` |                                    |
| Audience preference (interest targeting)                       |                                           | ✅ "Auto intenders" in brief        |
| Specific named signal offered by the seller                    | ✅ `signal_targeting_groups`               |                                    |
| Search/retail media keyword targeting                          | ✅ `keyword_targets` / `negative_keywords` |                                    |
| Broad thematic intent ("people searching for shoes")           |                                           | ✅ "Reach in-market shoe shoppers"  |
| Proximity to specific coordinates (within 2hr drive of a city) | ✅ `geo_proximity`                         |                                    |
| Nearby audience ("people near coffee shops")                   |                                           | ✅ "Reach people near coffee shops" |

**Why briefs work better for preferences:**

* Natural language captures intent more clearly
* Publishers know their inventory and can target effectively
* Avoids channel-specific complexity (DOOH has no browsers)
* Simpler API with fewer edge cases

## Available Targeting Overlay Parameters

Geographic targeting supports both inclusion (restrict to) and exclusion (exclude from) for all geo dimensions. Inclusion and exclusion fields can be combined — for example, include a country but exclude specific metros within it.

### Exclusion Semantics

**Exclusion without inclusion.** When an exclusion field is present without a corresponding inclusion field, the exclusion applies to the product's full geographic coverage. For example, if a product covers the entire US and the buyer specifies only `geo_metros_exclude`, the excluded metros are removed from the product's national footprint.

**Cross-level resolution.** Geographic levels form a hierarchy: country > region > metro > postal. Sellers SHOULD resolve hierarchical conflicts such that exclusion at a higher level takes precedence over inclusion at a more specific level. For example, `geo_countries_exclude: ["US"]` combined with `geo_regions: ["US-CA"]` SHOULD result in no US delivery — the country-level exclusion takes precedence.

**Same-value overlap.** Sellers SHOULD reject requests where the same value appears in both the inclusion and exclusion field at the same level (e.g., `geo_countries: ["US"]` with `geo_countries_exclude: ["US"]`) and return a descriptive error.

**Capabilities.** Sellers that declare geographic targeting support in `get_adcp_capabilities` SHOULD support both inclusion and exclusion at that level. If a seller only supports one direction, it MUST return a validation error for unsupported fields rather than silently ignoring them.

### geo\_countries

* **Description**: Restrict delivery to specific countries
* **Format**: ISO 3166-1 alpha-2 country codes
* **Examples**: `["US", "CA"]`, `["GB", "FR", "DE"]`
* **Use cases**: Regulatory compliance, country-specific campaigns

### geo\_countries\_exclude

* **Description**: Exclude specific countries from delivery
* **Format**: ISO 3166-1 alpha-2 country codes
* **Examples**: `["RU", "CN"]`
* **Use cases**: Regulatory compliance, sanctions

### geo\_regions

* **Description**: Restrict delivery to specific regions/states
* **Format**: ISO 3166-2 subdivision codes
* **Examples**: `["US-CA", "US-NY"]`, `["GB-SCT", "GB-ENG"]`
* **Use cases**: State-level compliance, regional testing

### geo\_regions\_exclude

* **Description**: Exclude specific regions/states from delivery
* **Format**: ISO 3166-2 subdivision codes
* **Examples**: `["US-CA"]`, `["CA-QC"]`
* **Use cases**: Regulatory compliance (e.g., cannabis restrictions by province), RCT holdout regions, regions where product is unavailable

### geo\_metros

* **Description**: Restrict delivery to specific metro areas
* **Format**: Array of objects, each with a `system` and `values`
* **Systems**: `nielsen_dma` (US), `uk_itl1` / `uk_itl2` (UK), `eurostat_nuts2` (EU), `custom`
* **Example**: `[{ "system": "nielsen_dma", "values": ["501", "803"] }]`
* **Use cases**: Local campaigns, metro-level RCT testing
* **Note**: Seller must declare supported systems in `get_adcp_capabilities`

### geo\_metros\_exclude

* **Description**: Exclude specific metro areas from delivery
* **Format**: Array of objects, each with a `system` and `values`
* **Example**: `[{ "system": "nielsen_dma", "values": ["602"] }]`
* **Use cases**: RCT holdout markets, competitive exclusion zones, markets where product is unavailable
* **Note**: Seller must declare supported systems in `get_adcp_capabilities`

### geo\_postal\_areas

* **Description**: Restrict delivery to specific postal areas
* **Format**: Array of objects, each with a `country`, `system`, and `values`
* **Systems**: country-local values such as `zip`, `zip_plus_four`, `outward`, `full`, `fsa`, `plz`, `code_postal`, `postcode`, `pin`, and `postal_code`
* **Example**: `[{ "country": "US", "system": "zip", "values": ["10001", "10002"] }]`
* **Use cases**: Hyper-local campaigns, postal-level restrictions
* **Note**: Seller must declare supported systems in `get_adcp_capabilities`. During the 3.x migration, deprecated country-fused systems such as `us_zip` remain accepted for compatibility and SDK backfill.

### geo\_postal\_areas\_exclude

* **Description**: Exclude specific postal areas from delivery
* **Format**: Array of objects, each with a `country`, `system`, and `values`
* **Example**: `[{ "country": "US", "system": "zip", "values": ["90210"] }]`
* **Use cases**: RCT holdout zip codes, restricted delivery areas
* **Note**: Seller must declare supported systems in `get_adcp_capabilities`; the deprecated legacy form remains accepted during the 3.x migration.

### axe\_include\_segment

* **Description**: Segment ID for inclusion targeting (legacy AXE field)
* **Format**: String segment identifier
* **Examples**: `"seg_auto_intenders_q1"`, `"audience_lapsed_buyers_30d"`
* **Use cases**: Dynamic audience targeting, first-party data activation
* **Note**: This field is from the legacy AXE integration. New implementations should use [TMP](/docs/trusted-match), where audience targeting is handled through the Identity Match path.

### axe\_exclude\_segment

* **Description**: Segment ID for exclusion targeting (legacy AXE field)
* **Format**: String segment identifier
* **Examples**: `"seg_existing_customers"`, `"audience_past_converters"`
* **Use cases**: Customer suppression, frequency management
* **Note**: This field is from the legacy AXE integration. New implementations should use [TMP](/docs/trusted-match), where suppression is handled through the Identity Match path.

### audience\_include

* **Description**: Restrict delivery to users who are members of these first-party CRM audiences. Only people on the uploaded list are eligible to see the ad.
* **Format**: Array of `audience_id` strings from [`sync_audiences`](/docs/media-buy/task-reference/sync_audiences)
* **Example**: `["lapsed_subscribers", "high_value_prospects"]`
* **Use cases**: Retargeting known users, loyalty campaigns targeting existing members, CRM-based inclusion on closed platforms (LinkedIn, Meta, TikTok, Google Ads)
* **Not for lookalike/expansion**: To find new users *similar to* an audience, describe the intent in your campaign brief ("reach people like our existing customers") — the seller handles expansion strategy
* **Prerequisite**: Audiences must be registered and `ready` via `sync_audiences` before use
* **Note**: Seller must declare support in `get_adcp_capabilities`

### audience\_exclude

* **Description**: Suppress delivery to users who are members of these first-party CRM audiences. Matched users are excluded regardless of other targeting.
* **Format**: Array of `audience_id` strings from [`sync_audiences`](/docs/media-buy/task-reference/sync_audiences)
* **Example**: `["existing_customers", "recent_purchasers"]`
* **Use cases**: Customer suppression in acquisition campaigns, excluding recent converters, suppressing opted-out users
* **Prerequisite**: Audiences must be registered and `ready` via `sync_audiences` before use
* **Note**: Seller must declare support in `get_adcp_capabilities`

### signal\_targeting\_groups

* **Description**: Basic Boolean grouping for seller-offered data signals. Use this for both simple include-only signal targeting and grouped include/exclude expressions such as `(A OR B) AND NOT (C OR D)`.
* **Discovery**: Wholesale products can set `signal_targeting_allowed: true` and omit inline `signal_targeting_options`; buyers then use `get_signals` as the selectable signal feed. Products return inline `signal_targeting_options` when they need product-specific pricing, activation handles, defaults, grouping hints, or a relevant subset for a brief/refine response.
* **Format**: Object with required top-level `operator: "all"` and a `groups` array. The top-level operator is always present, even though v1 only supports `all`.
* **Child groups**: Each child group has `operator: "any"` or `operator: "none"` and a `signals` array of package signal targeting objects. Each signal carries `signal_ref`, `value_type`, and the value fields, plus optional commercial and activation handles.
* **Legacy flat targeting**: `targeting_overlay.signal_targeting` remains schema-valid during the SignalRef migration window for older clients, but it is deprecated. New package-level signal selection uses `signal_targeting_groups` so sellers can apply include/exclude groups, product rules, and per-signal pricing consistently.
* **Semantics**: `any` means the user must match at least one signal in that group. `none` means the user must match none of the signals in that group. With top-level `all`, every child group must pass. For simple include-only targeting, send one child group with `operator: "any"`.
* **Resolution model**: `signal_targeting_rules.resolution_model` tells buyers how the seller applies selected signals to inventory. `direct_targeting` means selected signals behave like package targeting predicates. `seller_planned` means selected signals are inputs to seller-managed planning against product-specific inventory, timing, availability, reach, or pacing constraints; buyers should not attempt to decompose the selected audience into lower-level inventory or schedule decisions.
* **Selection groups**: When the product declares `signal_targeting_rules.selection_group_rules`, each child group MUST contain signals from exactly one `selection_group` and one targeting mode, and buyers MUST send at most one child group for each `(selection_group, targeting_mode)` pair. Sellers MUST reject duplicate, mixed, or collapsed child groups that combine distinct selection-group rules into the same `any` or `none` group. `selection_group` is a product-defined composability bucket, not a backend identity type: for example, a GAM-backed seller may expose both audience segments and key-values as ordinary `signal_ref` options, using one `selection_group` when they are freely OR-combinable and separate `selection_group`s when they must be trafficked as separate ANDed clauses.
* **Pricing**: Include `pricing_option_id` when the selected product's `signal_targeting_options` entry has `pricing_options`; omit only when the signal is bundled into the product price or has no incremental cost. Product-scoped pricing in `signal_targeting_options` is authoritative for that product. If the product option has no product-specific price, sellers MAY use the default pricing exposed in `get_signals`.
* **Signal reference**: Use `signal_ref: { "scope": "product", "signal_id": "..." }` for a product-local signal option. Use `signal_ref: { "scope": "data_provider", "data_provider_domain": "...", "signal_id": "..." }` for a signal defined in a data provider's published adagents.json `signals[]`. `signal_ref` identifies the signal definition; `signal_agent_segment_id` identifies a resolved segment or execution handle when the product option exposes one. Echo an exposed `signal_agent_segment_id` verbatim on the package entry, and prefer it over reconstructing identity from categorical values because providers can namespace handles to distinguish definitions such as real-time rain versus forecast high-precipitation. If the product option has `activation_status: "requires_activation"`, it MUST include `signal_agent_segment_id`; activate the signal first, then include `activation_key` if the seller requires it.
* **Provider-published signals**: For a provider-published signal, `signal_ref.data_provider_domain` identifies the upstream data provider and `signal_ref.signal_id` identifies the public signal definition. Buyers can verify the seller's right to offer the signal by checking the provider's `adagents.json` `authorized_agents` entry for the seller.
* **Product gating**: Sellers SHOULD reject a signal entry when the product does not advertise that signal inline or through `get_signals`, `signal_targeting_allowed` is false for package-level selection, the signal violates the product's `signal_targeting_rules`, the signal's `allowed_targeting_modes` does not allow the requested child group operator, the signal is not active for the account, or the requested value is outside the signal definition. `allowed_targeting_modes: ["include"]` maps to `any` groups; `["exclude"]` maps to `none` groups. Binary package signal entries use `value: true`; use the parent `none` group for exclusion, not `value: false`. Signal targeting limits are product-scoped, not declared in seller-wide `get_adcp_capabilities`, because products may be backed by different ad servers or platforms. If `selection_mode` is `fixed`, buyers SHOULD omit edits to `signal_targeting_groups`; sellers apply the fixed/default selections and MUST echo them on the resulting package state.
* **Updates**: Because `targeting_overlay` is shared by `create_media_buy` and `update_media_buy`, sellers MAY reject mid-flight signal group changes with `REQUOTE_REQUIRED` when the selected signal, group expression, or `pricing_option_id` changes the priced envelope.
* **Not for first-party audiences**: Use `audience_include` / `audience_exclude` for buyer-uploaded audiences from `sync_audiences`.

The backend targeting primitive is intentionally hidden behind `signal_ref`. Buyers should not need a separate identity system for "audience segment" versus "key-value"; the selected product's `signal_targeting_rules` describe whether those options can be composed together. If a product exposes both a `gam_audience_segments` group and a `gam_key_values` group with `targeting_mode: "include"`, the buyer composes two `any` child groups under the top-level `all`, not one collapsed mixed group.

For products where inventory and audience planning are inseparable, such as linear broadcast schedules, sellers use `resolution_model: "seller_planned"`. Mandatory audience selection still lives in `selection_mode: "required"` or a required `selection_group_rules` entry; cross-product audience consistency comes from a shared `scope: "data_provider"` signal definition, even when the seller is also the data provider.

```json theme={null}
{
  "packages": [
    {
      "product_id": "retail_video_premium",
      "pricing_option_id": "media_cpm_usd",
      "budget": 25000,
      "targeting_overlay": {
        "signal_targeting_groups": {
          "operator": "all",
          "groups": [
            {
              "operator": "any",
              "signals": [
                {
                  "signal_ref": { "scope": "product", "signal_id": "high_intent_shoppers" },
                  "value_type": "binary",
                  "value": true
                },
                {
                  "signal_ref": { "scope": "product", "signal_id": "loyalty_members" },
                  "value_type": "binary",
                  "value": true
                }
              ]
            },
            {
              "operator": "none",
              "signals": [
                {
                  "signal_ref": { "scope": "product", "signal_id": "recent_purchasers" },
                  "value_type": "binary",
                  "value": true
                }
              ]
            }
          ]
        }
      }
    }
  ]
}
```

### frequency\_cap

* **Description**: Limit ad exposure frequency per entity. Two optional controls can be used independently or together.
* **Cooldown control**: `suppress` — minimum duration between consecutive exposures to the same entity. `suppress_minutes` (number) is also accepted for backwards compatibility.
* **Impression cap**: `max_impressions` + `per` + `window` — total impression ceiling per entity per time window. All three fields are required together.
* **Use cases**: User experience management, ad fatigue prevention, complementing reach optimization goals with a hard ceiling
* **Examples**: `{"suppress": {"interval": 60, "unit": "minutes"}}`, `{"max_impressions": 5, "per": "households", "window": {"interval": 7, "unit": "days"}}`

### age\_restriction

* **Description**: Require minimum age for compliance
* **Format**: Object with `min` (required), `verification_required`, and `accepted_methods`
* **Examples**: `{"min": 21, "verification_required": true}`, `{"min": 18, "accepted_methods": ["world_id"]}`
* **Use cases**: Alcohol (21+), gambling (18+), cannabis regulations
* **Note**: Platforms declare supported verification methods in `get_adcp_capabilities`

### device\_platform

* **Description**: Restrict to specific operating system platforms
* **Format**: Array of platform identifiers from Sec-CH-UA-Platform standard
* **Examples**: `["ios"]`, `["ios", "android"]`, `["tvos", "fire_os"]`
* **Use cases**: App install campaigns (iOS-only app), CTV-specific campaigns
* **Values**: `ios`, `android`, `windows`, `macos`, `linux`, `chromeos`, `tvos`, `tizen`, `webos`, `fire_os`, `roku_os`

### device\_type

* **Description**: Restrict to specific device form factors
* **Format**: Array of device type identifiers
* **Examples**: `["mobile"]`, `["mobile", "tablet"]`, `["ctv"]`
* **Use cases**: Mobile-only promotions, CTV campaigns targeting all TV platforms, excluding DOOH from certain campaigns
* **Values**: `desktop`, `mobile`, `tablet`, `ctv`, `dooh`, `unknown`
* **Note**: Seller must declare `device_type: true` in `get_adcp_capabilities` targeting

### device\_type\_exclude

* **Description**: Exclude specific device form factors from delivery
* **Format**: Array of device type identifiers
* **Examples**: `["dooh"]`, `["ctv", "dooh"]`
* **Use cases**: Exclude CTV for app-install campaigns, exclude DOOH for direct-response campaigns
* **Note**: Supported when seller declares `device_type: true` in `get_adcp_capabilities`

### language

* **Description**: Restrict to users with specific language preferences
* **Format**: Array of ISO 639-1 two-letter language codes
* **Examples**: `["en"]`, `["es", "en"]`, `["zh", "ja", "ko"]`
* **Use cases**: Localized creative, language-specific campaigns

### keyword\_targets

* **Description**: Target specific keywords for search and retail media platforms. Restricts delivery to queries matching the specified keywords.
* **Format**: Array of objects with `keyword`, `match_type` (`broad`, `phrase`, or `exact`), and optional `bid_price`
* **Identity**: Each keyword is identified by the tuple `(keyword, match_type)`. The same keyword string with different match types are distinct targets. Duplicate pairs in a single request SHOULD be rejected by sellers.
* **Match types**:
  * `broad` — matches related and synonym queries
  * `phrase` — matches queries containing the keyword phrase in order
  * `exact` — matches the keyword query only
* **Per-keyword bid**: The optional `bid_price` overrides the package-level `bid_price` for that keyword. Inherits the `max_bid` interpretation from the pricing option: when `max_bid` is true, this is the keyword's bid ceiling; when false, this is the exact bid. If omitted, the package `bid_price` applies.
* **Use cases**: Search campaigns, retail media sponsored products, keyword-based intent targeting
* **Note**: Seller must declare `execution.targeting.keyword_targets` in `get_adcp_capabilities` with the `supported_match_types` it accepts. Only use match types the seller declares — sellers must reject unsupported match types. Use `keyword_targets_add` and `keyword_targets_remove` in `update_media_buy` to add or update keywords incrementally after launch. Keyword-level delivery data (`by_keyword` in reporting) requires `reporting_capabilities.supports_keyword_breakdown: true` on the product — these are independent capabilities. `by_keyword` is keyword-grain (one row per keyword+match\_type pair), not search-term-grain.

```json theme={null}
{
  "$schema": "/schemas/core/targeting.json",
  "keyword_targets": [
    { "keyword": "running shoes", "match_type": "broad", "bid_price": 0.45 },
    { "keyword": "trail running shoes womens", "match_type": "phrase", "bid_price": 0.85 },
    { "keyword": "acme cloudrunner 5", "match_type": "exact", "bid_price": 1.20 }
  ]
}
```

### negative\_keywords

* **Description**: Exclude specific keywords from delivery. Queries matching these keywords will not trigger the ad.
* **Format**: Array of objects with `keyword` and `match_type` (`broad`, `phrase`, or `exact`)
* **Use cases**: Prevent wasteful spend on irrelevant queries, exclude competitor brand terms
* **Note**: Seller must declare `execution.targeting.negative_keywords` in `get_adcp_capabilities` with the `supported_match_types` it accepts. Use `negative_keywords_add` and `negative_keywords_remove` in `update_media_buy` to add/remove negatives incrementally after launch.

```json theme={null}
{
  "$schema": "/schemas/core/targeting.json",
  "negative_keywords": [
    { "keyword": "free", "match_type": "broad" },
    { "keyword": "used running shoes", "match_type": "phrase" }
  ]
}
```

### store\_catchments

* **Description**: Target users within store catchment areas from a synced store catalog
* **Format**: Array of objects, each referencing a store-type catalog synced via `sync_catalogs`
* **Required fields**: `catalog_id`
* **Optional fields**: `store_ids` (narrow to specific stores), `catchment_ids` (narrow to specific zones like `"walk"` or `"drive"`)
* **Use cases**: Drive-to-store campaigns, local inventory ads, proximity targeting

```json theme={null}
{
  "targeting_overlay": {
    "store_catchments": [
      {
        "catalog_id": "retail-locations",
        "store_ids": ["store_nyc_001", "store_nyc_002"],
        "catchment_ids": ["drive"]
      }
    ]
  }
}
```

When `store_ids` is omitted, all stores in the catalog are targeted. When `catchment_ids` is omitted, all catchment zones are targeted. The seller must declare support for store catchment targeting in `get_adcp_capabilities`.

### geo\_proximity

* **Description**: Target users within travel time, distance, or a custom boundary around arbitrary geographic points
* **Format**: Array of objects, each with exactly one method: `travel_time` + `transport_mode`, `radius`, or `geometry`
* **Required fields**: `lat` + `lng` (for travel\_time and radius methods), or `geometry` (for pre-computed boundaries)
* **Optional fields**: `label` (human-readable name for the entry)
* **Use cases**: Tourism campaigns (within 2hr drive of a city), event targeting (near a venue), airport catchment areas
* **Semantics**: Multiple entries use OR — a user within range of any listed point is eligible. Intersects with other geo targeting fields (e.g., combining with `geo_countries` restricts proximity to those countries)

Travel time (isochrone) example:

```json theme={null}
{
  "targeting_overlay": {
    "geo_proximity": [
      {
        "lat": 51.2277,
        "lng": 6.7735,
        "label": "Düsseldorf",
        "travel_time": { "value": 2, "unit": "hr" },
        "transport_mode": "driving"
      }
    ]
  }
}
```

Radius-based example:

```json theme={null}
{
  "targeting_overlay": {
    "geo_proximity": [
      {
        "lat": 51.4700,
        "lng": -0.4543,
        "label": "Heathrow Airport",
        "radius": { "value": 30, "unit": "km" }
      }
    ]
  }
}
```

Pre-computed geometry example (buyer provides the polygon):

```json theme={null}
{
  "targeting_overlay": {
    "geo_proximity": [
      {
        "label": "2hr drive from Düsseldorf",
        "geometry": {
          "type": "Polygon",
          "coordinates": [[[5.87, 50.35], [8.23, 50.35], [8.23, 52.10], [5.87, 52.10], [5.87, 50.35]]]
        }
      }
    ]
  }
}
```

For travel time entries, the platform resolves the isochrone to a geographic boundary based on actual transportation networks. Transport modes: `driving`, `walking`, `cycling`, `public_transport`. The `geometry` method allows buyers who have already computed isochrones (via TravelTime, Mapbox, etc.) to pass the polygon directly — this also enables sellers without routing engines to participate.

For campaigns targeting 10+ locations, consider using `store_catchments` with a location catalog instead, which supports ongoing management and per-location reporting. `geo_proximity` does not have an exclusion variant — this is by design, as excluding "everyone near a point" is rarely a meaningful targeting constraint.

Sellers SHOULD enforce minimum area thresholds consistent with their privacy policies and applicable regulations. The seller must declare `geo_proximity` support in `get_adcp_capabilities`, specifying which methods (`radius`, `travel_time`, `geometry`) and transport modes are supported.

Validated examples:

```json theme={null}
{
  "$schema": "/schemas/core/targeting.json",
  "geo_proximity": [
    {
      "lat": 51.2277,
      "lng": 6.7735,
      "label": "Düsseldorf",
      "travel_time": { "value": 2, "unit": "hr" },
      "transport_mode": "driving"
    }
  ]
}
```

```json theme={null}
{
  "$schema": "/schemas/core/targeting.json",
  "geo_proximity": [
    {
      "lat": 51.4700,
      "lng": -0.4543,
      "label": "Heathrow Airport",
      "radius": { "value": 30, "unit": "km" }
    }
  ]
}
```

```json theme={null}
{
  "$schema": "/schemas/core/targeting.json",
  "geo_proximity": [
    {
      "label": "2hr drive from Düsseldorf",
      "geometry": {
        "type": "Polygon",
        "coordinates": [[[5.87, 50.35], [8.23, 50.35], [8.23, 52.10], [5.87, 52.10], [5.87, 50.35]]]
      }
    }
  ]
}
```

## Benefits for Different Stakeholders

### For Buyers

* **Simpler planning**: Describe audience needs naturally
* **Transparent pricing**: All costs included upfront
* **Reduced complexity**: No targeting configuration required
* **Better outcomes**: Publisher expertise optimizes delivery

### For Publishers

* **Pricing control**: Bundle targeting into product pricing
* **Expertise utilization**: Apply knowledge of inventory and audiences
* **Simplified integration**: Fewer technical targeting parameters
* **Market positioning**: Differentiate through targeting capabilities

### For Platforms

* **Reduced conflicts**: Single targeting source eliminates layering issues
* **Cleaner implementation**: Less complex targeting logic required
* **Better performance**: Optimized for publisher inventory characteristics

## Real-Time Targeting Signals

Orchestrators can provide **real-time targeting signals** to publishers for dynamic, high-cardinality targeting beyond what can be expressed in static overlays. These signals enable:

* **Brand safety** - Real-time content filtering and adjacency controls
* **Brand suitability** - Contextual alignment with brand values
* **Audience targeting** - Dynamic audience segments updated in real-time
* **Contextual targeting** - Page-level or moment-level targeting decisions

Real-time signals are provided through the [AdCP Signals Protocol](/docs/signals/overview), which allows orchestrators to supply targeting data at impression time.

### Key Differences: Signals vs Overlays

* Signals are **evaluated at impression time**, not campaign setup
* Signals support **higher cardinality** (thousands of values vs. dozens)
* Signals can be **updated continuously** without modifying the media buy
* Signals enable **sophisticated contextual targeting** that briefs cannot express

### When to Use Real-Time Signals

✅ **Use Real-Time Signals For:**

* Brand safety filtering (block unsafe content)
* Brand suitability scoring (prefer suitable contexts)
* Dynamic audience targeting (real-time segment membership)
* Contextual targeting (page-level or moment-level decisions)
* High-cardinality targeting (thousands of values)
* Targeting that changes during campaign flight

## Managing keywords after launch

Both keyword targets and negative keywords support incremental operations in `update_media_buy`, avoiding the need to replace the full `targeting_overlay`:

* **`keyword_targets_add`** — upserts by `(keyword, match_type)` identity. Adds new keywords or updates `bid_price` on existing ones.
* **`keyword_targets_remove`** — removes matching `(keyword, match_type)` pairs.
* **`negative_keywords_add`** — appends negatives. Duplicates are no-ops.
* **`negative_keywords_remove`** — removes matching pairs. Missing entries are no-ops.

```json theme={null}
{
  "packages": [
    {
      "package_id": "pkg_sponsored_search_001",
      "keyword_targets_add": [
        { "keyword": "trail running shoes", "match_type": "phrase", "bid_price": 0.95 }
      ],
      "keyword_targets_remove": [
        { "keyword": "running shoes", "match_type": "broad" }
      ],
      "negative_keywords_add": [
        { "keyword": "diy", "match_type": "broad" },
        { "keyword": "how to make running shoes", "match_type": "phrase" }
      ]
    }
  ]
}
```

Sellers SHOULD return a validation error if `targeting_overlay.keyword_targets` is present in the same request as `keyword_targets_add` or `keyword_targets_remove` (and likewise for negative keywords). The incremental operations and the full overlay replacement are mutually exclusive within a single update.

To remove all keyword targeting while preserving other overlay fields, send the full `targeting_overlay` without the `keyword_targets` field.

## Implementation Requirements

### Publishers MUST:

1. **Support Geographic Targeting**: Handle geographic inclusion and exclusion parameters (`geo_countries`, `geo_countries_exclude`, `geo_regions`, `geo_regions_exclude`, `geo_metros`, `geo_metros_exclude`, `geo_postal_areas`, `geo_postal_areas_exclude`) to the extent your platform supports them. Declare supported metro and postal systems in `get_adcp_capabilities`
2. **Interpret Briefs**: Use briefs to determine appropriate audience and content targeting
3. **Validate Targeting**: Reject media buys with targeting that cannot be supported
4. **Document Limitations**: Clearly communicate any geographic targeting limitations in product descriptions

### Buyers SHOULD:

1. **Use Briefs First**: Express most targeting needs in natural language briefs
2. **Minimize Overlays**: Only use technical targeting for geographic restrictions or RCT testing
3. **Trust Publishers**: Let publishers apply their inventory knowledge to brief interpretation
4. **Validate Early**: Check product capabilities before applying technical targeting

## Best Practices

1. **Default to briefs** - Start with natural language descriptions
2. **Write Clear Briefs**: Be specific about audience and context requirements
3. **Trust Publisher Expertise**: Publishers know their inventory capabilities best
4. **Use signals for dynamic targeting** - Real-time signals handle complex, high-cardinality targeting better than overlays
5. **Minimize Technical Overlays**: Use only for geographic restrictions or compliance
6. **Validate Audience Fit**: Ensure product descriptions match campaign goals
7. **Inclusive pricing** - Expect targeting costs to be built into product rates

## Future Evolution

* **Enhanced Brief Processing**: More sophisticated natural language understanding
* **Audience Discovery**: Better tools for exploring available audiences
* **Deeper Signal Integration**: More sophisticated real-time targeting capabilities
* **Performance Optimization**: AI-driven audience refinement based on campaign results

## Related Documentation

* **[Trusted Match Protocol (TMP)](/docs/trusted-match)** - Real-time execution layer for impression-time targeting, frequency capping, and brand suitability
* **[Signals Protocol](/docs/signals/overview)** - Real-time targeting signals for brand suitability and contextual targeting
* **[Product Discovery](/docs/media-buy/product-discovery/)** - How briefs lead to targeted product recommendations
* **[Example Briefs](/docs/media-buy/product-discovery/example-briefs)** - Real examples of effective targeting briefs
* **[Policy Compliance](/docs/media-buy/media-buys/policy-compliance)** - Automated compliance checking and enforcement
