投稿

8月, 2026の投稿を表示しています

GAQLの書き方を実際に使ってわかった5つのコツ

イメージ
Google広告APIを触り始めると、最初の壁が認証、次の壁がGAQL(Google Ads Query Language)の書き方だ。SQLに似ているのに微妙に違い、公式リファレンスは英語で量も多い。数千万円規模の広告をAPIで自動集計する中で、つまずいた点と、そのままコピペで動く形が見えてきた。この記事は、GAQLを「読める」から「自分で書ける」に変えるための実践ガイドだ。3要素、コピペ用クエリ5本、落とし穴3つ、日付指定までまとめる。認証段階でつまずくなら、先に Google広告APIをPythonで動かす手順と初回の壁 を読むと早い。 GAQLはSQLに似た「3要素」でできている GAQLはSQLに似ているが、GROUP BYもJOINも書かない。1つのresource(主リソース)を選び、そこにmetrics(数値指標)とsegments(分割軸)を足すだけの構造だ。公式ドキュメント(developers.google.com/google-ads/api/docs/query/structure)でも、この3要素の組み合わせがクエリの中心だと説明されている。 ざっくり役割はこうだ。(1)resource=何を主軸に見るか。campaign、ad_group、keyword_view、search_term_viewなど。(2)metrics=clicksやcost_micros、conversionsといった集計済みの数値。(3)segments=segments.dateやsegments.deviceなど、行を分割する軸。この3つをSELECTに並べ、FROMでresourceを1つ指定し、WHEREで絞り込む。基本形は「SELECT 項目 FROM リソース WHERE 条件」だけだ。 SQLとの一番の違いは、集計とグルーピングが暗黙で走る点だ。segmentsをSELECTに足すと、そのままGROUP BYを書いたように行が自動で分割される。この挙動を知らないと、後述する「行が勝手に増える」罠に必ずぶつかる。 そのままコピペで使えるGAQLクエリ5本 まずは動くものを手元に置くのが最短だ。以下の5本は、実運用でそのまま叩いている頻出クエリだ。ブックマークして、campaign.statusや日付範囲を自分の環境に書き換えて使ってほしい。すべてse...

Google広告の変更履歴をPythonで運用ログ化する実装

イメージ
広告の数値が急に動いたとき、最初に知りたいのは「誰がいつ何を変えたか」だ。だが管理画面の変更履歴は一覧性が低い。媒体をまたぐと追跡に時間がかかる。実際、tCPAが突然リセットした原因を追うのに半日を溶かした。犯人は深夜に入った入札変更だった。Google広告APIの change_event を使えば、変更履歴を機械的に取り出せる。取り出した履歴は運用ログへそのまま落とせる。この記事のゴールは、最小コードで履歴を取得することだ。あわせて手動変更とツール変更を見分け、台帳やSlackへ残すところまで進める。コピペできる骨格つきで説明する。 なぜ変更履歴を機械でログ化するのか 広告アカウントは複数人・複数ツールが同時に触る。担当者の手動変更、自動化スクリプト、代理店の入稿、AdPilotのような外部ツール。これらが混ざると、数値変動の原因が管理画面からは追いにくい。とくにtCPAやCV最大化の入札は、変更が学習リセットの引き金になる。学習リセットは配信量とCPAを数日ぶらす。だから「いつ・誰が・どのフィールドを・何から何へ」の記録が要る。 tCPA学習リセットの条件と防ぐ運用ルール と組み合わせると、リセットの予兆を変更ログ側から検知できる。管理画面の履歴は目視前提で、集計も差分抽出もできない。ここをAPIで機械化する意味は大きい。 change_eventを叩く最小実装 使うのは change_event リソースだ。Google広告のGAQL(クエリ言語)でフィールドを指定して取得する。骨格はこの1行に集約できる。ブックマークして、自分のアカウントIDと期間に書き換えて使ってほしい。 クエリ骨格: SELECT change_event.change_date_time, change_event.change_resource_type, change_event.client_type, change_event.user_email, change_event.changed_fields FROM change_event WHERE change_event.change_date_time DURING LAST_30_DAYS LIMIT 1000 実装手順は次の通り。(1)google-ads ライブラリで GoogleAdsService の s...

RSAアセットの成果をPythonで取得する手順

イメージ
レスポンシブ検索広告(RSA)を回していても、どの見出しが効いていて、どれが足を引っ張っているかは管理画面では見えにくい。アセットごとの評価は「良」「最良」といったラベルで出るが、複数広告グループを横断して弱いアセットだけ抜き出す作業は手作業だと重い。この記事では、Google広告APIとPythonでRSAの見出し・説明文の成果ラベルを一括取得し、低評価アセットを特定して差し替えるところまでを、そのまま使えるクエリ付きで解説する。対象はGoogle広告を運用する担当者と、レポート作業を自動化したいインハウスのマーケ担当だ。 RSAアセットの成果はどこに入っているか RSAの見出しと説明文の成果は、Google広告APIの ad_group_ad_asset_view というリソースに入っている。これは広告(AdGroupAd)とアセット(Asset)のひも付きを表すビューで、レスポンシブ検索広告・アプリ広告・デマンドジェネレーションに対応する。ここから performance_label(成果ラベル)を取れば、アセット単位で「効いている・いない」が機械的に判定できる。 performance_label が返す値は6種類。BEST(最良)、GOOD(良)、LOW(低)、LEARNING(学習中)、PENDING(保留)、UNKNOWN(不明)である。運用で見るべきはこのうち LOW だ。LOW のアセットは差し替え候補になる。field_type には HEADLINE(見出し)と DESCRIPTION(説明文)が入り、どちらの枠のアセットかを区別できる。詳細は公式のアセットレポートのドキュメント(developers.google.com/google-ads/api/performance-max/asset-reporting)にまとまっている。 取得クエリ(GAQL)をそのまま使う APIへの問い合わせは GAQL という専用のクエリ言語で書く。以下が低評価アセット抽出の骨格になるクエリだ。ブックマークして、自分のアカウントのIDと期間に書き換えて使ってほしい。 SELECT ad_group.name, ad_group_ad_asset_view.field_type, ad_group_ad_asset_view.performance_label...

オフラインコンバージョンをPythonで送る実装手順

イメージ
広告の成果を正しく測るうえで、オフラインコンバージョンの取り込みは避けて通れない。フォーム送信までは計測できても、実際に受注した案件のデータは広告側に戻らないからだ。ここではGoogle広告APIを使い、CRMの成約データをPythonで自動アップロードする実装をまとめる。実際にvalidate_onlyで形式を検証し、詰まった箇所とその回避策まで示す。手を動かせば今日から試せる内容だ。 なぜ成約データを広告APIに戻すのか iOSのトラッキング制限やCookie規制で、クリック後の行動を追い切るのは年々むずかしくなっている。フォーム送信までは取れても、その先の「受注したか」は広告の管理画面に届かない。ここを埋めるのがオフラインコンバージョンのアップロードだ。 仕組みはシンプルだ。広告クリック時に発行されるGCLID(Google Click ID)を自社のCRMに保存しておく。成約したタイミングで、そのGCLIDと金額をAPI経由でGoogle広告に送る。すると自動入札が「クリック数」ではなく「実売上」を学習するようになる。公式の解説は GCLIDを使ったオフラインコンバージョン設定 にまとまっている。 送信先になるコンバージョンアクションは、種別を「アップロード(クリック)」で作る必要がある。既存のタグ計測用アクションには送れない。ここを取り違えるとエラーになる。 最小構成のPython実装 使うのはConversionUploadServiceのupload_click_conversionsメソッドだ。ClickConversionオブジェクトに、コンバージョンアクションのリソース名・GCLID・日時・金額・通貨を詰めて送る。手本になる公式サンプルは google-ads-pythonのupload_offline_conversion.py が最短だ。 最小の組み立てはこうなる。ブックマークして、自分のアカウントに合わせて書き換えて使ってほしい。 c = client.get_type("ClickConversion"); c.conversion_action = svc.conversion_action_path(customer_id, action_id); c.gclid = gclid; c.conversion_dat...

P-MAXの検索語句をPythonで取得する実装手順

イメージ
P-MAX(パフォーマンスマックス)を回すと必ず突き当たるのが「検索語句が見えない」という壁だ。管理画面のインサイトはカテゴリ単位で丸められ、生の検索語句まで降りられない。Google広告APIを使えば語句レベルに近いデータを引ける。ただし通常の検索語句レポートとは取得口が違い、そこを知らないと空の結果を返し続けて時間を溶かす。実際に詰まった罠と、そのまま流用できる取得クエリを配置表つきでまとめた。 なぜP-MAXの検索語句は普通のレポートで取れないのか 検索広告なら search_term_view リソースに投げれば検索語句が返る。だがP-MAXにこのビューは効かない。campaign_idで絞っても該当行がゼロで返り、権限エラーも出ないため「データが無い」と誤読しやすい。実際、最初の実装ではsearch_term_viewに対してP-MAXのcampaign_idを渡し、30分ほど「配信はあるのに0件」の原因を追った。答えは単純で、P-MAX専用の campaign_search_term_insight という別リソースを使う必要がある。公式のフィールド定義(developers.google.com/google-ads/api/fields/v22/campaign_search_term_insight)にこの分離が明記されている。取得口を1つ間違えるだけで詰まる、典型的なAPIの落とし穴だ。 campaign_search_term_insight の構造を押さえる このリソースは2階層で考えると理解が早い。上位が category_label (管理画面で見えるカテゴリ名)、その下に segments.search_term で実際の検索語句がぶら下がる。つまりGoogleは生の語句を「カテゴリ」で束ねて返す設計だ。指標は metrics.impressions・metrics.conversions・metrics.conversions_value が取れる。注意点は3つ。(1)campaign_search_term_insight.campaign_id での絞り込みが必須で、無指定だと全キャンペーンが混ざる。(2)語句単位のクリック数やコストは提供されず、取れるのはインパクション・CV・CV値まで。(3)データは一定のプ...

広告費の月末着地をPythonで予測する3手順

イメージ
複数アカウントの予算を回していると、月末着地の読み違いは避けにくい。目視の「なんとなく足りている」という判断は、月末の予算¥18,000の残しや、逆に数日前の枠切れによる配信停止を招く。ここで示すのは、月初から昨日までの実消化からPythonで着地額を機械的に予測し、ズレを月中盤で検知する手順だ。計算式とコードの骨格は、そのまま自分のアカウントに移植できる形でまとめた。 なぜ月末着地はズレるのか 消化ペースは月内で一定にならない。土日の消化が平日の6〜7割に落ちる媒体もあれば、自動入札の学習が進む月後半で急に伸びるアカウントもある。目視だと「累計消化÷経過日数」の暗算すら曖昧になり、残り10日で微調整が効かない段階まで放置されやすい。 目視運用だった頃は、月末の消化率が94〜108%の幅でばらつき、松竹梅の予算区分ごとに¥10,000超の残し・超過が月1〜2件は出ていた。この幅を数値で先に潰すのが着地予測の役割だ。予算管理の前提は アナグラムの解説 にも整理がある。 月末着地を予測する計算式 基本の式は単純だ。ブックマークして、自分の月予算に置き換えて使ってほしい。1行で書くとこうなる。着地予測額 = 月初〜昨日の累計消化 ÷ 経過日数 × 当月の総日数。 経過日数は「昨日まで」を数える点に注意する。当日は消化の途中なので分母から外す。消化率の予測は、着地予測額 ÷ 月予算 で出す。105%を超えたら枠切れリスク、95%を下回れば残しリスク、と閾値を先に決めておくと判断が速い。 具体例で確かめる。月予算¥300,000のアカウントで、経過10日の累計消化が¥110,000だったとする。着地予測額は 110,000 ÷ 10 × 30 = ¥330,000、消化率は 330,000 ÷ 300,000 = 110%になる。この時点で枠切れ側に振れているとわかり、残り20日で日予算を約9,500円まで絞れば着地を100%近くへ戻せる。経過10日で気づけば打ち手は多いが、残り3日では効かない。早期に数値化する価値はここにある。 土日で消化が偏る媒体は、経過日数と総日数を「平日換算」に置き換えると精度が上がる。土日消化を平日の0.65倍として重み付けした日数で割ればよい。Google公式の ペース管理ヘルプ でも、均等配信の考え方が土台になっている。 Pythonで着地予測...

Google広告の機会損失をPythonで可視化する実装

イメージ
Google広告で「まだ伸ばせるはずなのに配信が頭打ち」と感じる場面は多い。その正体はたいてい機会損失、つまり出せたはずのインプレッションを取りこぼしている状態だ。管理画面でも数値は見えるが、複数アカウントを横断して毎日追うのは現実的でない。この記事では、インプレッションシェアをPythonで取得し、予算とランクどちらが原因かを自動で切り分ける実装を示す。読み終えれば、機会損失の可視化を定時実行に載せる下地ができる。 インプレッションシェアが機会損失を映す理由 インプレッションシェア(IS)は、出せたはずの表示回数のうち実際に出せた割合を示す。ISが60%なら、残り40%は何らかの理由で取りこぼしたことになる。つまりISは「配信の伸びしろ」を数値化した指標だ。運用者が本当に知りたいのは割合そのものより、失った40%の内訳である。 Google広告はこの内訳を2つに分けて提供する。予算不足で失った分と、広告ランク不足で失った分だ。前者は予算を積めば回収でき、後者は入札や品質の改善が要る。打ち手がまったく異なるため、混ぜて見てはいけない。 3つの指標で損失原因を切り分ける Google Ads APIには機会損失を切り分ける3指標がある。search_impression_share(取れた割合)、search_budget_lost_impression_share(予算で失った割合)、search_rank_lost_impression_share(ランクで失った割合)だ。この3つはおおよそ「IS+予算ロス+ランクロス≒100%」の関係になる。合計がほぼ100%に収まるので、内訳の検算にも使える。 判断はシンプルだ。予算ロスが大きいキャンペーンは、予算を積めば素直に配信が伸びる見込みが高い。ランクロスが大きいなら、入札引き上げか広告文・品質スコアの改善が先だ。数値で原因を特定してから動くので、感覚頼みの増額を避けられる。この切り分けの実データ運用は 広告の日予算を自動計算するPython実装 と組み合わせると効いてくる。 PythonとGoogle Ads APIで取得する手順 取得はGAQL(Google Ads Query Language)で書く。キャンペーン単位なら次の一行で3指標がまとめて取れる。SELECT campaign.na...

Google広告の曜日・時間帯別CPAをPythonで集計

イメージ
自動入札に任せているのに、曜日や時間帯でCPAがぶれる。そう感じる運用者は多い。Google広告の管理画面は曜日と時間帯を同時に見られず、168コマ(7曜日×24時間)の全体像がつかみにくい。ここではGoogle Ads APIとPythonで168コマを一括取得し、CPAの穴を見つけて入札調整へ落とすまでの手順を、実装でつまずく点も含めて示す。今日から自分のアカウントで再現できる。 自動入札の時代でも曜日・時間帯分析が効く理由 tCPAやコンバージョン最大化を使っていても、曜日・時間帯の分析は無駄にならない。理由は2つある。1つは、自動入札は過去データを学習するため、CVが薄い深夜帯に配信予算が漏れている期間が発生しうること。もう1つは、広告のスケジュール(ad schedule)による入札単価調整が、自動入札と併用できる場面が残っていることだ。 管理画面でも曜日別・時間帯別は見られるが、両者の掛け合わせは1画面に出ない。0-7時の日曜だけCPAが2倍、といった コマ単位の異常 は、168コマを一枚の表にして初めて見える。APIで取れば、この掛け合わせを一度に抜き出せる。 Google Ads APIで168コマを一括取得するGAQL Google Ads APIは、UI と違って1つのクエリに複数のセグメントを指定できる。曜日(segments.day_of_week)と時間帯(segments.hour)を同時に指定すれば、campaign リソースから168コマ分の行が返る。セグメントの仕様は公式のフィールド一覧(developers.google.com/google-ads/api/fields/v22/segments)で確認できる。 この記事で一番のアセットが次のGAQLだ。ブックマークして、campaign を ad_group に変えるなど自分の粒度に書き換えて使ってほしい。 SELECT campaign.name, segments.day_of_week, segments.hour, metrics.cost_micros, metrics.conversions, metrics.clicks FROM campaign WHERE segments.date DURING LAST_30_DAYS これを GoogleAdsServi...

Meta広告の重複をPythonで検知して分かった3つ

イメージ
Meta広告のCPAが下がらない。予算を足しても配信が伸びない。その原因が、実は自分の広告セット同士の「オーディエンス重複」にある場合は多い。同じユーザー層を複数の広告セットで狙うと、Metaのオークションで自社の広告が競合し、CPMが上がる。この記事では、広告マネージャの手動確認ではなく、Marketing APIとPythonで重複を検知する手順をまとめた。実運用で詰まった点も添える。 なぜ広告セットの重複がCPAを押し上げるのか オーディエンス重複とは、複数の広告セットが同一ユーザーを配信対象に含む状態を指す。重複率が高いと、Metaのオークションで自社の広告セット同士が入札を奪い合う。結果、CPMが上がりCPAも連動して悪化する。特にカスタムオーディエンスと類似オーディエンスを併用する構成で起きやすい。 広告マネージャにも「オーディエンスの重複を表示」機能はある。ただし手動で2つずつ選ぶ方式で、広告セットが10個を超えると現実的に回らない。運用規模が大きいほど、APIで一括取得して機械的に判定する価値が出る。手動確認の限界は Meta広告レポートをPythonで自動化する実装手順 でも触れたとおりだ。 Marketing APIで広告セットのtargetingを取得する 重複判定の入口は、各広告セットの配信条件(targeting)をAPIで取ることだ。エンドポイントは広告アカウント配下の adsets で、fields に name と targeting を指定する。1行で書くと GET https://graph.facebook.com/v20.0/act_アカウントID/adsets?fields=name,targeting,effective_status&access_token=トークン を叩けば、各広告セットのJSONが返る。 targetingの中で重複判定に効くキーは4つある。(1)geo_locations(地域)(2)age_min と age_max(年齢帯)(3)genders(性別)(4)custom_audiences と flexible_spec 内の interests(カスタム客層・興味関心)。特にcustom_audiencesのIDが複数の広告セットで一致していれば、それは明確な重複シグ...