なぜMeta広告とYahoo!広告は実装が必要なのか
Google広告にはBigQuery Data Transfer Service、GA4にはBigQueryエクスポートという公式連携があります。一方、Meta広告とYahoo!広告には、BigQueryへ直接データを送る公式コネクタがありません。この2媒体を分析基盤に加えるには、APIでデータを取得して自分で書き込む実装が必要になります。
| 媒体 | BigQueryへの連携手段 | 実装の要否 |
|---|---|---|
| Google広告 | Data Transfer Service(公式) | 設定のみ |
| GA4 | BigQueryエクスポート(公式) | 設定のみ |
| Meta広告 | Marketing API+自作スクリプト | 実装が必要 |
| Yahoo!広告 | LINEヤフー広告 API+自作スクリプト | 実装が必要 |
実装と聞くと身構えるかもしれませんが、日次でレポートデータを取り込むだけなら、Google Apps Script(GAS)で完結します。サーバーの契約も追加費用も不要です。筆者も複数の広告アカウントでこの構成を本番運用しており、一度構築すれば手を入れる場面はほとんどありません。
この記事はBigQueryの基本を理解している前提で進めます。初めての場合はBigQueryで広告データを集約する方法から読むことをおすすめします。Google広告の連携はData Transfer Serviceの設定ガイドをご覧ください。
全体アーキテクチャ
構成はシンプルです。GASが時間トリガーで毎日起動し、各媒体のAPIから前日分のレポートを取得して、BigQueryにロードします。
実装環境はGASのほかに、Cloud RunやCloud Functionsを使う選択肢もあります。判断基準は次のとおりです。
| 観点 | GAS | Cloud Run+Scheduler |
|---|---|---|
| 追加費用 | なし | 無料枠超過分が発生しうる |
| 実行時間の制限 | 1回6分まで | 実質制約なし |
| 開発・保守の負荷 | 低い | 環境構築とデプロイ管理が必要 |
| 向いているケース | 日次バッチ・少数アカウント | 大量アカウント・高頻度実行 |
GASの実行時間は公式の割り当てで1回6分までです。日次のキャンペーン単位レポートであれば、経験上この制限内に十分収まります。まずGASで作り、限界が見えたらCloud Runへ移す順番が現実的です。GASの基礎はGASで広告運用を自動化するで解説しています。
Meta広告のデータを取得する
準備: アプリとシステムユーザートークン
Meta広告のデータ取得には、Meta for Developersでのアプリ作成と、アクセストークンの発行が必要です。ここで重要なのがトークンの種類の選択です。
通常の手順で発行される長期ユーザートークンは、約60日で失効します。自動連携が2か月ごとに止まる原因になるため、バッチ用途には向きません。ビジネスマネージャの「システムユーザー」で発行するトークンは、Full Access(Standard tier)のアプリであれば時間経過による失効がなく、無人運用に適しています。
ただし、システムユーザートークンも権限変更などのイベントで無効になることがあります。完全に「設定して終わり」にはならない前提で、失敗検知の通知を用意しておきましょう。
insightsエンドポイントの基本
レポートデータは /act_{広告アカウントID}/insights エンドポイントから取得します。主要パラメータは次の4つです。
| パラメータ | 役割 | 設定例 |
|---|---|---|
level | 集計粒度 | campaign(ほかに account / adset / ad) |
fields | 取得する指標 | spend,impressions,clicks,actions など |
time_range | 対象期間 | {"since":"2026-07-01","until":"2026-07-23"} |
time_increment | 期間の分割 | 1 で日別(既定は期間合計) |
コンバージョンは actions フィールドに種類別の配列で返ります。さらに action_attribution_windows パラメータで 7d_click や 1d_view を指定すると、クリック起因とビュー起因の数値を別々のキーで取得できます。Meta広告の申告コンバージョンはビュースルーの比率が高いことも多く、この分離は分析の質を大きく左右します。最初から分けて蓄積しておくことを強くおすすめします。
GASでの取得コード
キャンペーン単位・日別でインサイトを取得する実装例です。トークンやアカウントIDは、流出防止のためスクリプトプロパティに保存して参照します。
const PROPS = PropertiesService.getScriptProperties();
const META_API_VERSION = "v25.0";
function fetchMetaInsights(sinceDate, untilDate) {
const accountId = PROPS.getProperty("META_ACCOUNT_ID");
const token = PROPS.getProperty("META_ACCESS_TOKEN");
const params = {
level: "campaign",
fields: "campaign_id,campaign_name,spend,impressions,clicks,actions",
time_range: JSON.stringify({ since: sinceDate, until: untilDate }),
time_increment: "1",
action_attribution_windows: JSON.stringify(["7d_click", "1d_view"]),
limit: "500",
access_token: token,
};
const query = Object.keys(params)
.map(function (k) { return k + "=" + encodeURIComponent(params[k]); })
.join("&");
let url = "https://graph.facebook.com/" + META_API_VERSION +
"/act_" + accountId + "/insights?" + query;
const rows = [];
while (url) {
const res = JSON.parse(UrlFetchApp.fetch(url).getContentText());
(res.data || []).forEach(function (r) { rows.push(flattenMetaRow(r)); });
url = res.paging && res.paging.next ? res.paging.next : null;
}
return rows;
}
function flattenMetaRow(row) {
let cvClick = 0;
let cvView = 0;
(row.actions || []).forEach(function (a) {
if (a.action_type === "offsite_conversion.fb_pixel_purchase") {
cvClick += Number(a["7d_click"] || 0);
cvView += Number(a["1d_view"] || 0);
}
});
return {
date: row.date_start,
media: "meta",
campaign_id: row.campaign_id,
campaign_name: row.campaign_name,
cost: Number(row.spend || 0),
impressions: Number(row.impressions || 0),
clicks: Number(row.clicks || 0),
cv_click: cvClick,
cv_view: cvView,
};
}
flattenMetaRow で集計対象にする action_type は、アカウントの計測設計によって変わります。購入なら offsite_conversion.fb_pixel_purchase、リード獲得なら別のタイプになるため、まず一度APIの生レスポンスを確認し、自社のCVに対応するタイプを特定してください。
レート制限は広告アカウント単位で管理され、アプリのアクセスレベルによって上限が大きく異なります。日次バッチで数アカウントを扱う範囲なら、通常は問題になりません。
Yahoo!広告のデータを取得する
準備: API利用の申請
Yahoo!広告のAPI(現名称はLINEヤフー広告 API)は、誰でもすぐ使えるわけではありません。Yahoo! JAPANビジネスIDでのログインと、API管理ツールでのアプリケーション登録の手続きが必要です。検索広告とディスプレイ広告でAPIの体系が分かれている点も、最初に押さえておきましょう。
認証はOAuth 2.0で、発行したリフレッシュトークンからアクセストークンを更新しながら利用します。Metaのシステムユーザートークンとは管理の考え方が異なるため、トークン更新処理を実装に含める必要があります。
非同期レポートの3ステップ
Yahoo!広告のレポート取得は、Metaのような同期型ではなく非同期型です。レポートの定義を登録し、生成完了を待ってからダウンロードする流れになります。
リクエストの具体的な項目定義はAPIバージョンごとに変わるため、実装時は必ず公式リファレンスの現行バージョンの定義に沿って組み立ててください。実装のポイントは次の3点です。
- レポート定義には日別・キャンペーン別の粒度と、費用・表示回数・クリック・CVの項目を含める
- ポーリングは数秒間隔にとどめ、GASの6分制限内に完了しない場合は取得期間を分割する
- ダウンロードしたCSVはヘッダー行と合計行の扱いに注意して整形する
なお、Yahoo!広告は検索広告とディスプレイ広告でレポートAPIが別々です。両方を配信している場合は、それぞれに同じ3ステップを実装し、整形後に共通スキーマへそろえます。
BigQueryへロードする
共通スキーマの設計
媒体ごとにバラバラの形式で保存すると、後の横断分析が面倒になります。取り込み時点で共通スキーマにそろえるのが定石です。最小構成として、次の項目をおすすめします。
| 列名 | 型 | 内容 |
|---|---|---|
date | DATE | 配信日(パーティション列にする) |
media | STRING | 媒体名(meta / yahoo_search など) |
campaign_id | STRING | キャンペーンID |
campaign_name | STRING | キャンペーン名 |
cost | FLOAT64 | 費用 |
impressions | INT64 | 表示回数 |
clicks | INT64 | クリック数 |
cv_click | FLOAT64 | クリック起因CV |
cv_view | FLOAT64 | ビュー起因CV |
date 列でパーティション分割しておくと、クエリのスキャン量と費用を抑えられます。テーブル設計の考え方は広告データ集約の基礎も参照してください。
GASからのロード実装
GASの「高度なGoogleサービス」でBigQueryを有効化すると、ロードジョブを直接投入できます。整形済みの行データをNDJSON形式にしてロードする実装例です。
function loadToBigQuery(rows, targetDate) {
if (!rows.length) return;
const projectId = PROPS.getProperty("BQ_PROJECT_ID");
const datasetId = "ads";
const tableId = "daily_campaign_stats";
const ndjson = rows.map(function (r) { return JSON.stringify(r); }).join("\n");
const blob = Utilities.newBlob(ndjson, "application/octet-stream");
const job = {
configuration: {
load: {
destinationTable: {
projectId: projectId,
datasetId: datasetId,
tableId: tableId,
},
sourceFormat: "NEWLINE_DELIMITED_JSON",
writeDisposition: "WRITE_APPEND",
timePartitioning: { type: "DAY", field: "date" },
autodetect: true,
},
},
};
const inserted = BigQuery.Jobs.insert(job, projectId, blob);
Logger.log("load job: " + inserted.jobReference.jobId);
}
ロードジョブ自体は無料で、課金対象はストレージとクエリだけです。ストリーミング挿入(insertAll)は料金が発生するうえ日次バッチには不要なので、ロードジョブ方式を選んでください。
洗い替え設計: 数値の遡及更新に備える
この構成で最も重要な設計判断が「何日分を取り直すか」です。Meta広告のコンバージョンはアトリビューションウィンドウの期間内、数値が後から増えていきます。前日分を1回取り込んで終わりにすると、BigQueryの数値だけが古いまま管理画面とずれ続けます。
実装は「直近7日分をDELETEしてから、同じ7日分を取得してAPPENDする」だけです。日次実行の冒頭に次のクエリを挟みます。
function deleteRecentRows() {
const projectId = PROPS.getProperty("BQ_PROJECT_ID");
const sql =
"DELETE FROM `" + projectId + ".ads.daily_campaign_stats` " +
"WHERE media = 'meta' " +
"AND date >= DATE_SUB(CURRENT_DATE('Asia/Tokyo'), INTERVAL 7 DAY)";
const request = { query: sql, useLegacySql: false };
BigQuery.Jobs.query(request, projectId);
}
取り直す日数は、アカウントのアトリビューション設定に合わせます。7日クリックを使っているなら7日分、より長いウィンドウなら日数を延ばしてください。Yahoo!広告も同じ洗い替えに含めておくと、媒体側の数値修正に自動で追随できます。
運用の注意点
構築後に実際へ起きやすいトラブルを挙げます。いずれも筆者が本番運用で経験したものです。
| リスク | 対策 |
|---|---|
| トークンの失効・無効化 | 取得失敗時にSlack等へ通知し、当日中に気づける状態にする |
| APIバージョンの廃止 | Metaは約2年でバージョンが失効するため、年1回の更新を予定に入れる |
| 実行の無音失敗 | 日次で行数をチェックし、0件の日はアラートを出す |
| 数値の定義ずれ | 導入時に管理画面と数日分を突き合わせ、CV定義を確定させる |
特に無音失敗への備えは重要です。トリガーは動いているのにデータが入っていない、という状態は気づきにくく、欠損期間が長いほど復旧に手間がかかります。「昨日の日付の行が存在するか」を確認するだけの監視クエリでも、あるとないとでは大違いです。
蓄積したデータの活用はBigQueryのSQL実践ガイドや、AIエージェントとのMCP接続に進むと広がります。日本語で媒体横断の分析ができる環境は、この取り込み基盤があってこそ成立します。
まとめ
Meta広告・Yahoo!広告のBigQuery取り込みについて、実装の要点を整理しました。
| 工程 | 要点 |
|---|---|
| 方式選定 | まずGAS。制限に当たったらCloud Runへ |
| Meta取得 | システムユーザートークン+insights、CVはクリック/ビューを分離 |
| Yahoo!取得 | API利用申請のうえ、非同期レポートの3ステップで実装 |
| ロード | 共通スキーマ+日付パーティション+ロードジョブ |
| 洗い替え | 直近7日を毎日削除→再取得で遡及更新に追随 |
| 運用 | 失敗通知と行数監視を最初から組み込む |
公式コネクタがない媒体の連携は、最初の構築にこそ手間がかかりますが、動き始めれば日々のレポート業務を大きく減らしてくれます。まずはMeta広告1アカウントから、管理画面との数値突き合わせまでを一巡させてみてください。