Skip to main content
データドリブンな監視と最適化による継続的改善を実現します。AdCP はパフォーマンス追跡・配信分析・成果向上を支援する包括的なレポーティング/最適化機能を提供します。 AdCP のレポーティングはキャンペーン設定に用いる Targeting と整合しており、ライフサイクル全体で一貫した分析が可能です。ターゲットした内容と同じ粒度でレポートできます。 パフォーマンスデータは AdCP の Accountability & Trust Framework に反映され、パブリッシャーは安定した配信でレピュテーションを築き、バイヤーはデータに基づいて配分判断ができます。

主な最適化タスク

デリバリーレポート

get_media_buy_delivery でインプレッション、消化額、クリック、コンバージョンなど全パッケージのパフォーマンスデータを取得します。 あるいはメディアバイ作成時に Webhook ベースのレポーティング を設定し、定期的な自動通知を受け取ります。

キャンペーン更新

パフォーマンスインサイトに基づき、update_media_buy で設定・予算・構成を更新します。

最適化ワークフロー

一般的な最適化サイクル:
  1. 配信を監視: 目標に対するパフォーマンスを追跡
  2. パフォーマンス分析: 最適化の機会を特定
  3. 調整を実施: 予算・ターゲティング・クリエイティブ割り当てを更新
  4. 変化を追跡: 最適化の影響をモニタリング
  5. 反復: 定期的な分析で継続的改善

パフォーマンス監視

リアルタイム指標

配信中のキャンペーンを追跡します。
  • 目標に対する インプレッション配信状況
  • 予算に対する 消化ペース
  • CTR とエンゲージメント
  • 事業成果に紐づく コンバージョン追跡

ヒストリカル分析

時間軸でパフォーマンス傾向を把握します。
  • 主要指標の 日次/時間別の内訳
  • 期間をまたいだ パフォーマンス比較
  • 最適化機会を見つける トレンド識別

アラート/通知

重要なキャンペーンイベントを把握します。
  • ペース異常に対する 配信アラート
  • 大きな変化に対する パフォーマンス通知
  • 上限到達前の 予算警告

配信方法

パブリッシャーは Webhook 通知またはオフラインファイル配信でレポートデータをバイヤーへプッシュできます。これによりポーリングを不要にし、タイムリーなインサイトを提供します。 Webhook Push(リアルタイム) - バイヤーのエンドポイントへ HTTP POST
  • 適合: 多くのバイヤー・セラー関係
  • レイテンシ: ほぼリアルタイム(秒〜分)
  • コスト: 標準的な Webhook 基盤
オフラインファイル配信(バッチ) - クラウドストレージバケットへのプッシュ
  • 適合: 高ボリュームの大口バイヤー/セラー
  • レイテンシ: 定期バッチ(毎時/日次)
  • コスト: 大幅に低い(0.010.10/GB0.01-0.10/GB 対 0.50-2.00/100 万 Webhook)
  • フォーマット: JSON Lines, CSV, Parquet
  • ストレージ: S3, GCS, Azure Blob Storage

Webhook ベースのレポーティング

Webhook 設定

メディアバイ作成時に reporting_webhook パラメーターでレポート Webhook を設定します。
{
  "buyer_ref": "campaign_2024",
  "packages": [...],
  "reporting_webhook": {
    "url": "https://buyer.example.com/webhooks/reporting",
    "authentication": {
      "schemes": ["Bearer"],
      "credentials": "secret_token_min_32_chars"
    },
    "reporting_frequency": "daily"
  }
}
本番推奨: HMAC 署名付き
{
  "buyer_ref": "campaign_2024",
  "packages": [...],
  "reporting_webhook": {
    "url": "https://buyer.example.com/webhooks/reporting",
    "authentication": {
      "schemes": ["HMAC-SHA256"],
      "credentials": "shared_secret_min_32_chars"
    },
    "reporting_frequency": "daily"
  }
}
セキュリティ必須:
  • authentication 設定は必須(32 文字以上)
  • Bearer トークン: シンプルで開発向き(Authorization ヘッダー)
  • HMAC-SHA256: 本番推奨。リプレイ攻撃を防止(署名ヘッダー)
  • 資格情報はオンボーディング時に帯域外で交換
  • 実装詳細は Security を参照

サポートされる頻度

パブリッシャーはプロダクトの reporting_capabilities でサポートする頻度を宣言します。すべてをサポートする必要はなく、運用に適した頻度を選択します。
  • hourly: キャンペーン期間中、毎時間通知(任意。コスト/複雑性を考慮)
  • daily: 1 日 1 回通知(最も一般的、フェーズ1に推奨)
  • monthly: 月 1 回通知(タイムゾーンはパブリッシャー指定)
コスト考慮: 時間単位 Webhook は日次の 24 倍のトラフィックを発生。大規模なバイヤー/セラーではコスト効率のためオフラインレポートを好む場合があります。

提供可能な指標

パブリッシャーは reporting_capabilities.available_metrics で提供できる指標を宣言します。一般的な指標例:
  • impressions: 広告表示(常に提供)
  • spend: 消化額(常に提供)
  • clicks: クリック数
  • ctr: クリック率
  • video_completions: 動画完了数
  • completion_rate: 動画完了率
  • conversions: クリック後/視聴後コンバージョン
  • viewability: ビューアブル率
  • engagement_rate: プラットフォーム固有のエンゲージメント指標
バイヤーは requested_metrics で必要な指標のみを要求し、ペイロードを抑えて KPI に集中できます。

パブリッシャーのコミットメント

レポート Webhook を設定した場合、パブリッシャーは以下を送信します。 (キャンペーン期間 / reporting_frequency) + 1 回の通知
  • キャンペーン期間中、頻度ごとに 1 回
  • キャンペーン完了時に最終通知を 1 回
  • 想定遅延時間を超える場合は "delayed" 通知を送信

Webhook ペイロード

レポート Webhook は get_media_buy_delivery と同じペイロードにメタデータを加えます。
{
  "notification_type": "scheduled",
  "sequence_number": 5,
  "next_expected_at": "2024-02-06T08:00:00Z",
  "reporting_period": {
    "start": "2024-02-05T00:00:00Z",
    "end": "2024-02-05T23:59:59Z"
  },
  "currency": "USD",
  "media_buy_deliveries": [
    {
      "media_buy_id": "mb_001",
      "buyer_ref": "campaign_a",
      "status": "active",
      "totals": {
        "impressions": 125000,
        "spend": 5625.00,
        "clicks": 250,
        "ctr": 0.002
      },
      "by_package": [...]
    }
  ]
}
Fields:
  • notification_type: "scheduled"(定期)、"final"(完了)、"delayed"(データ未準備)
  • sequence_number: 連番(1 起算)
  • next_expected_at: 次回通知の ISO 8601 時刻(最終通知では省略)
  • media_buy_deliveries: メディアバイ配信データの配列(パブリッシャーが複数メディアバイをまとめて返す場合あり)

タイムゾーンの扱い

レポーティングはすべて UTC を使用する必要があります。 DST の複雑性を排除し、照合を簡素化し、一貫した 24 時間単位を保証します。
{
  "reporting_capabilities": {
    "timezone": "UTC",
    "available_reporting_frequencies": ["daily"]
  }
}
レポート期間:
  • 日次: 00:00:00Z 〜 23:59:59Z(常に 24 時間)
  • 時次: 時刻 00 分 00 秒〜59 分 59 秒(常に 1 時間)
  • 月次: 月初〜月末
Example webhook payload:
{
  "reporting_period": {
    "start": "2024-02-05T00:00:00Z",
    "end": "2024-02-05T23:59:59Z"
  }
}

遅延レポーティング

プロダクトの expected_delay_minutes 内にレポートデータが用意できない場合、パブリッシャーは notification_type: "delayed" で通知します。
{
  "notification_type": "delayed",
  "sequence_number": 3,
  "next_expected_at": "2024-02-06T10:00:00Z",
  "message": "Reporting data delayed due to upstream processing. Expected availability in 2 hours."
}
これにより、通知が欠落したと誤解されるのを防ぎます。

Webhook の集約

複数のメディアバイが以下を共有する場合、呼び出し数削減のため Webhook を集約すべきです。
  • 同一 Webhook URL
  • 同一のレポート頻度
  • 同一のレポート期間
: バイヤーが同一エンドポイントで日次レポートを受けるアクティブキャンペーンを 100 件持つ場合
  • 集約なし: 1 日 100 件の Webhook(非効率)
  • 集約あり: 1 日 1 件の Webhook に 100 キャンペーンをまとめる(最適)
media_buy_deliveries 配列には Webhook 1 件あたり 1〜N のメディアバイが含まれます。バイヤーは配列を反復して各キャンペーンを処理してください。 Aggregated webhook example:
{
  "notification_type": "scheduled",
  "reporting_period": {
    "start": "2024-02-05T00:00:00Z",
    "end": "2024-02-05T23:59:59Z"
  },
  "currency": "USD",
  "media_buy_deliveries": [
    { "media_buy_id": "mb_001", "totals": { "impressions": 50000, "spend": 1750 }, ... },
    { "media_buy_id": "mb_002", "totals": { "impressions": 48500, "spend": 1695 }, ... },
    // ... 98 more media buys
  ]
}
バイヤーは配列を反復し、各メディアバイを個別に処理します。集計値が必要な場合は各メディアバイの合計から算出してください。

部分的な失敗の扱い

複数メディアバイを 1 つの Webhook にまとめる際、キャンペーンごとにデータ可否が異なる場合があります。 方針: ステータス付きベストエフォート配信 パブリッシャーは利用可能なデータをすべて含めた集約 Webhook を送り、ステータスで可否を示すべきです。
{
  "notification_type": "scheduled",
  "sequence_number": 5,
  "reporting_period": {
    "start": "2024-02-05T00:00:00Z",
    "end": "2024-02-05T23:59:59Z"
  },
  "currency": "USD",
  "media_buy_deliveries": [
    {
      "media_buy_id": "mb_001",
      "status": "active",
      "totals": {
        "impressions": 50000,
        "spend": 1750
      }
    },
    {
      "media_buy_id": "mb_002",
      "status": "active",
      "totals": {
        "impressions": 48500,
        "spend": 1695
      }
    },
    {
      "media_buy_id": "mb_003",
      "status": "reporting_delayed",
      "message": "Reporting data temporarily unavailable for this campaign",
      "expected_availability": "2024-02-06T02:00:00Z"
    }
  ],
  "partial_data": true,
  "unavailable_count": 1
}
部分失敗の主なフィールド:
  • partial_data: いずれかのキャンペーンでデータ欠落がある場合に true
  • unavailable_count: 遅延/欠落しているキャンペーン数
  • status: キャンペーン単位のステータス("active", "reporting_delayed", "failed"
  • expected_availability: 遅延データの準備予定時刻(分かる場合)
部分配信を使うべきケース:
  1. 上流遅延: データソースの速度差がある
  2. システム劣化: 部分的な障害が一部キャンペーンに影響
  3. データ品質問題: 特定キャンペーンのみ検証に失敗
  4. レートリミット: API 制限で全キャンペーンを取得できない
部分配信を使わないケース:
  1. 全体障害: "delayed" 通知を送る
  2. 全キャンペーンに影響: notification_type: "delayed" を使用
  3. バイヤー側エンドポイント問題: サーキットブレーカーで送信を止める
バイヤー側の処理例:
function processAggregatedWebhook(webhook) {
  if (webhook.partial_data) {
    console.warn(`Partial data: ${webhook.unavailable_count} campaigns delayed`);
  }

  for (const delivery of webhook.media_buy_deliveries) {
    if (delivery.status === 'reporting_delayed') {
      // Mark campaign as pending, retry via polling or wait for next webhook
      markCampaignPending(delivery.media_buy_id, delivery.expected_availability);
    } else if (delivery.status === 'active') {
      // Process normal delivery data
      processCampaignMetrics(delivery);
    } else {
      console.error(`Unexpected status for ${delivery.media_buy_id}: ${delivery.status}`);
    }
  }
}
ベストプラクティス:
  • データがない場合もステータス付きで全キャンペーンを配列に含める
  • 遅延/失敗がある場合は partial_data: true を設定
  • 分かる場合は expected_availability を返す
  • Webhook 全体をリトライしない。必要ならバイヤーは個別にポーリング
  • 部分配信率をモニタリングし、システム的な問題を検知

プライバシーとコンプライアンス

GDPR/CCPA 向けの PII マスキング
パブリッシャーはすべての Webhook ペイロードから PII を削除し、GDPR/CCPA に準拠する必要があります。レポート Webhook には集計・匿名化された指標のみを含めてください。 除去するもの:
  • ユーザー ID、デバイス ID、IP アドレス
  • メールアドレス、電話番号
  • 正確な位置情報(緯度/経度)
  • Cookie ID、広告 ID(集計されていない場合)
  • PII を含むカスタムディメンション
保持してよいもの:
  • 集計指標(インプレッション、消化額、クリックなど)
  • 粗い地理情報(市/州/国。番地は不可)
  • デバイスタイプカテゴリ(モバイル/デスクトップ/タブレット)
  • ブラウザ/OS カテゴリ
  • 時間ベースの集計
Example - Before PII Scrubbing (❌ DO NOT SEND):
{
  "media_buy_id": "mb_001",
  "user_events": [
    {
      "user_id": "user_12345",
      "ip_address": "192.168.1.100",
      "device_id": "abc-def-ghi",
      "impressions": 1,
      "lat": 40.7128,
      "lon": -74.0060
    }
  ]
}
Example - After PII Scrubbing (✅ CORRECT):
{
  "media_buy_id": "mb_001",
  "totals": {
    "impressions": 125000,
    "spend": 5625.00,
    "clicks": 250
  },
  "by_geography": [
    {
      "city": "New York",
      "state": "NY",
      "country": "US",
      "impressions": 45000,
      "spend": 2025.00
    }
  ]
}
パブリッシャーの責任:
  • Webhook 配信ではなくデータ収集レイヤーで PII をマスクする
  • 再識別されないよう集計閾値を設定(例: セグメントあたり 10 ユーザー以上)
  • 収集データと Webhook で共有するデータの違いを明文化
  • GDPR 準拠のため DPA(データ処理契約)を提供
  • GDPR/CCPA の削除依頼に対応
バイヤーの責任:
  • requested_metrics やカスタムディメンションで PII を要求しない
  • Webhook データが集計・匿名化されていることを理解する
  • 適切なデータ保持ポリシーを実装
  • プライバシーポリシー/ユーザー通知に Webhook データを含める

実装ベストプラクティス

  1. 配列を扱う: 1 件でも media_buy_deliveries は配列として処理する
  2. 冪等なハンドラー: 重複通知を安全に処理(Webhook は at-least-once 配信)
  3. シーケンス管理: sequence_number で欠落/順不同の通知を検知
  4. フォールバックポーリング: Webhook 失敗時に備え定期ポーリングを継続
  5. タイムゾーン意識: 期間計算のためパブリッシャーのタイムゾーンを保持
  6. 頻度の検証: リクエストした頻度が available_reporting_frequencies に含まれることを確認
  7. 指標の検証: リクエストした指標が available_metrics に含まれることを確認
  8. PII コンプライアンス: Webhook ペイロードにユーザーレベルデータを含めない

Webhook Health Monitoring

Webhook 配信ステータスは AdCP のグローバルタスク管理システム で追跡します(Task Lifecycle 参照)。 reporting_webhook を設定してメディアバイを作成すると、パブリッシャーは配信用のタスクを生成します。バイヤーは標準のタスククエリで Webhook の健全性を監視できます。 タスク管理を使う利点:
  • すべての AdCP オペレーションで一貫したステータス管理
  • ポーリング/Webhook の標準パターンを利用
  • ステータス/履歴/エラーの既存インフラを活用
  • メディアバイ固有の健全性エンドポイントが不要
Webhook 配信が恒常的に失敗しサーキットブレーカーが開いた場合、パブリッシャーはタスクステータスを更新して問題を示します。バイヤーは通常のタスク監視で検知できます。

オフラインファイル配信ベースのレポーティング

例: オフライン配信 パブリッシャーが日次レポートをバイヤーのクラウドストレージへプッシュ:
s3://buyer-reports/publisher_name/2024/02/05/media_buy_delivery.json.gz
ファイルは Webhook と同じ構造で、すべてのキャンペーンを集約しています。バイヤーは都合の良いタイミングで処理します。 オフライン配信を使うケース:
  • 同一バイヤーで 100 本超のアクティブキャンペーン
  • 時間単位レポートが必要(コスト 24 倍削減)
  • 詳細な内訳や多次元データでボリュームが大きい
  • バイヤーにバッチ処理基盤がある
パブリッシャーはプロダクトの capabilities でオフライン配信サポートを宣言します。
{
  "reporting_capabilities": {
    "supports_webhooks": true,
    "supports_offline_delivery": true,
    "offline_delivery_protocols": ["s3", "gcs"]
  }
}
オフライン配信では JSON Lines (JSONL)、CSV、Parquet でレポートを提供できます。いずれも Webhook のネスト構造を保つためバッチ処理に適しています。 .jsonl.gz/.csv.gz/.parquet.gz のように gzip 圧縮してストレージと転送コストを削減できます。

JSON Lines (JSONL)

1 行 1 メディアバイ(改行区切り JSON)。各行にレポート期間とパッケージレベルのデータを持つ 1 つのデリバリーオブジェクトが含まれます。ネスト構造を保持しつつ、行単位で簡単にパースできるためストリーミング処理に適しています。 Example JSONL file:
{"notification_type": "scheduled", "sequence_number": 5, "next_expected_at": "2024-02-06T08:00:00Z", "reporting_period": {"start": "2024-02-05T00:00:00Z", "end": "2024-02-05T23:59:59Z"}, "currency": "USD", "media_buy_id": "mb_001", "buyer_ref": "campaign_a", "status": "active", "totals": {"impressions": 50000, "spend": 1750.00, "clicks": 100, "ctr": 0.002}, "by_package": [{"package_id": "pkg_001", "impressions": 30000, "spend": 1050.00, "pacing_index": 0.95, "pricing_model": "cpm", "rate": 0.035, "currency": "USD"}, {"package_id": "pkg_002", "impressions": 20000, "spend": 700.00, "pacing_index": 0.98, "pricing_model": "cpm", "rate": 0.035, "currency": "USD"}]}
{"notification_type": "scheduled", "sequence_number": 5, "next_expected_at": "2024-02-06T08:00:00Z", "reporting_period": {"start": "2024-02-05T00:00:00Z", "end": "2024-02-05T23:59:59Z"}, "currency": "USD", "media_buy_id": "mb_002", "buyer_ref": "campaign_b", "status": "active", "totals": {"impressions": 200000, "spend": 9000.00, "clicks": 400, "ctr": 0.002}, "by_package": [{"package_id": "pkg_003", "impressions": 200000, "spend": 9000.00, "pacing_index": 1.02, "pricing_model": "cpm", "rate": 45.00, "currency": "USD"}]}
{"notification_type": "scheduled", "sequence_number": 5, "next_expected_at": "2024-02-06T08:00:00Z", "reporting_period": {"start": "2024-02-05T00:00:00Z", "end": "2024-02-05T23:59:59Z"}, "currency": "USD", "media_buy_id": "mb_003", "buyer_ref": "campaign_c", "status": "active", "totals": {"impressions": 75000, "spend": 3375.00, "clicks": 150, "ctr": 0.002}, "by_package": [{"package_id": "pkg_004", "impressions": 75000, "spend": 3375.00, "pacing_index": 0.96, "pricing_model": "cpcv", "rate": 0.045, "currency": "USD"}]}

CSV

For tabular analysis CSV files require unnesting nested arrays. Each record should be unnested to the by_package level, meaning one row per package with parent-level data (reporting period, media buy info, totals) duplicated. Example CSV structure:
notification_type,sequence_number,next_expected_at,reporting_period_start,reporting_period_end,currency,media_buy_id,buyer_ref,status,totals_impressions,totals_spend,totals_clicks,totals_ctr,by_package_package_id,by_package_impressions,by_package_spend,by_package_clicks,by_package_pacing_index,by_package_pricing_model,by_package_rate,by_package_currency
scheduled,5,2024-02-06T08:00:00Z,2024-02-05T00:00:00Z,2024-02-05T23:59:59Z,USD,mb_001,campaign_a,active,50000,1750.00,100,0.002,pkg_001,30000,1050.00,60,0.95,cpm,0.035,USD
scheduled,5,2024-02-06T08:00:00Z,2024-02-05T00:00:00Z,2024-02-05T23:59:59Z,USD,mb_001,campaign_a,active,50000,1750.00,100,0.002,pkg_002,20000,700.00,40,0.98,cpm,0.035,USD
scheduled,5,2024-02-06T08:00:00Z,2024-02-05T00:00:00Z,2024-02-05T23:59:59Z,USD,mb_002,campaign_b,active,200000,9000.00,400,0.002,pkg_003,200000,9000.00,400,1.02,cpm,45.00,USD
scheduled,5,2024-02-06T08:00:00Z,2024-02-05T00:00:00Z,2024-02-05T23:59:59Z,USD,mb_003,campaign_c,active,75000,3375.00,150,0.002,pkg_004,75000,3375.00,150,0.96,cpcv,0.045,USD

Parquet

For high-volume analytics Columnar format optimized for analytics workloads. Excellent compression ratios. Supports nested structures natively. Best for data warehouses and big data processing. Example Parquet schema:
{
  "type": "record",
  "name": "MediaBuyDelivery",
  "fields": [
    {"name": "notification_type", "type": "string"},
    {"name": "sequence_number", "type": "int"},
    {"name": "next_expected_at", "type": "string"},
    {"name": "reporting_period", "type": {
      "type": "record",
      "name": "ReportingPeriod",
      "fields": [
        {"name": "start", "type": "string"},
        {"name": "end", "type": "string"}
      ]
    }},
    {"name": "currency", "type": "string"},
    {"name": "media_buy_id", "type": "string"},
    {"name": "buyer_ref", "type": "string"},
    {"name": "status", "type": "string"},
    {"name": "totals", "type": {
      "type": "record",
      "name": "Totals",
      "fields": [
        {"name": "impressions", "type": "long"},
        {"name": "spend", "type": "double"},
        {"name": "clicks", "type": "long"},
        {"name": "ctr", "type": "double"}
      ]
    }},
    {"name": "by_package", "type": {
      "type": "array",
      "items": {
        "type": "record",
        "name": "PackageDelivery",
        "fields": [
          {"name": "package_id", "type": "string"},
          {"name": "impressions", "type": "long"},
          {"name": "spend", "type": "double"},
          {"name": "pacing_index", "type": "double"},
          {"name": "pricing_model", "type": "string"},
          {"name": "rate", "type": "double"},
          {"name": "currency", "type": "string"}
        ]
      }
    }}
  ]
}
File Structure: Each file contains one media buy delivery per line (JSONL) or row (CSV/Parquet). Files may contain:
  • Multiple media buy deliveries (one per line/row)
  • Multiple reporting periods for the same media buy (separate rows)
  • Multiple media buys (each with its own rows)
Processing Recommendations:
  • Process files in chronological order using file timestamps
  • Handle duplicate files gracefully (idempotent processing)
  • Validate file integrity using checksums if provided
  • Monitor for missing files and alert on gaps

Data Reconciliation

The get_media_buy_delivery API is the authoritative source of truth for all campaign metrics, regardless of whether you use webhooks, offline delivery, or polling. Reconciliation is important for any reporting delivery method because:
  • Webhooks: May be missed due to network failures or circuit breaker drops
  • Offline files: May be delayed, corrupted, or fail to process
  • Polling: May miss data during API outages
  • Late-arriving data: Impressions can arrive 24-48+ hours after initial reporting (all methods)

Reconciliation Process

Buyers SHOULD periodically reconcile delivered data against API to ensure accuracy: Recommended Reconciliation Schedule:
  • Hourly delivery: Reconcile via API daily
  • Daily delivery: Reconcile via API weekly
  • Monthly delivery: Reconcile via API at month end + 7 days
  • Campaign close: Always reconcile after campaign_end + attribution_window
Reconciliation Logic:
async function reconcileWebhookData(mediaBuyId, startDate, endDate) {
  // Get authoritative data from API
  const apiData = await adcp.getMediaBuyDelivery({
    media_buy_id: mediaBuyId,
    date_range: { start: startDate, end: endDate }
  });

  // Compare with webhook data in local database
  const webhookData = await db.getWebhookTotals(mediaBuyId, startDate, endDate);

  const discrepancy = {
    impressions: apiData.totals.impressions - webhookData.impressions,
    spend: apiData.totals.spend - webhookData.spend,
    clicks: apiData.totals.clicks - webhookData.clicks
  };

  // Acceptable discrepancy thresholds
  const impressionVariance = Math.abs(discrepancy.impressions) / apiData.totals.impressions;
  const spendVariance = Math.abs(discrepancy.spend) / apiData.totals.spend;

  if (impressionVariance > 0.02 || spendVariance > 0.01) {
    // Significant discrepancy (>2% impressions or >1% spend)
    console.warn(`Reconciliation discrepancy for ${mediaBuyId}:`, discrepancy);

    // Update local database with authoritative API data
    await db.updateCampaignTotals(mediaBuyId, apiData.totals);

    // Alert if discrepancy is unusually large
    if (impressionVariance > 0.10 || spendVariance > 0.05) {
      await alertOps(`Large reconciliation discrepancy detected`, {
        media_buy_id: mediaBuyId,
        webhook_totals: webhookData,
        api_totals: apiData.totals,
        discrepancy
      });
    }
  }

  return {
    status: impressionVariance < 0.02 ? 'reconciled' : 'discrepancy_found',
    api_data: apiData.totals,
    webhook_data: webhookData,
    discrepancy
  };
}
Why Discrepancies Occur:
  1. Delivery failures: Webhooks missed, offline files corrupted, API timeouts during polling
  2. Late-arriving data: Impressions attributed after initial reporting (all delivery methods)
  3. Data corrections: Publisher adjusts metrics after initial reporting
  4. Processing errors: Buyer-side failures to process delivered data
  5. Timezone differences: Period boundaries may differ between delivery and API query
Source of Truth Rules:
  • For billing: Always use get_media_buy_delivery API at campaign end + attribution window
  • For real-time decisions: Use delivered data (webhook/file/poll) for speed, reconcile later
  • For discrepancies: API data wins, update local records accordingly
  • For audits: API provides complete historical data, delivered data is ephemeral
Best Practices:
  • Store webhook sequence_number to detect missed notifications
  • Run automated reconciliation daily for active campaigns
  • Alert on discrepancies >2% for impressions or >1% for spend
  • Use API data for all financial reporting and invoicing
  • Document reconciliation process for audit compliance

Late-Arriving Impressions

Ad serving data often arrives with delays due to attribution windows, offline tracking, and pipeline latency. Publishers declare expected_delay_minutes in reporting_capabilities:
  • Display/Video: Typically 4-6 hours
  • Audio: Typically 8-12 hours
  • CTV: May be 24+ hours
This represents when most data is available, not all data.

遅延データの扱い

過去の期間に遅延データが届いた場合、その期間を is_adjusted: true 付きで 再送 します。
{
  "notification_type": "adjusted",
  "reporting_period": {
    "start": "2024-02-01T00:00:00Z",
    "end": "2024-02-01T23:59:59Z"
  },
  "media_buy_deliveries": [{
    "media_buy_id": "mb_001",
    "is_adjusted": true,
    "totals": {
      "impressions": 51000,  // Updated total (was 50000)
      "spend": 1785          // Updated spend (was 1750)
    }
  }]
}
バイヤー側の処理:
function processWebhook(webhook) {
  for (const delivery of webhook.media_buy_deliveries) {
    if (delivery.is_adjusted) {
      // Replace entire period with updated totals
      db.replaceCampaignPeriod(
        delivery.media_buy_id,
        webhook.reporting_period,
        delivery.totals
      );
    } else {
      // Normal new period data
      db.insertCampaignPeriod(delivery.media_buy_id, webhook.reporting_period, delivery.totals);
    }
  }
}
調整済み期間を送るべき場合:
  • 大きなデータ変化(インプレッション ±2% 超、または消化額 ±1% 超)
  • campaign_end + attribution_window 時点での最終照合
  • データ品質修正
ポーリングのみの場合、バイヤーは API 結果を時系列で比較することで調整を検知します。

Webhook の信頼性

レポート Webhook は AdCP 標準の信頼性パターンに従います。
  • At-least-once 配信: 同じ通知が複数回届く場合がある
  • ベストエフォート順序: 順不同で届く場合がある
  • タイムアウトとリトライ: 配信失敗時は回数を限定して再試行
実装の詳細は Webhooks を参照してください。

最適化の戦略

予算最適化

  • 成果の高低パッケージ間での 再配分
  • 配信改善のための ペーシング調整
  • 消化効率 の分析と改善

クリエイティブ最適化

  • アセット別の パフォーマンス分析
  • A/B テスト によるアプローチ比較
  • クリエイティブ疲弊を防ぐ リフレッシュ戦略

ターゲティング改善

  • オーディエンス別パフォーマンス の分析
  • 配信データに基づく 地理的最適化
  • 最適なタイミングに合わせた 時間調整

パフォーマンスフィードバックループ

ビジネス成果をパブリッシャーにフィードバックすることで、AI 主導の最適化を可能にします。詳細な API は provide_performance_feedback を参照してください。

パフォーマンスインデックスの概念

相対的な成果を示す正規化スコア。
  • 0.0 = 測定可能な価値や影響なし
  • 1.0 = ベースライン/想定パフォーマンス
  • > 1.0 = 平均以上(例: 1.45 は 45% 改善)
  • < 1.0 = 平均未満(例: 0.8 は 20% 低下)

パフォーマンスデータの共有

バイヤーは provide_performance_feedback タスクを使って任意で成果を共有できます。
{
  "media_buy_id": "gam_1234567890",
  "measurement_period": {
    "start": "2024-01-15T00:00:00Z",
    "end": "2024-01-21T23:59:59Z"
  },
  "performance_index": 1.35,
  "metric_type": "conversion_rate"
}

サポートされる指標

  • overall_performance: キャンペーン全体の成果
  • conversion_rate: クリック後/視聴後コンバージョン率
  • brand_lift: ブランド認知/想起のリフト
  • click_through_rate: クリエイティブのエンゲージメント
  • completion_rate: 動画/音声の完了率
  • viewability: ビューアブル率
  • brand_safety: ブランドセーフティ順守
  • cost_efficiency: 望む成果あたりのコスト

パブリッシャーが活用する方法

パブリッシャーはパフォーマンスインデックスを活用して:
  1. 配信最適化: 高成果セグメントへ配信をシフト
  2. 価格調整: 実証された価値に基づき CPM を更新
  3. プロダクト改善: 成果パターンに基づきプロダクト定義を磨く
  4. アルゴリズム強化: 実際のビジネス成果で ML モデルを学習

プライバシーとデータ共有

  • パフォーマンス共有は任意でありバイヤーが制御する
  • 集計されたパフォーマンス傾向はプラットフォーム全体の改善に利用される場合がある
  • 個別キャンペーンの詳細はバイヤーとパブリッシャーの関係内に留まる

Dimensional Performance (Future)

Future implementations may support dimensional performance feedback, allowing optimization at the intersection of multiple dimensions (e.g., “mobile users in NYC perform 80% above baseline”).

Targeting Consistency

Reporting aligns with AdCP’s Targeting approach, enabling:
  • Consistent analysis across campaign lifecycle
  • Granular breakdowns by targeting parameters
  • Cross-campaign insights for portfolio optimization

Target → Measure → Optimize

The power of consistent targeting and reporting creates a virtuous cycle:
  1. Target: Define your audience using briefs and overlays (e.g., “Mobile users in major metros”)
  2. Measure: Report on the same attributes (Track performance by device type and geography)
  3. Optimize: Feed performance back to improve delivery (Shift budget to high-performing segments)

Standard Metrics

All platforms must support these core metrics:
  • impressions: Number of ad views
  • spend: Amount spent in currency
  • clicks: Number of clicks (if applicable)
  • ctr: Click-through rate (clicks/impressions)
Optional standard metrics:
  • conversions: Post-click/view conversions
  • viewability: Percentage of viewable impressions
  • completion_rate: Video/audio completion percentage
  • engagement_rate: Platform-specific engagement metric

Platform-Specific Considerations

Different platforms offer varying reporting and optimization capabilities:
  • Comprehensive dimensional reporting, real-time and historical data, advanced viewability metrics

Kevel

  • Real-time reporting API, custom metric support, flexible aggregation options

Triton Digital

  • Audio-specific metrics (completion rates, skip rates), station-level performance data, daypart analysis

Advanced Analytics

Cross-Campaign Analysis

  • Portfolio performance across multiple campaigns
  • Audience overlap and frequency management
  • Budget allocation optimization across campaigns

Predictive Insights

  • Performance forecasting based on historical data
  • Optimization recommendations from AI analysis
  • Trend prediction for proactive adjustments

Response Times

Optimization operations have predictable timing:
  • Delivery reports: ~60 seconds (data aggregation)
  • Campaign updates: Minutes to days (depending on changes)
  • Performance analysis: ~1 second (cached metrics)

Best Practices

  1. Report Frequently: Regular reporting improves optimization opportunities
  2. Track Pacing: Monitor delivery against targets to avoid under/over-delivery
  3. Analyze Patterns: Look for performance trends across dimensions
  4. Consider Latency: Some metrics may have attribution delays
  5. Normalize Metrics: Use consistent baselines for performance comparison

Integration with Media Buy Lifecycle

Optimization and reporting is the ongoing phase that runs throughout active campaigns:
  • Connects to Creation: Use learnings to improve future campaign setup
  • Guides Updates: Data-driven decisions for campaign modifications
  • Enables Scale: Proven strategies can be applied to similar campaigns
  • Feeds AI: Performance data improves automated optimization