広告データパイプライン、実際に動かしてみたらバグとの戦いでした
Photo by Carlos Muza on Unsplash
こんにちは。エンスポーツの田窪です。
前回の記事では「Meta・Google・Appleの広告データをBigQueryに集約して、分析・自動化・AI活用まで持っていく」という構想についてお話しました。
今回は「実際にAPI繋いでBigQueryにデータを流すまで」の話なのですが、まあまあハマりポイントがあって大変でした。
シェアしていきます。
そもそもなぜこれをやっているのか
広告運用をやっていると「データはあるのに、見たい形で見られない」というフラストレーションが日常的にあるんですよね。
Meta、Google、Appleの3つの管理画面をそれぞれ開いて、CSVを落として、スプレッドシートに貼って、やっと比較できる。この作業を毎週やっていると、さすがに「もうちょっとなんとかならんか」と思うわけです。
だからこそ「APIで自動取得→BigQueryに集約」の仕組みを作ろうとしているのですが、この「繋ぐだけ」が思った以上に一筋縄ではいきませんでした。
まず、3つのAPIに繋ぐところから
コードはできた。認証情報も(苦労して)揃えた。あとは繋ぐだけ。
のはずでした。
Metaの罠: トークンを発行しただけでは足りない
接続テストを走らせると、いきなりこれです。
❌ 接続失敗:
Ad account owner has NOT grant ads_management or ads_read permission
❌ 接続失敗:
Ad account owner has NOT grant ads_management or ads_read permission
「アクセストークン発行したのに読めないんですけど。」と思いました。
調べてみると、原因はシステムユーザーに広告アカウントへのアクセス権限を付与していなかったことでした。Metaの仕組みでは、トークンを発行しただけでは広告データにアクセスできなくて、Business Manager → システムユーザー → 「アセットを追加」で広告アカウントを紐づけるという、もう1ステップが必要だったんですよね。
しかもこれ、トークン発行の画面とアカウント紐づけの画面が完全に別の場所にあるので、気づくのに時間がかかりました。
Googleの罠: UIに表示されてるそのままコピペしたらエラー
❌ 接続失敗:
Invalid customer ID 'XXX-XXX-XXXX'.
❌ 接続失敗:
Invalid customer ID 'XXX-XXX-XXXX'.
Customer IDにハイフンが入っていたのが原因でした。Google Adsの管理画面ではハイフン付きで表示されるのに、APIは数字だけで渡さないといけない仕様なんですね。なんでやねん。
Appleの罠: 鍵ペアを自分で作るところから始まる
Appleは認証の仕組みからして一味違いました。管理画面を開くと「Public Keyをアップロードしてね」と表示される。
他の2つはトークンやOAuthクレデンシャルを管理画面から発行できるのに、Appleは鍵ペアを自分で生成するところから始まります。ターミナルでopensslコマンドを叩いて鍵を作り、公開鍵をAppleにアップロードし、秘密鍵を手元に保管する、という流れでした。
ここまではよかったのですが、次のハマりポイントが待っていました。
秘密鍵を .env ファイルに直接入れると、改行の扱いでJWTの署名処理がコケるんですよね。 secretOrPrivateKey must be an asymmetric key when using ES256 というエラーが出て、最初は何が悪いのか全然わかりませんでした。最終的に「環境変数に鍵の中身を入れるのではなく、ファイルパスを指定する方式」に切り替えて解決しました。
さらにもう1つ。Apple Search Adsの管理画面で「Adminロール」を持っているのに、APIユーザーが作れないという問題もありました。調べたらAdmin権限とAPI権限は別物で、APIアクセス用のロールを別途付与する必要があったんですよね。Adminなのにできない、というのは直感に反していてかなり混乱しました。
3つとも繋がった瞬間
接続テストスクリプトを作って、1つずつ確認していきました。
✅ Meta: 接続成功! アカウント名: ○○○○
✅ Google: 接続成功! アカウント名: ○○○○
✅ Apple: 認証成功!
✅ Meta: 接続成功! アカウント名: ○○○○
✅ Google: 接続成功! アカウント名: ○○○○
✅ Apple: 認証成功!
ここに至るまでの試行錯誤を考えると、なんとも感慨深かったです。
BigQueryにデータを流す
接続テストが通ったので、次はいよいよ本番です。APIからデータを取得して、変換して、BigQueryに投入するパイプラインを動かします。
「接続さえできればあとはスムーズでしょ」と思っていたのですが、そんなに甘くはなかったです。
Metaの仕様: 言わなければ返ってこない
Insert error: Field value of account_id cannot be empty. (invalid)
Insert error: Field value of account_id cannot be empty. (invalid)
APIからデータ18行の取得に成功。変換処理もOK。BigQueryに入れようとしたら「account_idが空」と怒られました。
原因を調べたら、Meta APIは「ほしいフィールドを明示的にリストする」仕様になっていて、リクエスト時に account_id を指定し忘れていたことが原因でした。他のプラットフォームだと基本情報は勝手に返ってくることが多いのですが、Metaは「言わなければ返さない」タイプなんですよね。合理的ではあるけど、気づかないと原因の特定に時間がかかります。
フィールドリストに1行追加して解決しました。たった1行ですが、この1行に辿り着くまでの調査時間たるや。
BigQueryの内部バッファとの戦い
UPDATE or DELETE statement over table would affect rows in the streaming buffer
UPDATE or DELETE statement over table would affect rows in the streaming buffer
これはBigQueryの仕様に起因するエラーでした。このパイプラインでは、同じ日付のデータを再実行しても重複しないように「該当日のデータをDELETE → 新しいデータをINSERT」というパターンを採用しています。
ところがBigQueryにはストリーミングバッファという仕組みがあって、INSERT直後のデータは内部バッファに保持されます。このバッファがフラッシュされるまで(数十分かかることもある)、そのデータに対するDELETEが効かないんですよね。
テスト中に何度も連続実行していたので、これに引っかかりました。「ストリーミングバッファエラーの場合はDELETEをスキップする」という処理を追加して対応しました。
全部通った
📊 パイプラインテスト: meta ✅ 完了 (18行)
📊 パイプラインテスト: google ✅ 完了 (3行)
📊 パイプラインテスト: apple ✅ 完了 (3行)
📊 パイプラインテスト: meta ✅ 完了 (18行)
📊 パイプラインテスト: google ✅ 完了 (3行)
📊 パイプラインテスト: apple ✅ 完了 (3行)
BigQueryのコンソールを開くと、meta_ads_daily、google_ads_daily、apple_ads_daily の3テーブルにちゃんとデータが入っていました。
昨日の広告パフォーマンスが、キャンペーン・広告グループ・広告の粒度で格納されている。あの3つの管理画面を行ったり来たりしなくても、1つのSQLで横断的に見られる状態になりました。
これがやりたかったことです。やったね。
2年分の過去データを一気に流し込む
昨日のデータだけ入っても分析としてはあまり意味がないので、2024年1月から現在まで約2年分の過去データを一括投入することにしました。トレンドや季節性を把握するにはやはりある程度の期間のデータが必要です。
とはいえ2年分を一発でAPIに投げるとタイムアウトするので、月単位のチャンクに分割して処理するスクリプトを書きました。各プラットフォーム × 27ヶ月 = 81回のAPI呼び出しを自動で回してくれます。
📊 バックフィル: 2024-01-01 〜 2026-03-03 (27 チャンク)
=== Meta Ads ===
🔄 2024-01-01 〜 2024-01-30 ✅ 7行
🔄 2024-01-31 〜 2024-02-28 ✅ 21行
🔄 2024-02-29 〜 2024-03-30 ✅ 63行
...
📊 バックフィル: 2024-01-01 〜 2026-03-03 (27 チャンク)
=== Meta Ads ===
🔄 2024-01-01 〜 2024-01-30 ✅ 7行
🔄 2024-01-31 〜 2024-02-28 ✅ 21行
🔄 2024-02-29 〜 2024-03-30 ✅ 63行
...
Metaだけで数千行のデータが流れ込んでいきます。広告を出していない月はデータが少なく、キャンペーンを多く回していた月はデータ量が跳ね上がる。こういう実データの手触りは、実際に動かしてみないとわからないものだなと思いました。
やってみて感じたこと
データ基盤は地味だけど一番大事
正直な話、今日やったことの大半は「エラーを直す」「設定を確認する」「ドキュメントを読む」の繰り返しでした。華やかさはないです。ダッシュボードもグラフもまだない。
でも、この地味な基盤がないと上に何も積めないんですよね。CSVを手動でダウンロードして貼り付ける作業から解放されるのは、ここをちゃんとやったからです。
マーケティングの仕事って、施策を考えたりクリエイティブを作ったりする部分にスポットが当たりがちですが、その裏側では「データをちゃんと整備する」という地味な作業が積み重なっています。今回はそれを自分の手でやってみたことで、改めてデータ基盤の重要さを実感しました。
3プラットフォームの設計思想の違いが面白い
広告運用をやっていると各プラットフォームのUIの違いは日常的に感じていますが、APIレベルで付き合うと設計思想の違いがもっとはっきり見えてきます。
Metaは「全部明示的に指定させる」スタイル。欲しいフィールドを一つ一つ列挙しないとデータが返ってこない。Googleは「Customer IDのハイフンを自分で除去しろ」。Appleは「鍵ペアを自分で作れ」から始まる。
どれが正解とかではないのですが、それぞれの会社の開発者向けプロダクトに対する考え方が透けて見えるのは面白かったです。
Claudeさんっていいよね
このプロジェクトはClaude Codeとのペアプログラミングで進めています。コードの雛形を書いてもらう → エラーが出る → ログを貼る → 原因特定して修正、のサイクルがものすごい速さで回ります。
特に今回のような「各プラットフォームのAPIの微妙な仕様差を調べる」部分でAIが活きました。3つのAPIのドキュメントを全部自分で読んで比較していたら、たぶん3倍は時間がかかっていたと思います。
マーケターの立場から思うのは、こういうツールの価値は「コードが書けない人がコードを書けるようになる」というより、「やりたいことの実現速度が上がる」という部分にあるということです。構想から動くものまでの距離が圧倒的に短くなるので、「こういう仕組みがあったらいいのにな」を実際に手を動かして作れるようになります。
今日の成果
- Meta / Google / Apple の3プラットフォーム、すべてAPI接続に成功
- 3つのパイプラインでBigQueryへのデータ投入を確認
- 2024年1月からの過去データ、一括バックフィルを実行
- BigQueryに
meta_ads_daily、google_ads_daily、apple_ads_dailyの3テーブルが稼働開始
次にやること
統合ビューの作成がまず最初です。3テーブルを横断で見られるVIEWを作って、1つのSQLで全媒体を比較できるようにします。その後、Cloud Functionsへデプロイして毎朝自動でデータ取得する仕組みにして、Looker Studioで可視化まで持っていきたいと思っています。
あとはGoogle Ads Developer Tokenの本番承認を待っている状態です。テスト用トークンで動作確認は済んだので、本番トークンが降りたら本格運用を開始します。
データが入った。基盤ができましたので、ここからが本番です。
前回の記事: https://www.wantedly.com/companies/ensports/post_articles/1048339