· 16分で読める

Meta広告・Yahoo!広告のデータをBigQueryに取り込む|API×GASで自動連携を実装する

目次閉じる開く

なぜMeta広告とYahoo!広告は実装が必要なのか

Google広告にはBigQuery Data Transfer Service、GA4にはBigQueryエクスポートという公式連携があります。一方、Meta広告とYahoo!広告には、BigQueryへ直接データを送る公式コネクタがありません。この2媒体を分析基盤に加えるには、APIでデータを取得して自分で書き込む実装が必要になります。

媒体BigQueryへの連携手段実装の要否
Google広告Data Transfer Service(公式)設定のみ
GA4BigQueryエクスポート(公式)設定のみ
Meta広告Marketing API+自作スクリプト実装が必要
Yahoo!広告LINEヤフー広告 API+自作スクリプト実装が必要

実装と聞くと身構えるかもしれませんが、日次でレポートデータを取り込むだけなら、Google Apps Script(GAS)で完結します。サーバーの契約も追加費用も不要です。筆者も複数の広告アカウントでこの構成を本番運用しており、一度構築すれば手を入れる場面はほとんどありません。

この記事はBigQueryの基本を理解している前提で進めます。初めての場合はBigQueryで広告データを集約する方法から読むことをおすすめします。Google広告の連携はData Transfer Serviceの設定ガイドをご覧ください。

全体アーキテクチャ

構成はシンプルです。GASが時間トリガーで毎日起動し、各媒体のAPIから前日分のレポートを取得して、BigQueryにロードします。

API×GASによる広告データ連携の全体像Meta Marketing APIinsightsエンドポイントLINEヤフー広告 API非同期レポートGAS時間トリガーで日次実行取得・整形・ロードBigQuery日付パーティション媒体横断テーブル下流: Looker Studio / AIエージェント / Slackレポート

実装環境はGASのほかに、Cloud RunやCloud Functionsを使う選択肢もあります。判断基準は次のとおりです。

観点GASCloud 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_click1d_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のような同期型ではなく非同期型です。レポートの定義を登録し、生成完了を待ってからダウンロードする流れになります。

Yahoo!広告 非同期レポート取得の流れ1. レポート定義を登録期間・項目・粒度を指定ReportDefinitionService2. 完了までポーリングステータスを数秒おきに確認完了まで待機3. ダウンロードCSVを取得して整形BigQueryへロードGASの1回の実行(6分以内)にこの3ステップを収める

リクエストの具体的な項目定義はAPIバージョンごとに変わるため、実装時は必ず公式リファレンスの現行バージョンの定義に沿って組み立ててください。実装のポイントは次の3点です。

  • レポート定義には日別・キャンペーン別の粒度と、費用・表示回数・クリック・CVの項目を含める
  • ポーリングは数秒間隔にとどめ、GASの6分制限内に完了しない場合は取得期間を分割する
  • ダウンロードしたCSVはヘッダー行と合計行の扱いに注意して整形する

なお、Yahoo!広告は検索広告とディスプレイ広告でレポートAPIが別々です。両方を配信している場合は、それぞれに同じ3ステップを実装し、整形後に共通スキーマへそろえます。

BigQueryへロードする

共通スキーマの設計

媒体ごとにバラバラの形式で保存すると、後の横断分析が面倒になります。取り込み時点で共通スキーマにそろえるのが定石です。最小構成として、次の項目をおすすめします。

列名内容
dateDATE配信日(パーティション列にする)
mediaSTRING媒体名(meta / yahoo_search など)
campaign_idSTRINGキャンペーンID
campaign_nameSTRINGキャンペーン名
costFLOAT64費用
impressionsINT64表示回数
clicksINT64クリック数
cv_clickFLOAT64クリック起因CV
cv_viewFLOAT64ビュー起因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の数値だけが古いまま管理画面とずれ続けます。

洗い替え設計: 直近分を毎日取り直す8日以上前: 確定分として保持直近7日: 毎日削除→再取得ビュースルーCVなどの遡及更新を毎日反映できる古い日付は再取得しないため処理時間とAPI消費を抑えられる取り直す日数はアトリビューション設定のウィンドウ長に合わせる

実装は「直近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アカウントから、管理画面との数値突き合わせまでを一巡させてみてください。

関連記事

この記事をAIと深掘りする

要約・疑問の解消に。記事のタイトル・URL・参照元を入れた質問文が自動で入力されます。

| 共有 はてブ

SIGNALZ メルマガ

厳選した実践ナレッジを週1回お届けします。

SIGNALZ

SIGNALZ

運用型広告の実務経験をもとに、体系的なナレッジを発信しています。

SIGNALZの記事はAIを活用して作成し、10年以上の運用型広告の実務経験をもとに内容を確認・監修しています。制作方針の詳細はサイトについてをご覧ください。

この記事について感想やご質問を送れます

誤りの指摘、補足情報、ご質問など、お気軽にどうぞ。