どのやり方で自動化するか(30秒で選ぶ) 先に結論です。Xの自動化手段は大きく3つで、Google広告のBigQuery Data Transferのような「無料の公式転送」にあたるものはありません。
X Ads Managerの手動エクスポート
難易度: ★☆☆(画面操作のみ) 出力先: CSV(手動ダウンロード) 費用: 無料 弱点: 自動配信・自動蓄積はできない コネクタ/ETLツール
難易度: ★★☆(画面設定+SQL) 出力先: BigQuery・Looker Studio等 費用: ツール月額(有料) 弱点: X公式のLooker Studioコネクタは無い Ads API 直連携(非同期レポート)
難易度: ★★★(申請+OAuth 1.0a実装) 出力先: 自由(スプシ/DB/BI)。承認後のAPI利用は無料 弱点: 申請の審査期間が読みにくく、認証方式もOAuth 1.0aと独特 X広告(旧Twitter)レポート自動化の3つのやり方。無料の公式転送・公式コネクタが無いため、自動蓄積させるならツールかAds API直連携になる 月次でまとめて見られれば十分 → やり方1(手動エクスポート) 実装せずにBigQueryやBIへ流したい → やり方2(コネクタ・ETLツール) 無料で完結させたい・独自の集計や自動配信まで組みたい → やり方3(Ads API直連携) 手動エクスポートとAds API直連携の間を埋める「アカウント内蔵スクリプト」のような公式の中間手段が無いのもXの特徴です。コードを書かずに済ませたいなら、最初からツール前提で考えたほうが早くなります。
やり方1: X Ads Managerで手動エクスポートする(無料) X Ads Manager(ads.x.com)のアナリティクス画面では、期間・キャンペーンやライン単位の実績をCSVでダウンロードできます。画面に表示されている指標をそのまま書き出すだけなので、追加の申請や設定は不要です。
ただし、Google広告マネージャやMeta広告マネージャにあるような定期メール配信の機能があるかどうかは、2026年8月時点のマニュアル上で確認が取れていません。届いたCSVをスプレッドシートに転記する運用は変わらず、月次でまとめて見る程度の頻度ならこれで足りますが、日次で自動配信・自動蓄積したい場合はやり方2かやり方3に進む必要があります。
やり方2: コネクタ・ETLツールでBigQueryやBIへ流す 実装せずにBigQueryやLooker Studioへデータを流したい場合は、有料のコネクタ・ETLツールを使う方法があります。複数媒体をまとめて扱うパートナーコネクタやETLツールの中には、Twitter広告(X広告)向けのコネクタを提供しているサービスもあります。
こうしたツールの対価は、後述するAds APIのOAuth 1.0a認証や非同期ジョブのポーリングといった実装を、ツール側が肩代わりしてくれることです。自社で保守するコードを持ちたくない場合は、まずツールで足りるかを検討するのが現実的です。ツールごとの料金・対応媒体の比較は広告レポート自動化ツール比較|主要9ツールの料金・対応媒体・選び方 にまとめています。
やり方3: Ads APIで自由に取得する 無料で完結させたい、あるいは自社システムに組み込みたいなら、X Ads APIの直連携です。公式には「X Ads API for campaign, audience, and creative management」という名称で、旧Twitter Ads APIから呼び方が変わっただけで、実体は同じ系譜のAPIです。ここが今回の本題なので、順を追って説明します。
手順1: デベロッパーアカウント登録とAppを作成する X Ads APIに専用の申し込みポータルはなく、入口は一般のX APIと共通のDeveloper Portal(開発者ポータル)です。まずここでデベロッパーアカウントとAppを作ります。
進める前に、この記事の前提を3つ確認してください。
認証済みのXアカウント : 電話番号とメールアドレスの認証が済んでいること。未認証だとデベロッパー登録フローの途中で弾かれます稼働中のX Adsアカウント : 自社またはクライアントの広告アカウント(approval_status が ACCEPTED)があることPython 3.9以降の実行環境 : 手順5以降のスクリプト実行に使います※以下、画面のボタン名・メニュー名は2026年8月時点で一般的な表記です。UIの更新で表記や配置が変わる場合があります。
1-1. デベロッパーアカウントを登録する
ブラウザで https://developer.x.com/en/portal/dashboard を開きます
広告アカウントを管理しているXアカウント (または連携専用に用意した運用アカウント)でログインします。後で発行するAccess Tokenは「ここでログインしたユーザー」に紐づくため、担当者の個人アカウントでログインすると、退職時にパイプラインごと止まるリスクがあります
初回はプラン選択画面が表示されるので、無料の「Free」プランの「Sign up for Free Account」をクリックします
利用目的の入力欄(「Describe all of your use cases of X’s data and API」といった表記)に、英語で250文字以上 の利用目的を入力します。次の例文を社名・用途だけ書き換えて使えます
We plan to use the X Ads API to automatically download daily
performance reports (impressions, clicks, spend, and conversions)
for the X Ads accounts that our company manages. The retrieved data
will be stored in our internal data warehouse and used only for
internal reporting and analysis. We will not display X content
publicly, resell any data, or build a consumer-facing product. 「Developer agreement & policy」への同意にチェックを入れ、「Submit」をクリックします
完了確認 : Developer Portalのダッシュボード画面(左にサイドバーが並ぶ管理画面)が表示されれば登録完了です。確認メールが届いた場合は、メール内のリンクをクリックして認証を済ませておきます
1-2. Appを作成する
ダッシュボード左サイドバーの「Projects & Apps」→「Overview」をクリックします Freeプランでは、登録時にデフォルトのProjectとAppが1つ自動作成されています。それを使っても構いませんが、新しく作る場合は「+ Add App」(または「Create App」)ボタンをクリックします 「App name」に任意の名前を入力します(例: mycompany-ads-report-2026)。App名は全開発者間で一意 である必要があり、重複すると「That App name is already taken」のようなエラーになります。社名や年号を含めると通りやすくなります 「Next」をクリックします(環境の選択肢が出る場合は「Production」を選択して進めます) 作成直後の画面に「API Key」「API Key Secret」「Bearer Token」の3つが表示されます。この画面は一度閉じると二度と再表示できません (後からできるのは「Regenerate」による再生成のみで、再生成すると古いキーは即座に無効になります)。3つとも「Copy」ボタンでコピーし、パスワードマネージャーなど安全な場所に保存してください 保存し終えたら「App settings」をクリックしてAppの設定画面に進みます 1-3. App IDを控える
左サイドバーの「Projects & Apps」→「Overview」→ 作成したApp名の順にクリックします 「Settings」タブの上部に表示されている数字のID(例: 29881364)がApp ID です。手順3のAds API申請でこの数字を使うので控えておきます 手順2: Keys and tokensを発行する Ads APIのOAuth 1.0a認証に必要なのは、①API Key(Consumer Key)②API Key Secret(Consumer Secret)③Access Token ④Access Token Secret の4つです。手順1-2で保存したBearer Tokenは一般のX API v2用で、Ads APIでは使いません 。
2-1. User authentication settingsを設定する
Appのユーザー認証を設定しないと、Access Tokenが権限Read Only(読み取りのみ)で発行されます。レポート取得でも非同期ジョブの作成はPOSTリクエストになるため、先にRead and Writeへ変更しておきます 。
「Projects & Apps」→「Overview」→ 対象のApp名をクリックし、「Settings」タブを開きます ページ下部の「User authentication settings」欄にある「Set up」ボタン(設定済みの場合は「Edit」)をクリックします 「App permissions」で「Read and write」を選択します 「Type of App」で「Web App, Automated App or Bot」を選択します 「App info」の必須項目を入力します。サーバーで定期実行するだけならこれらのURLが実際に呼ばれることはありませんが、入力は必須です「Callback URI / Redirect URL」: http://localhost と入力します 「Website URL」: 自社サイトのURL(例: https://www.example.co.jp)を入力します 「Save」をクリックします。OAuth 2.0用の「Client ID」「Client Secret」が表示されることがありますが、これもAds APIでは使わないため、控えるだけで先に進んで問題ありません 完了確認 : Settingsタブに戻り、「User authentication settings」欄が「Set up」ボタンから設定内容の表示(「Edit」ボタン付き)に変わっていれば完了です2-2. Access TokenとAccess Token Secretを生成する
対象のAppの画面で、「Settings」の隣にある「Keys and tokens」タブ(鍵のアイコン)をクリックします 「Authentication Tokens」欄の「Access Token and Secret」の「Generate」ボタンをクリックします。2-1より前に生成済みの場合は「Regenerate」で作り直します(権限の変更は、トークンを再生成するまで反映されません ) 表示された「Access Token」「Access Token Secret」を「Copy」でコピーして保存します。この画面も一度しか表示されません 完了確認 : 「Access Token and Secret」の見出しの下に「Created with Read and Write permissions」と表示されていれば成功です。「Read Only」のままなら、2-1を保存し直してから「Regenerate」してください「Consumer Keys」欄の「API Key and Secret」は手順1-2で保存したものと同一で、紛失した場合はここの「Regenerate」で再生成できます(古いキーは即無効になります)。
この時点で、次の4つが手元に揃っていることを確認してください。
値 OAuth 1.0aでの呼び名 取得場所 API Key Consumer Key App作成直後の画面/「Keys and tokens」→「Consumer Keys」 API Key Secret Consumer Secret 同上 Access Token OAuth Token 「Keys and tokens」→「Authentication Tokens」 Access Token Secret OAuth Token Secret 同上
このAccess Tokenは「Developer Portalにログインしていた@ユーザー」の代理として動くトークンです。そのため、その@ユーザー自身が対象のAdsアカウントへのアクセス権を持っている必要があります (他社アカウントを扱う場合の権限付与は手順4で行います)。4つの値は、疎通確認や検証の間はこの後のスクリプトのように直書きでも構いませんが、cronなどの定期実行に載せる前に.envファイルや環境変数・シークレット管理サービスへ移してください。
Appを作っただけではAds APIは呼べません。App IDごとに 申請して承認を受ける必要があります。
ブラウザで https://developer.x.com/en/docs/x-ads-api/apply を開きます(docs.x.comのX Ads APIドキュメントの「Getting Started」ページからも「apply」「Ads API Access」といった表記のリンクで辿れます)
ページ内の申請フォームへのリンク(「Ads API Access Form」などの表記)をクリックします
フォームの各項目を入力します。項目名・順序は変わる可能性がありますが、おおむね次の内容を聞かれます
App ID : 手順1-3で控えた数字のID(@ユーザー名やApp名ではなく、数字のIDです)
会社名・担当者名・連絡先メールアドレス : 承認連絡が届くアドレスなので、受信できるものを入力します
利用目的(英語) : どのエンドポイントで何をするかを具体的に書きます。例文:
We would like to programmatically retrieve daily analytics reports
(impressions, clicks, spend, and conversions) for the X Ads accounts
our company manages, using the asynchronous analytics endpoints
(POST /12/stats/jobs/accounts/:account_id). The data will be used
for internal reporting only. 必要なアクセスレベル : 「Standard Access」を選択します(理由は下表)
送信します。受付・承認の連絡はデベロッパーアカウントのメールアドレス宛に届きます
完了確認 : 承認されると、対象のAppでAds APIの本番エンドポイント(https://ads-api.x.com)が呼べるようになります。手順5の疎通確認で GET /12/accounts が200を返せば承認済み、403が返る間は未承認です
アクセスレベル 内容 Conversion Only コンバージョン計測用途に限定したアクセス Standard Access Analytics・Campaign Management・Creatives・Custom Audiences・Conversion系エンドポイントへの読み書きを含む、フルセットのアクセス
レポート自動化が目的なら、Analyticsエンドポイントを含むStandard Access が前提になります。
審査期間について、公式は「最大3営業日」を掲げてきました(現行の申請ページでの記載は変わっている可能性があります)。一方、開発者コミュニティ(devcommunity.x.com)には数週間〜数ヶ月かかったという報告が多数あり、公式SLAと実際の体感には大きな開きがあります。また、コミュニティ報告ベースの情報ですが、以前使われていた申請用のGoogleフォームは無効化され、営業担当経由の新しい申請フローに移行したようです。申請前に、developer.x.com/en/docs/x-ads-api/apply の最新のページで導線が変わっていないか確認しておくと安全です。
なお、審査待ちの間もサンドボックス環境(ベースURLを https://ads-api-sandbox.x.com に差し替えたもの)は通常のデベロッパーアカウントで利用できるとされています。承認を待ちながら、手順5以降の実装をサンドボックスで先に進めておくと、承認後すぐ本番に切り替えられます。
手順4: 広告主のAdsアカウントへのアクセス権を得る 自社のAdsアカウントを、その管理者アカウントで手順1〜2を進めた場合は、このステップは不要です (ログインユーザー自身がすでにアクセス権を持っているため)。手順5に進んでください。
他社(クライアント)のAdsアカウントを扱う場合や、手順2のAccess Tokenを発行した@ユーザーが広告アカウントの管理者と別の場合は、広告主側の管理者 に次の操作をしてもらいます。
※画面の表記・メニュー位置はUIの更新で変わる場合があります。business.x.comの「ビジネス設定」経由で同等の画面に辿れる構成になっていることもあります。
広告主の管理者が https://ads.x.com を開き、対象のAdsアカウントのAccount administrator権限を持つXアカウント でログインします 画面右上のアカウント名(@ユーザー名)をクリックしてメニューを開きます メニュー内の「アカウントへのアクセスを編集(Edit access to account)」をクリックします。現在アクセス権を持つユーザーの一覧画面が開きます 「アカウントへのアクセスを許可(Grant account access)」ボタンをクリックします 「ユーザー名(Username)」欄に、手順2でAccess Tokenを発行したデベロッパー側の@ユーザー名 を入力します 「役割(Role)」でロールを選択します。レポート取得だけなら「キャンペーンアナリスト(Campaign analyst)」で足ります。キャンペーンの作成・編集まで任せる場合は「広告マネージャー(Ad manager)」を選びます 「変更を保存(Save changes)」をクリックします 完了確認 : アクセス一覧にデベロッパー側の@ユーザー名と役割が表示されていれば付与完了です。以降、手順5の GET /12/accounts のレスポンスにこのAdsアカウントが含まれるようになります役割(Role) できること Account administrator(アカウント管理者) アクセス権の管理を含むすべての操作 Ad manager(広告マネージャー) キャンペーンの作成・編集、レポート閲覧 Creative manager(クリエイティブマネージャー) クリエイティブの管理・プレビュー Campaign analyst(キャンペーンアナリスト) キャンペーンとレポートの閲覧(レポート自動化はここで十分 ) Organic analyst(オーガニックアナリスト) オーガニック投稿のアナリティクス閲覧のみ
認証はどちらの構成でも共通して**OAuth 1.0a(3-legged OAuth)**です(冒頭で触れたとおり、OAuth 2.0・Bearer Token中心のX API v2とは認証方式が異なります)。
手順5: 疎通確認する 取得した4つの認証情報で GET /12/accounts(アクセス可能なAdsアカウントの一覧)を呼び、認証と承認が通っているかを確認します。
5-1. 実行環境を準備する
Python 3.9以降が入っている環境で、ターミナル(macOSはターミナル.app、WindowsはPowerShell)を開き、次のコマンドを実行してライブラリをインストールします。
pip install requests requests-oauthlib pip でコマンドが見つからない場合は pip3 に、以降の python は python3 に読み替えてください(macOSに多いパターンです)。
5-2. 疎通確認スクリプトを実行する
以下を check_connection.py という名前で保存します。冒頭の4つの値だけ、手順2で保存した自分の認証情報に書き換えてください。
import requests
from requests_oauthlib import OAuth1
# ===== 手順2で取得した4つの値に書き換える =====
CONSUMER_KEY = "ここにAPI Keyを貼る"
CONSUMER_SECRET = "ここにAPI Key Secretを貼る"
ACCESS_TOKEN = "ここにAccess Tokenを貼る"
ACCESS_TOKEN_SECRET = "ここにAccess Token Secretを貼る"
# ==========================================
auth = OAuth1( CONSUMER_KEY , CONSUMER_SECRET , ACCESS_TOKEN , ACCESS_TOKEN_SECRET )
resp = requests.get( "https://ads-api.x.com/12/accounts" , auth = auth, timeout = 30 )
print ( "HTTPステータス:" , resp.status_code)
print (resp.json()) 保存したら、ターミナルで次を実行します。
python check_connection.py 5-3. 結果を確認する
成功時は HTTPステータス: 200 に続いてJSONが表示されます。実際のレスポンスには次の例以外のフィールド(request や next_cursor など)も含まれますが、data 配列の中に id を持つアカウントが表示されていれば成功 です。
{
"data" : [
{
"id" : "18ce54d4x5t" ,
"name" : "株式会社サンプル" ,
"timezone" : "Asia/Tokyo" ,
"approval_status" : "ACCEPTED"
}
],
"total_count" : 1
} この data[].id(英数字のID。例: 18ce54d4x5t)が、以降のレポート取得で使う**アカウントID(account_id)**です。控えておいてください。
エラーになった場合の切り分けは次のとおりです。
ステータス 主な原因 対処 401 認証情報4つのいずれかが間違っている/コピー時に空白が混入 手順2の値を貼り直す。直らなければ「Keys and tokens」でRegenerateして新しい値で試す 403 AppがまだAds API未承認 手順3の審査結果を待つ。サンドボックス(ads-api-sandbox.x.com)で先に実装を進める 404 URLのパス間違い(バージョン番号の欠落など) https://ads-api.x.com/12/accounts になっているか確認する。APIバージョン(本記事は2026年8月時点の /12)が更新されていないかもdocs.x.comで確認する200だが data が空 ログインユーザーがどのAdsアカウントのアクセス権も持っていない 手順4の権限付与を実施する
レポート取得: 同期と非同期の2方式 疎通確認が済んだら、レポート取得です。X Ads APIのレポート取得には同期・非同期の2方式があり、定期的な自動化には非同期方式が前提になります。
項目 同期(GET /12/stats/accounts/:account_id) 非同期(POST /12/stats/jobs/accounts/:account_id ほか) 取得期間 最大7日間 最大90日間(非セグメント)/45日間(セグメント化) セグメンテーション 非対応 対応(AGE・GENDER・METROSなど) レート制限 User-level 250リクエスト/15分 Account-level 同時実行100ジョブまで 向いている用途 リアルタイム寄りの短期確認 定期レポートの自動取得
非同期方式は「ジョブ作成→ポーリング→ダウンロード」の3ステップです。まず各ステップのパラメータを押さえ、その後にコピペで動く完全なスクリプトを示します。
ステップ0: 対象のキャンペーンIDを取得する
ジョブ作成には対象エンティティのIDが必要です。キャンペーン単位なら GET /12/accounts/:account_id/campaigns で一覧を取得し、レスポンスの data[].id を控えます(下の完全版スクリプトでは、この取得も自動化しています)。
ステップ1: POST /12/stats/jobs/accounts/:account_id でジョブを作成する
主なパラメータは次のとおりです。
パラメータ 指定する値 例 entity集計単位。CAMPAIGN・LINE_ITEM・PROMOTED_TWEETなど CAMPAIGNentity_ids対象IDをカンマ区切りで最大20件 abc12,def34start_time / end_timeISO 8601形式。広告アカウントのタイムゾーンの0時 (日本のアカウントなら+09:00の0時)に揃えることが必須。揃っていないと400エラーまたは日別集計の日付ズレの原因になる。end_timeは終了日の翌日0時を指定(この時刻自体は含まれない) 2026-07-01T00:00:00+09:00granularity集計粒度。DAY(日別)・HOUR(時間別)・TOTAL(期間合計) DAYmetric_groups取得する指標グループをカンマ区切りで。ENGAGEMENT(表示・クリック系)・BILLING(費用)・WEB_CONVERSION(CV)など ENGAGEMENT,BILLINGplacement配信面。1リクエストにつき1つのみ 。ALL_ON_TWITTER(X上)・PUBLISHER_NETWORK(外部ネットワーク)など ALL_ON_TWITTERsegmentation_type(任意)セグメント分割。AGE・GENDER・METROSなど。指定時は取得期間上限が45日になる GENDER
成功すると201が返り、レスポンスの data.id がジョブIDです。
ステップ2: GET /12/stats/jobs/accounts/:account_id?job_ids=<ジョブID> を一定間隔でポーリングする
レスポンスの data[].status が PROCESSING の間は待ち、SUCCESS になったら data[].url に結果ファイルのダウンロードURLが入ります。FAILED ならパラメータを見直して再作成します。
ステップ3: URLから結果ファイルをダウンロードして解凍する
結果ファイルはgzip圧縮されたJSON です(拡張子は .json.gz 相当)。zipではないので、Pythonならgzipモジュールで解凍します。JSONの中身は、エンティティごとに指標名→日別の値の配列という構造で返ります。
以下がコピペで動く完全版スクリプトです。事前に手順5-1と同じく pip install requests requests-oauthlib を済ませ、fetch_x_ads_report.py として保存し、冒頭の認証情報4つとアカウントIDを書き換えて python fetch_x_ads_report.py で実行します。実行するとキャンペーン別×日別の実績が x_ads_report.csv に書き出されます。
"""X Ads API 非同期レポート取得スクリプト
実行前に: pip install requests requests-oauthlib
実行方法: python fetch_x_ads_report.py
出力: カレントディレクトリに x_ads_report.csv
"""
import csv
import gzip
import json
import sys
import time
from datetime import date, timedelta
import requests
from requests_oauthlib import OAuth1
# ===== 手順2で取得した4つの値と、手順5で確認したアカウントIDに書き換える =====
CONSUMER_KEY = "ここにAPI Keyを貼る"
CONSUMER_SECRET = "ここにAPI Key Secretを貼る"
ACCESS_TOKEN = "ここにAccess Tokenを貼る"
ACCESS_TOKEN_SECRET = "ここにAccess Token Secretを貼る"
ACCOUNT_ID = "ここにアカウントIDを貼る" # 例: "18ce54d4x5t"
# 広告アカウントのタイムゾーンのUTCオフセット。手順5のレスポンスのtimezoneに
# 合わせる(Asia/Tokyoなら"+09:00"のまま)。ズレると400エラーや日付ズレの原因になる
TIMEZONE_OFFSET = "+09:00"
# ==========================================================================
# 取得期間: 昨日までの直近30日分(end_timeは「終了日の翌日0時」を指定する)
DAYS = 30
end_date = date.today() # 今日の0時 = 昨日分までが対象
start_date = end_date - timedelta( days = DAYS )
auth = OAuth1( CONSUMER_KEY , CONSUMER_SECRET , ACCESS_TOKEN , ACCESS_TOKEN_SECRET )
BASE = "https://ads-api.x.com/12"
def api_request (method: str , url: str , * , max_retries: int = 5 , ** kwargs):
"""429/503を指数バックオフでリトライしながらリクエストする"""
for attempt in range (max_retries):
resp = requests.request(method, url, auth = auth, timeout = 60 , ** kwargs)
if resp.status_code in ( 429 , 503 ):
wait = 2 ** attempt * 15 # 15秒, 30秒, 60秒...
print ( f " { resp.status_code } が返りました。 { wait } 秒待って再試行します" )
print ( f " レスポンスヘッダー: {dict (resp.headers) } " ) # 原因切り分け用
time.sleep(wait)
continue
if resp.status_code >= 400 :
print ( f "エラー: HTTP { resp.status_code } " , file = sys.stderr)
print (resp.text, file = sys.stderr)
resp.raise_for_status()
return resp.json()
raise RuntimeError ( "リトライ上限に達しました" )
# ステップ0: アクティブなキャンペーンIDを取得する(最大20件/ジョブ)
campaigns = api_request(
"GET" ,
f " {BASE} /accounts/ {ACCOUNT_ID} /campaigns" ,
params = { "count" : 20 , "with_deleted" : "false" },
)
campaign_ids = [c[ "id" ] for c in campaigns[ "data" ]]
campaign_names = {c[ "id" ]: c[ "name" ] for c in campaigns[ "data" ]}
if not campaign_ids:
sys.exit( "キャンペーンが見つかりませんでした" )
if campaigns.get( "next_cursor" ):
print ( "注意: キャンペーンが20件を超えています。このスクリプトは先頭20件のみ取得します" )
print ( f "対象キャンペーン: {len (campaign_ids) } 件" )
# ステップ1: 非同期ジョブを作成する
job = api_request(
"POST" ,
f " {BASE} /stats/jobs/accounts/ {ACCOUNT_ID} " ,
data = {
"entity" : "CAMPAIGN" ,
"entity_ids" : "," .join(campaign_ids),
# アカウントのタイムゾーンの0時に揃える(必須)
"start_time" : f " { start_date.isoformat() } T00:00:00 {TIMEZONE_OFFSET} " ,
"end_time" : f " { end_date.isoformat() } T00:00:00 {TIMEZONE_OFFSET} " ,
"granularity" : "DAY" ,
"metric_groups" : "ENGAGEMENT,BILLING" ,
"placement" : "ALL_ON_TWITTER" ,
},
)
job_id = job[ "data" ][ "id" ]
print ( f "ジョブを作成しました: { job_id } " )
# ステップ2: 完了までポーリングする(30秒間隔・最大30分)
download_url = None
for _ in range ( 60 ):
status = api_request(
"GET" ,
f " {BASE} /stats/jobs/accounts/ {ACCOUNT_ID} " ,
params = { "job_ids" : job_id},
)
current = status[ "data" ][ 0 ]
if current[ "status" ] == "SUCCESS" :
download_url = current[ "url" ]
break
if current[ "status" ] == "FAILED" :
raise RuntimeError ( f "ジョブが失敗しました: { current } " )
print ( " 処理中..." )
time.sleep( 30 )
if download_url is None :
raise RuntimeError ( "30分待ってもジョブが完了しませんでした" )
# ステップ3: 結果(gzip圧縮されたJSON)をダウンロードして解凍する
# ダウンロードURL自体は認証不要の一時URLのため、authは付けない
raw = requests.get(download_url, timeout = 120 )
raw.raise_for_status()
if raw.content[: 2 ] == b " \x1f\x8b " : # gzipのマジックナンバーを確認
payload = gzip.decompress(raw.content)
else :
payload = raw.content # ライブラリ側で解凍済みの場合はそのまま使う
report = json.loads(payload)
# 日別×キャンペーン別のCSVに整形する
# レスポンスは data[].id (キャンペーンID) ごとに、指標名→日別配列の形で入っている
dates = [
(start_date + timedelta( days = i)).isoformat()
for i in range ((end_date - start_date).days)
]
with open ( "x_ads_report.csv" , "w" , newline = "" , encoding = "utf-8" ) as f:
writer = csv.writer(f)
# spendはアカウントの通貨単位(日本のアカウントなら円)
writer.writerow([ "date" , "campaign_id" , "campaign_name" ,
"impressions" , "clicks" , "engagements" , "spend" ])
for row in report[ "data" ]:
cid = row[ "id" ]
metrics = row[ "id_data" ][ 0 ][ "metrics" ]
impressions = metrics.get( "impressions" ) or [ 0 ] * len (dates)
clicks = metrics.get( "clicks" ) or [ 0 ] * len (dates)
engagements = metrics.get( "engagements" ) or [ 0 ] * len (dates)
# 費用はマイクロ単位(実額 × 1,000,000)・アカウント通貨建てで返るため換算する
spend_micro = metrics.get( "billed_charge_local_micro" ) or [ 0 ] * len (dates)
for i, d in enumerate (dates):
writer.writerow([
d, cid, campaign_names.get(cid, "" ),
impressions[i], clicks[i], engagements[i],
spend_micro[i] / 1_000_000 ,
])
print ( f "完了: x_ads_report.csv に {len (report[ 'data' ]) } キャンペーン× {len (dates) } 日分を書き出しました" ) 実行して 完了: x_ads_report.csv に ... と表示されれば成功です。あとはこのスクリプトをcronやCloud Runなどの定期実行に載せ、CSVの出力先をスプレッドシートやBigQueryへの書き込みに差し替えれば、日次の自動取得が完成します。
いくつか補足します。まず start_time/end_time は、アカウントのタイムゾーン(手順5のレスポンスの timezone)の0時に揃えることが必須 です。日本のアカウントにUTCの Z(=JST 9:00)を指定すると、時刻アライメントのエラーで400が返るか、日別集計が9時間ズレてAds Managerの画面と一致しなくなります。上のスクリプトでは冒頭の TIMEZONE_OFFSET で指定しているので、Asia/Tokyo 以外のアカウントを扱う場合はここを書き換えてください。費用系の指標(billed_charge_local_micro)はマイクロ単位 (100万分の1)かつアカウントの通貨建て で返ります(日本のアカウントなら円)。entity_ids は1ジョブ最大20件なので、キャンペーンが20件を超える場合は20件ずつ複数ジョブに分割します(同時実行はAccount-levelで100ジョブまで。上のスクリプトは先頭20件のみ取得し、超過時は警告を表示します)。また placement=ALL_ON_TWITTER はX上の配信のみの集計のため、外部ネットワーク(PUBLISHER_NETWORK)にも配信している場合は、placementを変えたジョブをもう1本実行して合算してください。画面の合計と数字が合わないときは、まずこのplacementとタイムゾーンを疑うのが近道です。
注意したいのは、429(レート超過)や503のエラーがコミュニティ上で多く報告されていることです。通常のレート制限はX-Rate-Limit-Limit/X-Rate-Limit-Remaining/X-Rate-Limit-Resetヘッダーで返る一方、429時にはx-cost-rate-limit-reset、503時にはretry-afterという別系統のヘッダーが使われており、リトライ実装を組む際にどちらを見ればいいのか混乱しやすいという指摘があります。まずは単純なリトライ+指数バックオフで動かし、エラーが頻発するようならレスポンスヘッダーの中身をログに出して原因を切り分けるのが安全です。
料金・アクセスレベルの現状整理 Ads API自体は、承認済みのX APIデベロッパーには追加費用なしで提供される、というのが2023年のティア再編時からの公式の位置づけです。2026年2月以降に一般のX API(投稿・読み取り)が従量課金へ移行した後も、Ads APIはこの無料の位置づけを維持していると報じられています。ただしAds API単体の公式料金ページはdocs.x.com上で確認できておらず、この点は確度中程度の情報として扱ってください。
混同しやすいのが、一般のX API(投稿やタイムライン取得など)の料金体系です。報道・コミュニティ情報を含む二次情報のため金額は目安ですが、2026年2月以降、新規登録はデフォルトで従量課金になり、投稿作成が1件0.015ドル、リンク付き投稿が1件0.20ドル、読み取りが1件0.005ドル(月200万件が上限)という水準が案内されています。レガシーのBasic(月200ドル)・Pro(月5,000ドル)プランは新規受付を終了し、Enterpriseは月額42,000ドル程度からと報じられています。金額や時期は変わる可能性があるため、見積もりの前に公式の料金ページで最新の数字を確認してください。Ads APIの承認を得るには通常のX APIデベロッパーアカウント登録が前提になりますが、Ads API自体の利用課金とこの一般APIの従量課金は別枠です。見積もりや社内説明の際は、この2つを混同しないよう注意してください。
なおアクセス権限はConversion OnlyとStandard Accessの2種類ですが、未確認情報ながら、2023年7月以前に申請した古いAppには別のアクセス権限が適用され、紐づけられるOAuthトークンの数が5個までに制限されるケースがあるようです(拡張は別途申請で緩和できるとされています)。古いAppを引き継いで運用している場合は、新しい広告主のトークンを追加した際に権限エラーが出ないか、この上限に当たっていないかを確認してください。
集めたデータをAIにつなぐ:考察まで自動化する 非同期ジョブでデータが自動で集まるようになったら、分析もAIに任せられます。取得したJSON(またはCSVに変換したもの)を、キャンペーン別・日別に集計してからChatGPT・Gemini・Claudeに渡すのが基本です。
添付はX広告のキャンペーン別・日別実績(過去30日、ENGAGEMENT・BILLING集計)です。
1. エンゲージメント単価が悪化しているキャンペーンと、その要因の仮説
2. 予算の再配分案(増額すべき・減額すべきキャンペーン)
3. 今週チェックすべきポイント3つ
を、根拠となる数字を引用しながら簡潔にまとめてください。 BigQueryなどに蓄積している場合は、「非同期ジョブで前日分を取得→SQLで集計→生成AIのAPIに考察を生成させる→Slackやメールに配信」という日次パイプラインまで組めます。他媒体のシリーズ記事でも繰り返している点ですが、コツは同じです。生データを丸投げせず、集計してから渡す こと。非同期ジョブの結果ファイルには行数の多い生データが入っているため、AIに渡す前の集計が、考察の精度とAPI費用の両方に効いてきます。
こうしたAI分析・異常検知を既製で載せたい場合は、私たちのアドヨミAI のように、広告データのBigQuery集約とAI考察をセットで提供するサービスという選択肢もあります。
実務でハマる落とし穴5つ ここからは、実際に申請・実装して初めて分かりやすいポイントです。
1. 審査の体感期間が公式SLAと大きく違う 。手順3で触れたとおり、「最大3営業日」を前提にスケジュールを組むと計画が崩れがちです。レポート自動化を何かの締め切りに合わせて組む場合は、審査待ちが長期化する前提で余裕を持たせてください。
2. 認証方式が一般のX APIと違う 。X API v2用のBearer TokenでAds APIを呼ぶと、キー自体は正しくても401が返り続けます。一般的なX APIクライアントやサンプルコードを流用する場合は、認証部分をOAuth 1.0aの4つの値(Consumer Key/Secret+Access Token/Secret)による署名に置き換える必要があります。
3. 429/503のエラーとヘッダーの読み方に注意 。前述のとおり、通常時のレート制限ヘッダーと429・503時のヘッダーが別系統になっており、リトライ実装で混乱しやすい部分です。エラー発生時はステータスコードとヘッダーの両方をログに残しておくと、後から原因を追いやすくなります。
4. 旧Appのアクセス権限に注意 。2023年7月以前に申請したAppには異なるアクセス権限が適用され、OAuthトークンの数が5個までに制限されるケースがあるとの情報があります。長く運用しているAppを引き継ぐ場合は、この制限に当たっていないか確認してください。
5. 申請フォームの導線自体が変わりつつある 。以前使われていたGoogleフォームが無効化され、営業担当経由の新しいワークフローに移行しているとの報告があります。この記事の手順3で紹介した申請の入口は、公開時点で最新の情報に沿っていますが、実際に申請する前にdeveloper.x.comの該当ページを開いて、導線が変わっていないか目視で確認することをおすすめします。
シリーズで見てきた他媒体と比べると、Xは「入口の不確実性が突出して大きい」媒体です。Googleの開発者トークンやTikTokの開発者登録・アプリ審査は、審査があっても期間の見通しはある程度立ちます。対してXは、審査待ちの長期化(手順3参照)に加えて申請フローそのものの変更が続いており、スケジュールを引きにくいのが特徴です。
認証方式もXだけがOAuth 1.0aという古い仕様のままである点で、Meta広告のシステムユーザートークン やTikTokの無期限トークン とは実装の作法が変わります。非同期ジョブ+ポーリングという設計自体はYahoo!広告のレポート取得 とも近く、この形に慣れていれば実装そのものは応用が利きます。
1媒体だけの自動化であれば、この記事の手順を踏めば内製できます。つらくなるのは、審査待ちのスケジュール不確実性や認証方式の違いを、Google・Meta・TikTok・Xと媒体ごとに抱えたときです。外注する場合の費用相場は広告レポート自動化の費用は?ツール・代行の料金相場と選び方 にまとめています。BigQuery側の保存・クエリコストの考え方はBigQueryの料金体系とコスト削減|課金トラップと対策 を参照してください。
まとめ:入口の不確実性を織り込んで計画する X広告の自動化のやり方は3つ。手動エクスポート(無料)/コネクタ・ETLツール(有料)/Ads API直連携(承認後は無料) Ads APIの認証はOAuth 1.0a 。一般のX API v2(OAuth 2.0)とは別方式で、ドキュメントの流用に注意 申請はApp作成→Keys and tokens発行→Ads API Access Form申請→広告主のアクセス権付与→疎通確認 の5段階 審査待ちは長期化しやすい (手順3参照)。締め切りから逆算せず、余裕を持って申請する 定期レポートの自動取得は非同期ジョブ方式 (ジョブ作成→ポーリング→gzipダウンロード)が前提。最大90日間(非セグメント)取得できる 429/503のエラーとレート制限ヘッダーの系統の違いに注意。リトライ設計は余裕を持って組む 料金はAds API自体は承認済み開発者に無料の位置づけ。一般X APIの従量課金と混同しない 集めたデータはAIにつないで考察まで自動化 できる。コツは生データを渡さず集計してから渡すこと まずはApp作成とKeys and tokensの発行だけでも先に済ませ、Access Formの審査待ちの間に実装を進めておくと、承認後すぐにレポート自動化を動かせます。
複数媒体の広告レポート自動化はEvastへ 株式会社EvastのアドヨミAI は、Google・Yahoo!・Meta・TikTok・Xなど主要媒体の広告データをAPIで自動連携し、自社所有のBigQueryに集約する半スクラッチ型の広告レポート自動化・AI分析サービス です。
「Xの申請の審査待ちや認証方式の違いに、これ以上工数を割きたくない」 「媒体ごとに違うAPIの保守を、社内で持ち続けたくない」 「レポートだけでなく、AIでの分析や異常検知まで載せたい」 現状の運用の棚卸しからで構いません。1媒体・初期5万円・月額1.5万円〜、最短2週間から始められます。
→ アドヨミAIの詳細・料金を見る → 無料相談を申し込む