GAS(Google Apps Script)でMeta広告の成果をスプレッドシートへ毎朝書き出すと、購入数が広告マネージャより多く出ることがあります。コードの書き間違いを疑いたくなるところですが、原因はMetaのMarketing APIが返すデータの形の側にあります。この記事を読むと、直近7日を毎朝上書きするGASのコードと、購入数が二重になる原因、数字が合わないときに確かめる順番がわかります。
「Facebook広告 スプレッドシート」の作業が3つに分かれる理由
「Facebook広告 スプレッドシート」で調べると、向きの違う3つの作業の話が同じ画面に並びます。どれを探しているかで、使う仕組みも必要な権限もまるで違います。
| 向き | 動くデータ | 主な手段 |
|---|---|---|
| Meta → シート(成果) | 表示回数・クリック・費用・購入などの集計値 | 広告レポートの書き出し、GAS、外部のコネクタ |
| Meta → シート(リード) | リード獲得広告のフォームに入力された氏名・連絡先 | Meta Business SuiteのCRM連携、外部の自動化ツール |
| シート → Meta | 商談化・成約などのオフラインの成果 | コンバージョンAPI(スプレッドシートを接続する設定) |
広告の成果をシートに出すなら、MetaのMarketing API(広告の数字を外から取り出す窓口)から取るのが基本です。広告マネージャの「広告レポート」は .xlsx や .csv で書き出せるため、週に1回の報告なら貼り付けで足ります。負担になるのは、毎朝の確認にシートを使う場合や、複数の人が同じシートを見る場合です。貼る人が休むと表が止まり、貼り忘れた日だけ数字が抜けます。毎日見る表なら、人の手を通さずにAPIから取る作りに寄せるのが向いています。
リードは氏名や電話番号を含む個人情報で、シートに流す前に誰が開けるか、いつ消すかを決めておく必要があります。成約の返送は配信の学習に効く仕組みで、どちらも成果の集計とは扱うデータも権限も違います。
GASでMeta広告の成果を毎朝シートに書き出す手順
準備は「アプリ」「システムユーザー」「ads_readの権限」の3つ
GASから広告の数字を取るには、Meta for Developersで作るアプリと、そのアプリを通して広告アカウントを読むためのアクセストークンが要ります。
- Meta for Developersでアプリを作る
- ビジネス設定でシステムユーザー(人ではなく仕組みのために作るアカウント)を作り、広告アカウントとアプリを割り当てる
- ads_read(広告の数字を読むだけの権限)でトークンを発行する
- トークンをGASの「スクリプト プロパティ」に
META_TOKEN、act_ から始まる広告アカウントIDをAD_ACCOUNT_IDという名前で入れる
Metaの開発者ドキュメントは、システムユーザーのアクセストークンは期限切れにならないと説明しています。個人のアカウントで発行した長期のトークンは約60日で切れるため、それで組むと2か月後のある朝に表が止まります。トークンはシートのセルに書かず、GASの「スクリプト プロパティ」に入れるのも忘れたくない点です。セルに書くと、シートを開ける人全員が広告アカウントを読める鍵を持つことになります。
直近7日を毎朝上書きするコード
次のコードは、キャンペーン別・日別の成果を直近7日分取り直し、シートの同じ期間だけを書き換えます。前日の1行を足していく作りにしないのは、Metaの成果があとから増えるためです。
const API_VERSION = 'v26.0'; // Metaの変更履歴(changelog)で使える版を確かめる
const SHEET_NAME = 'meta_raw';
const DAYS = 7; // 毎回取り直す日数
const ACTION = 'omni_purchase'; // 広告マネージャの「購入」と突き合わせて決める
const HEADER = ['日付', 'キャンペーン', '表示回数', 'クリック', '費用', '購入', '購入の値'];
function updateMetaAds() {
const props = PropertiesService.getScriptProperties();
const token = props.getProperty('META_TOKEN');
const account = props.getProperty('AD_ACCOUNT_ID'); // act_から始まるID
const tz = Session.getScriptTimeZone();
const day = 24 * 60 * 60 * 1000;
const fmt = function (d) { return Utilities.formatDate(d, tz, 'yyyy-MM-dd'); };
const key = function (v) { return v instanceof Date ? fmt(v) : String(v); };
const pick = function (list) {
const hit = (list || []).filter(function (a) { return a.action_type === ACTION; })[0];
return hit ? Number(hit.value) : 0;
};
const since = fmt(new Date(Date.now() - DAYS * day));
const until = fmt(new Date(Date.now() - day));
let url = 'https://graph.facebook.com/' + API_VERSION + '/' + account + '/insights' +
'?level=campaign&time_increment=1&limit=500' +
'&fields=campaign_name,impressions,clicks,spend,actions,action_values' +
'&time_range=' + encodeURIComponent(JSON.stringify({ since: since, until: until })) +
'&access_token=' + token;
const fresh = [];
while (url) {
const res = JSON.parse(UrlFetchApp.fetch(url, { muteHttpExceptions: true }).getContentText());
if (res.error) throw new Error(res.error.message); // 失敗はトリガーの通知メールで気づける
res.data.forEach(function (r) {
fresh.push([r.date_start, r.campaign_name, Number(r.impressions || 0), Number(r.clicks || 0),
Number(r.spend || 0), pick(r.actions), pick(r.action_values)]);
});
url = res.paging && res.paging.next;
}
const sheet = SpreadsheetApp.getActive().getSheetByName(SHEET_NAME);
const last = sheet.getLastRow();
const kept = last > 1 ? sheet.getRange(2, 1, last - 1, HEADER.length).getValues().filter(function (row) {
return key(row[0]) < since || key(row[0]) > until;
}) : [];
const rows = kept.concat(fresh).sort(function (a, b) {
return key(a[0]) < key(b[0]) ? -1 : key(a[0]) > key(b[0]) ? 1 : 0;
});
sheet.clearContents();
sheet.getRange(1, 1, 1, HEADER.length).setValues([HEADER]);
if (rows.length) sheet.getRange(2, 1, rows.length, HEADER.length).setValues(rows);
}
シートには meta_raw という名前のタブを作っておきます。動いたら、GASの「トリガー」から時間主導型・日付ベースで毎朝1回(例: 午前5時〜6時)を設定します。
見落としやすいのは日付の境目で、広告アカウントのタイムゾーンと、スクリプト(プロジェクトの設定)・スプレッドシート(ファイル→設定)のタイムゾーンをそろえておく必要があります。ずれていると、取り直す7日の端が1日ずれ、毎朝1日分だけ古い数字が残ります。トークン切れなどで7日より前に抜けた期間ができたときは、DAYS を一時的に広げて1回だけ実行すれば埋まります。
広告レポートの集計作業に時間を取られていませんか?ADminiなら無料で始められます。無料で試してみる →
購入数が広告マネージャより多くなる本当の原因
actionsの中には、同じ購入が複数の種類で入っている
APIの成果は actions という一覧で返り、同じ購入が omni_purchase や offsite_conversion.fb_pixel_purchase など複数の種類で並びます。名前に purchase を含む種類をすべて足すと、1件の購入を2〜3回数えることになります。冒頭の「購入数が多すぎる」の正体は、たいていこれです。
次の表は、ある1日のキャンペーンの actions を再現用のサンプルデータで示したものです(実在のアカウントの数字ではありません)。広告マネージャの「購入」列は12件でも、purchase を含む種類を合計すると35件になります。
| action_type | value |
|---|---|
| omni_purchase | 12 |
| purchase | 12 |
| offsite_conversion.fb_pixel_purchase | 11 |
| purchase を含む種類の合計 | 35(広告マネージャの「購入」は12) |
どの種類が広告マネージャの「購入」と一致するかは、ピクセルだけで計測しているか、Conversions APIやアプリの購入も送っているかで変わり得ます。決め方は単純です。
- 1日分だけ取って actions の中身をログに出す
- 広告マネージャで同じ日・同じアトリビューション設定の「購入」と比べる
- 一致する種類を1つ選んで、コードの
ACTIONに書く
種類は足さずに1つ選び、選んだ理由を別のタブに書き残すと、担当が替わっても数字の意味が変わりません。
7日の取り直しで足りても、月の締めの数字は28日まで動く
Metaの開発者ドキュメントでは、成果の数字は15分ごとに更新され、計上から28日たつと変わらなくなるとされています。7日という幅は、Conversions APIで送る成果が発生から7日以内ならあとから届く仕様に合わせたもので、ふだんの差はこの幅で消えます。
ところが月次報告では、前月末の数字を翌月の頭に締めるため、28日の手前で数字を固定することになります。「7日取り直していれば、締めた数字は広告マネージャといつまでも一致する」とは言えません。締めた日に前月分だけ取り直し、報告には何日時点の数字かを書き添えると、あとで食い違いを聞かれても説明がつきます。広告セットごとにアトリビューション設定が違う場合も、同じ「購入」に数え方の違う数字が混ざるので、先に設定をそろえておきます。
GASの書き出しが毎朝止まる3つの原因
止まったことに気づけるよう、トリガーの失敗通知はメールで受け取る設定にしておきます。原因はほぼ次の3つに収まります。
- トークン:個人のトークンは約60日で切れる。システムユーザーのトークンでも、広告アカウントの割り当てを外すと読めなくなる
- 実行時間:GASは1回の実行が6分までで、広告単位・日別で長い期間を取ると届くことがある。期間を分けるか、キャンペーン単位にする
- APIの版:Metaは版ごとに提供期限を設けている。期限を過ぎた版を書いたままでは、同じ動きが続く保証はない。年に1〜2回は変更履歴で使っている版を確かめる
3つに共通するのは、書いた人が見張り続けないと止まる点です。コードを持ちたくない場合は、ADminiのMeta広告連携のように、広告アカウント・集計の単位・成果として数えるアクションを選んでつなぐと、1日1回の自動更新のたびに前日までの数字を取り直してくれるツールに任せる手もあります。数える種類を最初に1つ選ぶ点は、上のコードの ACTION と同じ考え方です。ただし連携で取るのは表示回数・クリック・費用・コンバージョン・コンバージョン値で、リーチやフリークエンシー、動画の再生指標は取りません。
まとめ
- 成果をシートへ出すならMarketing APIから取り、GASならシステムユーザーのトークンで直近7日を毎朝上書きする
- 購入数が多すぎるときは、actions の purchase 系の種類を足していないかを確かめ、広告マネージャと一致する種類を1つだけ使う
- 月の締めの数字は計上から28日まで動くため、締めた日に前月分を取り直し、何日時点の数字かを書き添える
よくある質問
Facebook広告のデータをスプレッドシートに自動で出す方法はありますか?
あります。MetaのMarketing APIから成果を取り、Google Apps Script(GAS)でシートに書き込む方法と、外部のコネクタで転記する方法があります。GASで組む場合は、Meta for Developersのアプリと、ads_read の権限を持つアクセストークンが必要です。週に1回の報告だけなら、広告マネージャの「広告レポート」を .xlsx や .csv で書き出して貼る方法でも足ります。
GASでMeta広告のデータを取るとき、アクセストークンの期限はどうすればいいですか?
ビジネス設定のシステムユーザーでトークンを発行するのが確実です。Metaの開発者ドキュメントでは、システムユーザーのアクセストークンは期限切れにならないと説明されています。個人のアカウントで発行した長期のトークンは約60日で切れるため、定期実行には向きません。トークンはシートのセルではなく、GASのスクリプト プロパティに保存します。
APIで取ったMeta広告の購入数が広告マネージャより多いのはなぜですか?
actions の一覧に、同じ購入が omni_purchase や offsite_conversion.fb_pixel_purchase など複数の種類で入っているためです。purchase を含む種類をすべて足すと、1件の購入を2〜3回数えます。1日分を取って中身を確かめ、広告マネージャで同じ日・同じアトリビューション設定の「購入」と一致する種類を1つだけ使います。
リード獲得広告のリードをスプレッドシートに送ることはできますか?
できますが、広告の成果を集計する仕組みとは別の設定になります。Meta Business SuiteのCRM連携や外部の自動化ツールで、フォームに入力されたリードをシートへ送ります。リードは氏名や連絡先を含む個人情報のため、シートを開ける人と保存期間を決めてからつなぎます。
図解・表つきの完全版はこちら:Facebook(Meta)広告のデータをスプレッドシートに出す方法|GASで毎朝書き出すコードと、購入数が二重になる落とし穴
広告レポートの集計作業に時間を取られていませんか?ADminiなら無料で始められます。無料で試してみる →
この記事が役に立ったら LGTM をいただけると励みになります!
