0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Meta API】広告レポートを自動転記する方法

Posted at

事前準備

必要なもの

  • Facebookアカウント
  • Meta広告アカウント
  • Googleアカウント(GAS用)
  • スプレッドシート

取得する主な情報

  • アプリID
  • アプリシークレット
  • アクセストークン
  • 広告アカウントID
  • キャンペーンID、広告セットID、広告ID

Meta開発者アカウント・アプリの作成

ステップ1: Meta for Developersにアクセス

  1. Meta for Developers にアクセス
  2. Facebookアカウントでログイン
  3. 右上の「マイアプリ」をクリック

ステップ2: アプリを作成

  1. 「アプリを作成」ボタンをクリック
  2. ユースケースを選択
    • 広告データ取得の場合: 「マーケティングAPIで広告パフォーマンスデータを測定」を選択
    • その他: 用途に応じて選択
  3. 「次へ」をクリック

ステップ3: アプリ情報を入力

アプリ表示名: 任意の名前(例: 広告レポート取得)
アプリの連絡先メールアドレス: あなたのメールアドレス
ビジネスポートフォリオ: 該当する場合は選択
  1. 「アプリを作成」をクリック

meta_アプリ.png

ステップ4: アプリIDとアプリシークレットを確認

  1. 左メニュー「設定」→「ベーシック」を選択
  2. 以下の情報をメモ(後で使用)
    • アプリID: 123456789
    • app secret: 「表示」をクリックして確認

長期シークレット.png

⚠️ 重要: アプリシークレットは絶対に他人に教えないこと


アクセストークンの取得

方法1: Graph APIエクスプローラーを使用(推奨)

ステップ1: Graph APIエクスプローラーにアクセス

  1. Graph APIエクスプローラー を開く
  2. 右上の「アプリケーション」で作成したアプリを選択

ステップ2: 短期ユーザーアクセストークンを取得

  1. 「アクセストークンを取得」→「ユーザーアクセストークン」をクリック
  2. 必要な権限(Permissions)にチェック

広告データ取得に必要な権限:

ads_management
ads_read
  1. 「アクセス許可を生成」をクリック
  2. 表示されたトークンをコピー(これが短期トークン

短期アクセストークン発行.png

⚠️ 注意: 短期トークンは約1時間で期限切れ


方法2: 長期アクセストークンへ変換(GASで実行)

ステップ1: GASスクリプトを作成

  1. Google Apps Script にアクセス
  2. 「新しいプロジェクト」をクリック
  3. 以下のコードを貼り付け
  // ========== ここを編集 ==========
  const SHORT_LIVED_TOKEN = '短期トークンをここに貼り付け';
  const APP_ID = 'あなたのアプリID';
  const APP_SECRET = 'あなたのアプリシークレット';
  // ================================

function getLongLivedToken() {

  const url = 'https://graph.facebook.com/v21.0/oauth/access_token?' +
    'grant_type=fb_exchange_token&' +
    'client_id=' + APP_ID + '&' +
    'client_secret=' + APP_SECRET + '&' +
    'fb_exchange_token=' + SHORT_LIVED_TOKEN;

  try {
    const response = UrlFetchApp.fetch(url);
    const data = JSON.parse(response.getContentText());

    // 長期トークンをスクリプトプロパティに保存
    PropertiesService.getScriptProperties().setProperty('LONG_TOKEN', data.access_token);

    return data.access_token;
  } catch (error) {
    Logger.log('エラー: ' + error);
  }
}

ステップ2: 実行

  1. 関数選択で getLongLivedToken を選択
  2. 「実行」をクリック
  3. 初回は権限確認が表示されるので「権限を確認」→「許可」
  4. 実行ログ(表示 → ログ)で長期トークンを確認
  5. 長期トークンをコピーして安全な場所に保存

⚠️ 長期トークンの有効期限: 約60日


必要なIDの取得方法

1. 広告アカウントIDの取得

Meta広告マネージャから取得

  1. Meta広告マネージャ にアクセス
  2. URLを確認: https://business.facebook.com/adsmanager/manage/campaigns?act=123456789
  3. act= の後の数字が広告アカウントID
  4. API使用時は act_123456789 の形式で使用

2. それぞれのID取得実装例

 const ACCOUNT_ID = 'act_123456789';
 const LONG_TOKEN = 'あなたの長期トークン';
 const API_VERSION = 'v24.0';
  

// キャンペーンIDの取得
 const campainId = `https://graph.facebook.com/${API_VERSION}/${ACCOUNT_ID}/campaigns?` +
    `fields=id,name,status,objective&` +
    `access_token=${LONG_TOKEN}`;
    
// 広告セット取得
const adSetsUrl = `https://graph.facebook.com/${API_VERSION}/${campainId}/adsets?` +
    `fields=id,name,status&` +
    `access_token=${LONG_TOKEN}`;

const adSetsResponse = UrlFetchApp.fetch(adSetsUrl);
const adSetsData = JSON.parse(adSetsResponse.getContentText());

adSetsData.data.forEach(adSet => {
    // 広告取得
    const adsUrl = `https://graph.facebook.com/${API_VERSION}/${adSet.id}/ads?` +
      `fields=id,name,status&` +
      `access_token=${LONG_TOKEN}`;

    const adsResponse = UrlFetchApp.fetch(adsUrl);
    const adsData = JSON.parse(adsResponse.getContentText());
});

GASでの実装

広告データをスプレッドシートに転記

// ========== 設定情報 ==========
const CONFIG = {
  API_VERSION: 'v24.0',
  LONG_TOKEN: PropertiesService.getScriptProperties().getProperty('LONG_TOKEN'),
  ACCOUNT_ID: 'act_123456789',
  CAMPAIGN_ID: 'あなたのキャンペーンID',
  SHEET_ID: 'あなたのスプレッドシートID',
  SHEET_NAME: 'シート名',
  API_SLEEP_MS: 1000, // APIリクエスト間のスリープ時間(ミリ秒)
};

const SHEET_HEADERS = [
  '広告セット名',
  '広告名',
  '取得日',
  'clicks',
  'impressions',
  'spend',
  'reach',
  'ctr',
  'cpc',
  'cpm',
  'cpp'
];

const INSIGHT_FIELDS = [
  'clicks',
  'spend',
  'impressions',
  'reach',
  'ctr',
  'cpc',
  'cpm',
  'cpp'
];
// ==============================

/**
 * メイン関数:広告インサイトデータをスプレッドシートに取得
 */
function getAdInsightsToSheet() {
  try {
    const yesterday = getYesterdayDate();

    // 広告セット一覧を取得
    const adSetsData = fetchAdSets();
    const rowsToWrite = collectAdInsights(adSetsData, yesterday);
    
    writeToSheet(rowsToWrite);
    
    Logger.log('処理完了: ' + new Date());
  } catch (error) {
    Logger.log('エラーが発生しました: ' + error.message);
    throw error;
  }
}

/**
 * 広告セット一覧を取得
 * @returns {Object} 広告セットデータ
 */
function fetchAdSets() {
  const url = buildGraphApiUrl(
    `${CONFIG.CAMPAIGN_ID}/adsets`,
    { fields: 'id,name' }
  );
  
  return fetchFromApi(url, '広告セット取得');
}

/**
 * 指定された広告セットに紐づく広告一覧を取得
 * @param {Object} adSet - 広告セットオブジェクト
 * @returns {Object} 広告データ
 */
function fetchAds(adSet) {
  const url = buildGraphApiUrl(
    `${adSet.id}/ads`,
    { fields: 'id,name' }
  );
  
  return fetchFromApi(url, `広告取得: ${adSet.name}`);
}

/**
 * 指定された広告のインサイトデータを取得
 * @param {Object} ad - 広告オブジェクト
 * @param {string} date - 取得日(YYYY-MM-DD形式)
 * @returns {Object} インサイトデータ
 */
function fetchInsights(ad, date) {
  const url = buildGraphApiUrl(
    `${ad.id}/insights`,
    {
      fields: INSIGHT_FIELDS.join(','),
      'time_range[since]': date,
      'time_range[until]': date
    }
  );
  
  return fetchFromApi(url, `インサイト取得: ${ad.name}`);
}

/**
 * Graph API URLを構築
 * @param {string} endpoint - APIエンドポイント
 * @param {Object} params - クエリパラメータ
 * @returns {string} 完全なURL
 */
function buildGraphApiUrl(endpoint, params = {}) {
  const baseUrl = `https://graph.facebook.com/${CONFIG.API_VERSION}/${endpoint}`;
  
  // アクセストークンを追加
  params.access_token = CONFIG.LONG_TOKEN;
  
  // クエリ文字列を構築
  const queryString = Object.entries(params)
    .map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
    .join('&');
  
  return `${baseUrl}?${queryString}`;
}

/**
 * APIからデータを取得
 * @param {string} url - リクエストURL
 * @param {string} logMessage - ログメッセージ
 * @returns {Object} パース済みレスポンスデータ
 */
function fetchFromApi(url, logMessage = 'API取得') {
  try {
    Logger.log(`${logMessage}中...`);
    const response = UrlFetchApp.fetch(url);
    return JSON.parse(response.getContentText());
  } catch (error) {
    Logger.log(`${logMessage}失敗: ${error.message}`);
    throw error;
  }
}

/**
 * 全広告セットからインサイトデータを収集
 * @param {Object} adSetsData - 広告セットデータ
 * @param {string} date - 取得日
 * @returns {Array} スプレッドシート書き込み用の2次元配列
 */
function collectAdInsights(adSetsData, date) {
  const rowsToWrite = [];
  
  if (!adSetsData.data || adSetsData.data.length === 0) {
    Logger.log('広告セットが見つかりませんでした');
    return rowsToWrite;
  }
  
  adSetsData.data.forEach(adSet => {
    // 広告取得
    const adsData = fetchAds(adSet);
    Utilities.sleep(CONFIG.API_SLEEP_MS);
    
    if (!adsData.data || adsData.data.length === 0) {
      Logger.log(`  広告が見つかりません: ${adSet.name}`);
      return;
    }
    
    adsData.data.forEach(ad => {
      try {
        // インサイトデータを取得
        const insightsData = fetchInsights(ad, date);
        
        if (hasInsights(insightsData)) {
          const row = buildSheetRow(adSet, ad, insightsData.data[0], date);
          rowsToWrite.push(row);
        } else {
          Logger.log(`  データなし: ${ad.name}`);
        }
      } catch (error) {
        Logger.log(`  エラー: ${ad.name} - ${error.message}`);
      }
      
      Utilities.sleep(CONFIG.API_SLEEP_MS);
    });
  });
  
  Logger.log(`合計 ${rowsToWrite.length} 件のデータを収集しました`);
  return rowsToWrite;
}

/**
 * インサイトデータが存在するかチェック
 * @param {Object} insightsData - インサイトデータ
 * @returns {boolean} データの有無
 */
function hasInsights(insightsData) {
  return insightsData && 
         insightsData.data && 
         insightsData.data.length > 0;
}

/**
 * スプレッドシート書き込み用の行データを構築
 * @param {Object} adSet - 広告セット
 * @param {Object} ad - 広告
 * @param {Object} insights - インサイトデータ
 * @param {string} date - 取得日
 * @returns {Array} 行データ配列
 */
function buildSheetRow(adSet, ad, insights, date) {
  return [
    adSet.name,
    ad.name,
    date,
    insights.clicks || 0,
    insights.impressions || 0,
    insights.spend || 0,
    insights.reach || 0,
    insights.ctr || 0,
    insights.cpc || 0,
    insights.cpm || 0,
    insights.cpp || 0
  ];
}

/**
 * スプレッドシートにデータを書き込み
 * @param {Array} rowsToWrite - 書き込むデータの2次元配列
 */
function writeToSheet(rowsToWrite) {
  if (!rowsToWrite || rowsToWrite.length === 0) {
    Logger.log('書き込むデータがありません');
    return;
  }

  // シートデータを取得
  const ss = SpreadsheetApp.openById(CONFIG.SHEET_ID);
  let sheet = ss.getSheetByName(CONFIG.SHEET_NAME);
  
  const lastRow = sheet.getLastRow();
  const startRow = lastRow + 1;
  const numRows = rowsToWrite.length;
  const numCols = SHEET_HEADERS.length;
  
  sheet.getRange(startRow, 1, numRows, numCols).setValues(rowsToWrite);
  Logger.log(`${numRows} 件のデータを書き込みました(行 ${startRow} から)`);
}

/**
 * 昨日の日付を取得(YYYY-MM-DD形式)
 * @returns {string} 昨日の日付
 */
function getYesterdayDate() {
  const date = new Date();
  date.setDate(date.getDate() - 1);
  return formatDate(date);
}

/**
 * 日付をYYYY-MM-DD形式にフォーマット
 * @param {Date} date - Dateオブジェクト
 * @returns {string} フォーマットされた日付文字列
 */
function formatDate(date) {
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, '0');
  const day = String(date.getDate()).padStart(2, '0');
  
  return `${year}-${month}-${day}`;
}

トリガー設定手順:

  1. GASエディタで「トリガー」アイコン(時計マーク)をクリック

  2. 「トリガーを追加」をクリック

  3. 設定

    • 実行する関数: getAdInsightsTosheet
    • イベントのソース: 時間主導型
    • 時間ベースのトリガー: 日付ベースのタイマー
    • 時刻: 午前2時〜3時

    トリガー設定.png

  4. 「保存」をクリック


トラブルシューティング

エラー1: Invalid OAuth access token

原因: トークンが無効または期限切れ

解決方法:

  1. 新しい短期トークンを取得
  2. 長期トークンに変換し直す
  3. コード内のトークンを更新

エラー2: User request limit reached (Error Code 17)

原因: APIリクエスト制限に到達(一時的)

エラー3: Exception: Invalid argument: URL

原因: URLに特殊文字が含まれている

解決方法:

// フィルター条件をエンコード
const adFilter = encodeURIComponent(JSON.stringify([
    {
      "field": "effective_status",
      "operator": "IN",
      "value": ["DELETED", "ARCHIVED"]
    }
]));

参考リンク

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?