Skip to main content
Conversion tracking in AdCP connects advertising spend to business outcomes. Two tasks handle the lifecycle: sync_event_sources configures where events come from, and log_event sends the events themselves. Event data feeds into delivery reporting (conversions, ROAS, cost per acquisition) and enables optimization goals on media buy packages.

The flow

This shows the recommended order. In practice, media buys can be created before events are flowing — the seller begins optimizing once sufficient event history accumulates.

Event source

An event source represents a channel through which conversion events are collected — a website pixel, mobile SDK, server-to-server integration, or CRM import. Configure event sources with sync_event_sources. You provide an event_source_id, optional name, event_types, and allowed_domains. The response includes additional fields for each source:

Buyer-managed vs seller-managed

Buyer-managed sources are ones you configure via sync_event_sources. You control the event types, domains, and lifecycle. Seller-managed sources are always-on and appear in the response with managed_by: "seller". These are common in commerce media where the retailer provides built-in attribution (e.g., purchase tracking on their own platform). Products with conversion_tracking.platform_managed: true indicate the seller provides these sources. To discover all sources on an account (including seller-managed), call sync_event_sources without an event_sources array:

Event

An event represents a user action — a purchase, lead submission, page view, app install, or any of the standard event types. Send events with log_event:
Events are deduplicated by event_id + event_type + event_source_id. Sending the same event multiple times is safe.

User match

User identifiers enable the seller to attribute conversions to ad impressions. Provide the strongest identifiers available — more identifiers means higher match rates.
At least one identifier is required. The hierarchy from strongest to weakest: Hashing: Normalize before hashing — emails to lowercase with whitespace trimmed, phone numbers to E.164 format (e.g., +12065551234). Hash with SHA-256, output as 64-character lowercase hex. Send multiple identifier types when available. The seller uses the best available match.

Custom data

Event-specific data for attribution and reporting. For purchase events, always include value and currency to enable ROAS reporting.

Event types

Standard marketing event types, aligned with IAB ECAPI:

Action sources

Where the conversion event originated:

Optimization goals

Optimization goals tell the seller what to optimize delivery toward. Set them on a package in create_media_buy. A package accepts an array of goals — each with an optional priority (1 = highest). Products declare max_optimization_goals when they limit how many goals a package can carry (most social platforms accept only 1). Schema: /schemas/v3/core/optimization-goal.json There are two kinds of goals, discriminated by kind:
  • kind: "metric" — Optimize for a seller-tracked delivery metric (clicks, views, engagements, etc.). No event source or conversion tracking setup required. The product declares which metrics it supports in metric_optimization.
  • kind: "event" — Optimize for advertiser-tracked conversion events. Requires event sources registered via sync_event_sources. The product declares support in conversion_tracking.

kind: event

Optimize for advertiser-tracked conversion events. The event_sources array defines which source-type pairs feed this goal. When the seller supports multi_source_event_dedup (declared in get_adcp_capabilities), they deduplicate by event_id across all entries — the same business event reported by multiple sources counts once, using value_field and value_factor from the first matching entry. When multi_source_event_dedup is absent or false, buyers should use a single event source per goal. Cost per conversion (single source):
Return on ad spend (multiple sources with refunds):
For per_ad_spend targets, each event source entry specifies a value_field (which field on custom_data carries the monetary value) and an optional value_factor (multiplier, defaults to 1). The seller computes sum(value_field * value_factor) / spend across all deduplicated events. Maximize conversion value (no specific ROAS target):
A maximize_value target steers spend toward higher-value conversions without committing to a specific return ratio. Requires value_field on at least one event source entry.

kind: metric

Optimize for a seller-tracked delivery metric. No event source needed — the seller tracks these natively. Products declare which metrics they support in metric_optimization.supported_metrics. Maximize clicks (no target — seller optimizes for volume within budget):
Cost per click:
Minimum click-through rate:
Minimum attention time:
Maximize engagements (social reactions, comments, shares, story opens, overlay taps):
Completed views with duration threshold (6-second views on TikTok):
Metrics:

Target kinds

All target kinds across both goal types:

Choosing a strategy

Multiple goals and priority

A package can have multiple goals. Priority controls which the seller treats as primary. A common pattern is to use metric goals as proxy signals when event data is sparse:
The seller focuses on the priority: 1 goal (installs at $10 cost per, deduplicated across SDK and MMP) and uses clicks as a proxy signal until install data accumulates.

Pricing model vs. optimization goal

The pricing model (CPC, CPM, CPA, etc.) determines what the buyer pays. The optimization goal determines how the seller allocates impressions. These are independent — a package can use CPM pricing while optimizing toward a CPA target, or use CPA pricing while optimizing for ROAS. See Pricing Models for details on billing.

Reach and frequency

Reach-based optimization uses metric: "reach" with two additional fields:
  • reach_unit (required): The unit of measurement — must be a value declared in the product’s metric_optimization.supported_reach_units (e.g., households, individuals).
  • target_frequency (optional): Frequency band that guides optimization. The seller treats impressions toward unreached entities as higher-value and impressions toward already-saturated entities as lower-value. Includes min, max, and window (e.g., "7d", "campaign"). When omitted, the seller maximizes unique reach.
For GRP-based buys, use CPP pricing. For hard frequency limits independent of optimization, use frequency_cap on the package. Reach and frequency metrics are available in delivery reporting via get_media_buy_delivery.

Prerequisites

For metric goals (kind: "metric"):
  1. Check product support — The product must declare metric_optimization with the desired metric in supported_metrics. No event source or conversion tracking setup is required.
  2. Check target support — If setting a target, verify the target kind is listed in metric_optimization.supported_targets.
  3. Check view durations — If using completed_views with view_duration_seconds, verify the value is listed in metric_optimization.supported_view_durations.
For event goals (kind: "event"):
  1. Configure event sources — Call sync_event_sources to set up the event sources referenced in event_sources.
  2. Check product support — The product must declare conversion_tracking with the desired target kind in supported_targets.
  3. Check dedup support — If using multiple event sources per goal, verify the seller supports multi_source_event_dedup in get_adcp_capabilities. When unsupported, use a single event source per goal.
  4. Send events — Use log_event to send conversion data. The seller needs event history to optimize effectively.

Attribution windows

Attribution windows control how far back the seller looks to credit an ad impression for a conversion. Common options: Values must match an option in the seller’s conversion_tracking.attribution_windows capability. When omitted, the seller applies their default window.

Connection to delivery reporting

Once event sources are configured and events are flowing, conversion metrics appear in get_media_buy_delivery responses:
  • conversions — Post-click or post-view conversions attributed to the campaign
  • conversion_value — Monetary value of attributed conversions
  • roas — Return on ad spend (conversion_value / spend)
  • cost_per_acquisition — Cost per conversion (spend / conversions)
These metrics are reported per-package when the package has optimization_goals set. Sellers that support by_action_source breakdowns can show conversions split by source (website, app, in_store, etc.).

Catalog-item attribution

For catalog-driven packages, conversion events carry content_ids that identify which catalog items were involved. The catalog’s content_id_type declares what identifier type to expect (sku, gtin, job_id, etc.). Attribution is broad by design: a user might click on one item (job A) but convert on another (apply to job B). The event fires with the actual content_id of the conversion, not the clicked item. Per-item click-to-conversion path analysis is a platform optimization concern, not a protocol concern. The by_catalog_item breakdown in get_media_buy_delivery shows per-item metrics (impressions, spend, clicks, conversions).