【コピペOK】GASでYahoo広告のレポートをスプレッドシートに自動取得する方法|OAuth認証から日次更新まで

2021年9月30日

2026年5月時点:本記事はYahoo!広告API v19対応の最新版に更新しました。コピペで動くGAS実装コード全文を掲載しています。

Yahoo!広告のインプレッション数・クリック数・コンバージョン数・費用などの運用データを、毎日手作業で管理画面からダウンロードするのは大きな手間です。本記事ではGAS(Google Apps Script)+ Yahoo!広告 API v19を使って、Yahoo!広告データをGoogle スプレッドシートに毎朝自動で取得・蓄積する方法を、コピペで動くコード全文付きで解説します。

この記事を読むと、次のことができるようになります。

  • Yahoo!広告APIのアプリケーション登録から認証情報(client_id / client_secret / refresh_token)の取得まで完了できる
  • OAuth認証 → レポート作成 → 完了待ちポーリング → CSV取得 → スプシ書き込み、までを1ファイルのGASで実装できる
  • access_tokenの1時間期限・refresh_tokenの失効仕様・401エラーなど、現場でハマる落とし穴を回避できる
  • GASの時間トリガーで日次レポートを完全自動化し、Looker Studioまで連携できる

対象読者は、Yahoo!広告を運用している広告代理店・インハウス担当者、レポート作成を自動化したいマーケター、GASで広告APIを叩いた経験のないエンジニアです。結論として、Yahoo!広告API v19 + GASの組み合わせで、毎朝6時に前日分のレポートを自動でスプレッドシートへ蓄積する仕組みは1〜2時間で構築できます。

📌 この記事でわかること
GASでYahoo広告のレポートデータをスプレッドシートに自動取得する方法を、OAuth認証の設定からコピペで使えるGASコード全文・日次自動実行の設定まで解説します。

その他の広告媒体の取得方法

目次

Yahoo広告のデータをGASでスプレッドシートに自動取得するとは

Yahoo!広告APIをGASから叩き、ReportDefinitionServiceで作成したレポートCSVをスプレッドシートに毎日書き込む仕組みのことです。運用画面からの手動DLが不要になり、Looker Studio等への連携・前日比比較・複数アカウント横断集計が一気に可能になります。

Yahoo!広告APIの最新バージョンはv19です(2026年5月時点)。旧バージョン(v7・v9など)はサポート終了しているため、これから実装するなら必ずv19を使ってください。詳細はYahoo!広告API 公式ドキュメントを参照してください。

自動取得の全体フロー(5ステップで解説)

GASによるYahoo!広告データの自動取得は、次の5ステップで完成します。

  1. Yahoo!広告APIのアプリケーションを登録し、client_id / client_secret を取得する
  2. OAuth認証フローで認可コード → refresh_token を発行する
  3. GAS側でrefresh_token からaccess_tokenを再発行するロジックを実装する
  4. ReportDefinitionService でレポート定義を作成し、完了までポーリングする
  5. 完了したレポートCSVをDLし、スプレッドシートにsetValuesで一括書き込みする

① Yahoo広告APIのアプリケーション登録とclient_id/client_secret取得

Yahoo!広告 API管理ツールに運用しているYahoo!ビジネスIDでログインし、「アプリケーションを追加」から新規登録します。リダイレクトURIにはoobを入力してください。登録完了後に表示されるクライアントIDクライアントシークレットを控えます。

② OAuth認証でrefresh_tokenを取得する

以下の形式でURLを作成してブラウザでアクセスし、アクセスを許可すると認可コードが画面に表示されます。

https://biz-oauth.yahoo.co.jp/oauth/v1/authorize?response_type=code
&client_id=CLIENT_ID
&redirect_uri=REDIRECT_URI
&scope=yahooads
&state=THIS_VALUE_SHOULD_BE_UNIQUE_PER_REQUEST

取得した認可コードを使い、ターミナルから以下のcurlコマンドを実行してaccess_tokenとrefresh_tokenを取得します。

curl -X GET \
"https://biz-oauth.yahoo.co.jp/oauth/v1/token?grant_type=authorization_code\
&client_id=CLIENT_ID\
&client_secret=CLIENT_SECRET\
&redirect_uri=REDIRECT_URI\
&code=AUTH_CODE"

③ GASでaccess_tokenを発行する

access_tokenは有効期限が1時間と短いため、GAS側で実行のたびに refresh_token からaccess_tokenを再発行する実装にします(後述のコード全文を参照)。

④ ReportDefinitionService でレポート定義を作成

v19のエンドポイントhttps://ads-search.yahooapis.jp/api/v19/ReportDefinitionService/addに対し、reportType・reportDateRangeType・fieldsなどをPOSTするとreportJobIdが返却されます。

⑤ レポートDL → スプレッドシートへ書き込み

getエンドポイントでreportJobStatusがCOMPLETEDになるまでポーリングし、downloadでCSVを取得してUtilities.parseCsvでパースし、setValuesでシートに一括書き込みします。

事前準備:必要なものチェックリスト

実装に入る前に、以下を一度に揃えておくと作業がスムーズです。

Yahoo!広告アカウントとAPI利用申請

  • Yahoo!広告アカウント(検索広告)
  • Yahoo!ビジネスID(API管理ツールへのログインに必要)
  • API利用申請の承認(管理ツール上で申請、通常数営業日)
  • MCC運用の場合はx-z-base-account-id用のMCCアカウントID

Google スプレッドシート・GASエディタ

  • 書き込み先となる空のGoogle スプレッドシート
  • 「db」という名前のシート(コード冒頭で参照しているシート名)
  • スプレッドシートの拡張機能から開けるGASエディタ

取得しておく認証情報(client_id / client_secret / refresh_token / accountId)

  • clientId:アプリケーション登録時に発行
  • clientSecret:アプリケーション登録時に発行
  • refreshToken:OAuth認証フローで発行
  • mccAccountId:MCC利用時のヘッダ用
  • targetAccountId:データを取得したい広告アカウントID

コピペで使えるGASコード全文(Yahoo!広告API v19対応)

下記コードを丸ごとGASエディタに貼り付け、上部の認証情報を自分の値に書き換えるだけで動作します。スプレッドシートに「db」シートを作成しておくのを忘れないでください。

認証部分(OAuth2 + refresh_token)+ レポート定義作成 + DL → 貼り付け

/**
 * Yahoo!広告 検索広告 API v19 対応版
 * 前日分のキャンペーンレポートを取得して「db」シートに追記する
 */
function main() {
  const ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('db');
  if (!ss) throw new Error("シート 'db' が見つかりません。");

  // --- 設定情報(スクリプトプロパティ管理推奨)---
  const props = PropertiesService.getScriptProperties();
  const clientId         = props.getProperty('YAHOO_CLIENT_ID');
  const clientSecret     = props.getProperty('YAHOO_CLIENT_SECRET');
  const refreshToken     = props.getProperty('YAHOO_REFRESH_TOKEN');
  const mccAccountId     = props.getProperty('YAHOO_MCC_ACCOUNT_ID');     // x-z-base-account-id 用
  const targetAccountId  = props.getProperty('YAHOO_TARGET_ACCOUNT_ID');  // データを取得する広告アカウントID

  // 1. アクセストークン取得
  const accessToken = yahooAdLogin(clientId, clientSecret, refreshToken);

  // 2. レポート作成ジョブの追加 (v19)
  const reportName = "Search_Report_" + Utilities.formatDate(new Date(), "JST", "yyyyMMdd_HHmmss");
  const createReportResponse = yahooAdCreateSearchReport(accessToken, mccAccountId, targetAccountId, reportName);
  const reportJobId = createReportResponse.rval.values[0].reportDefinition.reportJobId;
  console.log(`Search Report Job Created: ${reportJobId}`);

  // 3. レポート作成完了までループで確認 (最大2分)
  let isCompleted = false;
  for (let i = 0; i < 12; i++) {
    isCompleted = yahooAdCheckSearchReportStatus(accessToken, mccAccountId, targetAccountId, reportJobId);
    if (isCompleted) break;
    console.log("レポート作成中... (10秒待機)");
    Utilities.sleep(10000);
  }
  if (!isCompleted) throw new Error("レポート作成がタイムアウトしました。");

  // 4. レポートの取得とパース
  const reportData = yahooAdDownloadSearchReport(accessToken, mccAccountId, targetAccountId, reportJobId);

  if (reportData && reportData.length > 0) {
    const lastRow = ss.getRange("B:B").getValues().filter(String).length;
    const targetRow = lastRow + 1;
    ss.getRange(targetRow, 1, reportData.length, reportData[0].length).setValues(reportData);
    console.log(`${reportData.length}件のデータを追記しました。`);
  } else {
    console.log("対象期間にデータがありませんでした。");
  }
}

/** 共通ヘッダー生成 */
function getSearchHeaders(accessToken, mccAccountId) {
  return {
    'Authorization': `Bearer ${accessToken}`,
    'x-z-base-account-id': mccAccountId,
    'Content-Type': 'application/json'
  };
}

/** 認証: refresh_token から access_token を取得 */
function yahooAdLogin(clientId, clientSecret, refreshToken) {
  const url = "https://biz-oauth.yahoo.co.jp/oauth/v1/token";
  const options = {
    method: 'post',
    payload: {
      grant_type: "refresh_token",
      client_id: clientId,
      client_secret: clientSecret,
      refresh_token: refreshToken
    }
  };
  const response = UrlFetchApp.fetch(url, options);
  return JSON.parse(response.getContentText()).access_token;
}

/** 検索広告レポート作成 (v19) */
function yahooAdCreateSearchReport(accessToken, mccAccountId, targetAccountId, reportName) {
  const url = "https://ads-search.yahooapis.jp/api/v19/ReportDefinitionService/add";
  const payload = {
    accountId: targetAccountId,
    operand: [{
      reportName: reportName,
      reportType: "CAMPAIGN",
      reportDateRangeType: "YESTERDAY",
      reportDownloadFormat: "CSV",
      reportDownloadEncode: "UTF8",
      reportLanguage: "JA",
      reportCompressType: "NONE",
      reportIncludeDeleted: "TRUE",
      fields: [
        "CAMPAIGN_NAME", "DAY", "CLICKS", "CONVERSIONS", "COST",
        "IMPS", "CLICK_RATE", "AVG_CPC", "CONV_RATE", "CONV_VALUE"
      ]
    }]
  };
  const options = {
    method: 'post',
    headers: getSearchHeaders(accessToken, mccAccountId),
    payload: JSON.stringify(payload),
    muteHttpExceptions: true
  };
  const response = UrlFetchApp.fetch(url, options);
  if (response.getResponseCode() !== 200) throw new Error("Create Error: " + response.getContentText());
  return JSON.parse(response.getContentText());
}

/** 検索広告レポートステータス確認 (v19) */
function yahooAdCheckSearchReportStatus(accessToken, mccAccountId, targetAccountId, reportJobId) {
  const url = "https://ads-search.yahooapis.jp/api/v19/ReportDefinitionService/get";
  const options = {
    method: 'post',
    headers: getSearchHeaders(accessToken, mccAccountId),
    payload: JSON.stringify({ accountId: targetAccountId, reportJobIds: [reportJobId] })
  };
  const response = UrlFetchApp.fetch(url, options);
  const status = JSON.parse(response.getContentText()).rval.values[0].reportDefinition.reportJobStatus;
  if (status === "COMPLETED") return true;
  if (status === "FAILED") throw new Error("レポート作成失敗");
  return false;
}

/** 検索広告レポートダウンロードと整形 */
function yahooAdDownloadSearchReport(accessToken, mccAccountId, targetAccountId, reportJobId) {
  const url = "https://ads-search.yahooapis.jp/api/v19/ReportDefinitionService/download";
  const options = {
    method: 'post',
    headers: getSearchHeaders(accessToken, mccAccountId),
    payload: JSON.stringify({ accountId: targetAccountId, reportJobId: reportJobId })
  };
  const response = UrlFetchApp.fetch(url, options);
  const csvData = Utilities.parseCsv(response.getContentText());
  if (csvData.length <= 1) return [];
  csvData.shift(); // ヘッダ行を除去
  return csvData
    .filter(row => row.length > 0 && row[0] !== "" && row[0] !== "Total" && row[0] !== "合計")
    .map(row => [
      row[0], row[1],
      Number(row[2]) || 0, Number(row[3]) || 0, Number(row[4]) || 0,
      Number(row[5]) || 0, row[6],
      Number(row[7]) || 0, row[8],
      Number(row[9]) || 0
    ]);
}

スクリプトプロパティで認証情報を安全に管理する書き方

client_secretやrefresh_tokenをコードにベタ書きするのは事故のもとです。GASのスクリプトプロパティに保存し、コードからはPropertiesService.getScriptProperties()で参照する設計にしましょう。

function setProps() {
  PropertiesService.getScriptProperties().setProperties({
    YAHOO_CLIENT_ID: 'xxxxxxxxxxxxxxxxxxxxx',
    YAHOO_CLIENT_SECRET: 'xxxxxxxxxxxxxxxxxxxxx',
    YAHOO_REFRESH_TOKEN: 'xxxxxxxxxxxxxxxxxxxxx',
    YAHOO_MCC_ACCOUNT_ID: 'xxxxxxxxx',
    YAHOO_TARGET_ACCOUNT_ID: 'xxxxxxxxx'
  });
}

初回だけsetProps()を実行すれば、以降はmain()を実行するだけで動作します。GASのファイル共有を行ってもシークレット値はコードに含まれません。

取得期間の設定(reportDateRangeType)

reportDateRangeTypeの値を変えると取得対象期間を切り替えられます。

TODAY 本日
YESTERDAY 昨日
LAST_7_DAYS 本日を除く過去7日間
LAST_14_DAYS 本日を除く過去14日間
LAST_30_DAYS 本日を除く過去30日間
LAST_WEEK 先週の月曜日〜日曜日
LAST_BUSINESS_WEEK 先週の月曜日〜金曜日(5営業日)
THIS_MONTH 当月(本日含む)
LAST_MONTH 前月
ALL_TIME 取得可能な全期間

日次自動実行する設定(GASトリガー)

GASの時間主導型トリガーを使えば、サーバを立てずに毎日決まった時間にmain関数を自動実行できます。Yahoo!広告のレポートが確定するタイミングを考慮し、午前6〜7時に設定するのがおすすめです。

時間ベースのトリガーを毎朝6時に設定

GASエディタ左メニューの「トリガー」→「トリガーを追加」から以下のとおり設定します。

  • 実行する関数:main
  • イベントのソース:時間主導型
  • 時間ベースのトリガーのタイプ:日タイマー
  • 時間:午前6時〜7時(前日分のレポートが確実に揃っているタイミング)

これで毎朝6時に前日分の検索広告キャンペーンレポートが自動でスプシに蓄積されます。

実行失敗時のメール通知を仕込む

トリガー追加画面で「エラー通知設定」を「すぐに通知を受け取る」にしておくと、access_token期限切れやAPIエラーで失敗した時にGoogleアカウントのメールへ通知が届きます。try / catchでエラーをキャッチしてMailApp.sendEmailで自前通知する形にすると、Slack Webhook通知にも拡張しやすくなります。

よくあるハマりポイントと対処法

Yahoo!広告API + GAS実装で現場でよく踏むハマりポイントを表にまとめます。

ハマりポイント 原因 対処法
401 Unauthorized access_token期限切れ(1時間) 毎回refresh_tokenから再発行する実装にする
refresh_tokenが無効 長期間API未実行で失効する仕様 日次トリガーで継続実行 / 失効時は再OAuth認証
レポートが空 date range / fields指定ミス YESTERDAY以外を試す・fields名を公式と照合
CSV文字化け reportDownloadEncode未指定 reportDownloadEncode: "UTF8"を明示
完了待ちタイムアウト 大規模アカウントでレポート生成が長い Utilities.sleep間隔を伸ばす / 回数を増やす

「401 Unauthorized」が出る → access_token期限切れ

最も多い原因はaccess_tokenの有効期限が1時間であることです。本記事のコードのように毎回refresh_tokenからaccess_tokenを再発行する設計なら、この問題は発生しません。それでも401が出る場合はclient_id / client_secret / accountIdの記述ミス、もしくはAPI利用申請が未承認のケースを疑ってください。

refresh_token が突然無効になる → 長期未利用時の失効仕様

Yahoo!広告APIのrefresh_tokenは長期間APIを叩かないと失効する仕様です(最新の有効期限は公式ドキュメントで必ず確認してください)。日次トリガーで動かしている限り実質失効しませんが、失効した場合はOAuth認証フローからやり直す必要があるため、運用停止する案件では「定期的な動作確認」を運用ルールにしておくと安全です。

レポートが空 → ReportDefinition の date range とフィールド指定ミス

取得結果が空配列になる場合、reportDateRangeType: "YESTERDAY"でその日にデータがないケースがほとんどです。"LAST_7_DAYS"に切り替えて期間を広げ、それでも空ならfields名を公式リファレンスと照合してください。

CSVが文字化け → Shift_JISからUTF-8への変換

レポート定義でreportDownloadEncode: "UTF8"を明示指定するのが最も確実です。古い実装でShift_JISのCSVを扱う場合は、Utilities.parseCsv(Utilities.newBlob(response.getContent()).getDataAsString("Shift_JIS"))のように明示的に文字コード指定して読み込んでください。

レポート生成完了待ちでタイムアウト → ポーリング間隔とUtilities.sleep

大規模アカウントだとレポート生成に2分以上かかることがあります。本記事のコードは10秒×12回 = 最大2分でタイムアウトする実装ですが、必要に応じてfor (let i = 0; i < 30; i++)に増やすか、Utilities.sleep(15000)に間隔を伸ばしてください。なおGASは1実行あたり6分の制限があるため、それを超える場合はレポート作成と取得をトリガー分割します。

取得できる主な指標とレポート種類

Yahoo!広告APIでは、reportTypefieldsの組み合わせで取得対象のレポート種類と指標を柔軟に切り替えられます。本記事サンプルはキャンペーン別ですが、用途に応じて変更してください。

アカウント別 / キャンペーン別 / 広告グループ別 / キーワード別

reportTypeの値を変えることで、集計粒度を切り替えられます。

  • ACCOUNT:アカウントサマリ
  • CAMPAIGN:キャンペーン別(本記事サンプル)
  • ADGROUP:広告グループ別
  • AD:広告別
  • KEYWORDS:キーワード別(検索クエリ含む)

主な集計指標(IMP・クリック・コスト・CV・CPA・ROAS)

fieldsに指定できる主要メトリクスは以下です。詳細は公式リファレンスを参照してください。

  • IMPS(インプレッション)/ CLICKS(クリック)/ CLICK_RATE(CTR)
  • COST(コスト)/ AVG_CPC(平均CPC)
  • CONVERSIONS(CV数)/ CONV_RATE(CVR)/ CONV_VALUE(CV価値)
  • VIDEO_PLAYS(動画再生)/ ASSISTED_IMP(アシストIMP)など

応用:Google広告データと並べてダッシュボード化する

Yahoo!広告データの自動取得が完成したら、次は他媒体と統合した運用ダッシュボードに発展させましょう。スプレッドシートをハブにすれば、追加コストなしで媒体横断レポートやLooker Studio連携まで広げられます。

スプレッドシート関数で前日比・前週比を可視化

「db」シートに蓄積したデータを別シートでQUERY関数やSUMIFSでピボットすれば、媒体横断レポートを自動更新できます。Yahoo!広告のデータと並行して【GAS】Google広告の運用データをスプレッドシートに自動取得する方法で取得したGoogle広告データを同一シートにまとめれば、媒体横断の前日比・前週比が一目で見られます。

Looker Studio に接続して常時モニタリング

2026年5月時点でYahoo!広告にはLooker Studio公式コネクタが存在しないため、GAS+スプレッドシート経由が事実上の標準ルートです。スプシをLooker Studioのデータソースとして接続すれば、日次更新されるダッシュボードが追加コストなしで実現できます。【GAS】Google Analytics GA4のデータを取得すると組み合わせれば、広告データ × サイト計測データの統合レポートも作成可能です。

MCC配下の複数アカウントを一括取得する

MCCで複数広告主アカウントを管理している場合、targetAccountIdを配列でループ実行することで一括取得できます。考え方は【Google広告】MCCのすべてのアカウントから運用レポートを取得すると同様です。アカウントIDの一覧をスプレッドシートで管理し、main関数からループで回す実装が運用しやすいです。

✅ この記事のまとめ

  • Yahoo!広告API v19 + GASで、毎日のレポート取得を完全自動化できる
  • access_tokenは1時間で失効するため、毎回refresh_tokenから再発行する設計が必須
  • refresh_tokenは長期間未利用で失効する仕様だが、日次トリガー運用なら実質失効しない
  • 認証情報はスクリプトプロパティで管理し、コードにベタ書きしない
  • レポート完了待ちはUtilities.sleepでポーリングし、最大2〜3分のタイムアウトを設ける
  • 2026年5月時点でLooker Studio公式コネクタはないため、スプシ経由が標準ルート

よくある質問

Q1. GASでYahoo広告のAPIを叩くのに料金はかかりますか?

Yahoo!広告API自体の利用料は無料ですが、API利用申請の承認が必要です。GASも個人利用範囲なら無料ですが、1実行6分の制限トリガー実行上限90分/日があるため、大規模アカウントでは分割実行を検討してください。

Q2. refresh_token はどれくらいの期間有効ですか?

Yahoo!広告APIのrefresh_tokenは長期間APIを叩かないと無効化される仕様になっています(最新の有効期限は公式ドキュメントで必ず確認してください)。日次トリガーで自動取得する運用であれば実質失効しません。失効した場合は再度OAuth認証フローからやり直す必要があります。

Q3. 「401 Unauthorized」エラーが出るのはなぜですか?

最も多い原因はaccess_tokenの期限切れ(有効期限1時間)です。GASコード側で毎回refresh_tokenからaccess_tokenを再発行する実装にしておくと回避できます。それでも出る場合はclient_idやaccountIdの記載ミス、もしくはAPI利用申請が未承認のケースを疑ってください。

Q4. Google広告のように公式コネクタはありますか?

2026年5月時点でYahoo!広告にはLooker StudioやGoogle スプレッドシート用の公式コネクタはありません。GAS + Yahoo!広告APIの自前実装か、サードパーティ有料コネクタ(例: Supermetrics等)が現実的な選択肢です。本記事の実装なら無料で同等のことが実現できます。

Q5. 取得したデータをLooker Studioで可視化するにはどうすればよいですか?

GASでスプレッドシートに書き込んだ後、Looker Studioのデータソースとして「Google スプレッドシート」を選択して接続するのが最短です。日次更新されるスプシをそのままデータソースにすれば、追加のETL不要で運用レポートを自動更新できます。