google-ads-query
Google Ads Query
Setup
Check prerequisites before querying:
Script path resolution: Before running any script, determine the correct base path. Check in this order:
.claude/skills/google-ads-query/scripts/— project-local install (run from repository root)~/.claude/skills/google-ads-query/scripts/— global install
Use whichever path exists. All script paths below use the project-local form; substitute the global path if that's where scripts are found.
- Virtual environment:
.claude/skills/google-ads-query/scripts/.venv/must exist - Config file:
google-ads.yamlmust be findable (see Config section)
First-time setup
# 1. Install dependencies
bash .claude/skills/google-ads-query/scripts/setup.sh
# 2. Create google-ads.yaml in project root or ~/.config/google-ads-query/
# (see Config section for template)
# 3. Test (direct argument is fine here — no special characters)
gads "SELECT customer.id FROM customer"
Claude Code sandbox
When running inside the Claude Code sandbox, network access is restricted. Add the following domains to ~/.claude/settings.json under sandbox.network.allowedDomains:
Setup (pip install):
pypi.orgfiles.pythonhosted.org
Runtime (Google Ads API):
googleads.googleapis.comoauth2.googleapis.com
Config
The script searches for google-ads.yaml in this order:
--configCLI parameter (explicit path)./google-ads.yaml(project root)~/.config/google-ads-query/google-ads.yaml(user-level)
Template (google-ads.yaml):
# Service account authentication:
developer_token: "YOUR_TOKEN"
json_key_file_path: "/path/to/service-account.json"
customer_id: "YOUR_CUSTOMER_ID"
use_proto_plus: true
# OR OAuth2 authentication:
# developer_token: "YOUR_TOKEN"
# client_id: "YOUR_CLIENT_ID.apps.googleusercontent.com"
# client_secret: "YOUR_SECRET"
# refresh_token: "1//YOUR_REFRESH_TOKEN"
# customer_id: "YOUR_CUSTOMER_ID"
# use_proto_plus: true
# Optional (manager accounts):
# login_customer_id: "MANAGER_CUSTOMER_ID"
Usage
Use the gads alias for queries:
alias gads='.claude/skills/google-ads-query/scripts/.venv/bin/python3 .claude/skills/google-ads-query/scripts/query.py'
IMPORTANT: Always pipe queries via stdin. Use echo "QUERY" | gads - for all queries. This avoids shell escaping failures with dots in field names, single quotes in WHERE clauses, and other GAQL punctuation. Direct argument passing (gads "QUERY") is fragile and should only be used for trivial test queries like gads "SELECT customer.id FROM customer".
# Standard query (pipe via stdin to avoid shell escaping issues)
echo "SELECT campaign.name, metrics.clicks FROM campaign" | gads -
# Query with single quotes in WHERE clause
echo "SELECT campaign.name FROM campaign WHERE campaign.status != 'REMOVED'" | gads -
# Override customer ID
echo "SELECT campaign.name FROM campaign" | gads --customer-id 9876543210 -
# Explicit config path
echo "SELECT campaign.name FROM campaign" | gads --config /path/to/google-ads.yaml -
# Direct argument (only for trivial test queries with no special characters)
gads "SELECT customer.id FROM customer"
Direct argument mode: Passing the query as a positional argument (gads "QUERY") works only for simple queries with no single quotes, dots in WHERE clauses, or other special GAQL characters. For all real queries, use stdin (echo "..." | gads -).
Output: JSON array to stdout. Enums returned as names (e.g., "ENABLED", not 2).
Errors: JSON to stderr + exit code 1.
Field Notes
These fields may cause issues depending on API version:
campaign.start_date,campaign.end_date— may be unrecognizedconversion_action.type— can return cryptic errorsconversion_action.tag_snippets— repeated composite, may fail in some versions
The script handles repeated fields (both scalar and composite) correctly via protobuf serialization. If a query fails, remove suspected fields one at a time to isolate the issue.
Query Patterns
Campaign overview
echo "SELECT campaign.id, campaign.name, campaign.status,
campaign.advertising_channel_type, campaign.bidding_strategy_type,
metrics.impressions, metrics.clicks, metrics.cost_micros,
metrics.conversions, metrics.all_conversions
FROM campaign
WHERE campaign.status != 'REMOVED'" | gads -
Conversion actions (full list)
echo "SELECT conversion_action.id, conversion_action.name,
conversion_action.status, conversion_action.category,
conversion_action.origin, conversion_action.counting_type,
conversion_action.include_in_conversions_metric,
conversion_action.primary_for_goal
FROM conversion_action" | gads -
Campaign conversion goals
echo "SELECT campaign.id, campaign.name,
campaign_conversion_goal.category, campaign_conversion_goal.origin,
campaign_conversion_goal.biddable
FROM campaign_conversion_goal
WHERE campaign.id = CAMPAIGN_ID" | gads -
Conversion goal config (account vs campaign level)
echo "SELECT campaign.id, campaign.name,
conversion_goal_campaign_config.goal_config_level
FROM conversion_goal_campaign_config" | gads -
Metrics with date range
echo "SELECT campaign.name, metrics.impressions, metrics.clicks,
metrics.cost_micros, metrics.conversions, segments.date
FROM campaign
WHERE segments.date >= 'YYYY-MM-DD' AND segments.date <= 'YYYY-MM-DD'
AND campaign.status != 'REMOVED'" | gads -
Ad group details
echo "SELECT ad_group.id, ad_group.name, ad_group.status,
ad_group.cpc_bid_micros, campaign.name
FROM ad_group
WHERE campaign.status != 'REMOVED'" | gads -
Keywords
echo "SELECT ad_group_criterion.keyword.text,
ad_group_criterion.keyword.match_type,
ad_group_criterion.status, metrics.clicks,
metrics.impressions, metrics.cost_micros
FROM keyword_view
WHERE campaign.status != 'REMOVED'" | gads -
Search terms report
echo "SELECT search_term_view.search_term, metrics.clicks,
metrics.impressions, metrics.cost_micros, metrics.conversions
FROM search_term_view
WHERE segments.date >= 'YYYY-MM-DD' AND segments.date <= 'YYYY-MM-DD'" | gads -
Enum Reference
The script returns enum values as human-readable names (e.g., "ENABLED", "MAXIMIZE_CONVERSIONS"), so you typically don't need to decode numeric codes. For raw numeric references, see references/enums.md.
Key enum values for GAQL WHERE clauses (these use string names):
| Field | WHERE value | Meaning |
|---|---|---|
| campaign.status | 'ENABLED' |
Active campaign |
| campaign.status | 'PAUSED' |
Paused campaign |
| campaign.status | 'REMOVED' |
Deleted campaign |
Conversion Tracking Audit
- Query customer settings — confirm
conversion_tracking_statusandauto_tagging_enabled - Query all
conversion_action— list actions, check status, primary_for_goal, include_in_conversions_metric - Query
campaign_conversion_goalfor the campaign — verify biddable goals match campaign objective - Query
conversion_goal_campaign_config— check if campaign uses campaign-level or account-level goals - If GA4-imported conversions: verify GA4 tag fires on target pages (recommend Google Tag Assistant)
- Check metrics: compare
metrics.conversions(primary only) vsmetrics.all_conversions(includes secondary)
Notes
metrics.cost_microsis in micros (divide by 1,000,000 for currency)- GAQL WHERE uses string enum values (
'REMOVED'), not numeric codes segments.daterequires both>=and<=bounds- Campaign-level goals override account-level defaults when
goal_config_level= CAMPAIGN
More from aivokone/ak-skills
pr-review
Use FIRST for any PR/code review work — checking feedback, reading CR comments, responding to reviewers, addressing review bot or human comments, or preparing commits on a PR. Collects feedback from ALL sources (conversation, inline, reviews) to prevent the common failure of missing inline feedback. Start with get-context.sh for state detection, then follow the Decision Tree. All operations through provided scripts — never raw git/gh commands.
15seravo-dev
Use this skill FIRST for any Seravo-hosted WordPress task. Trigger when the user mentions Seravo, production/shadow, deploy, Git-based deploys, SSH, DDEV, DB sync/import/export, or Seravo custom wp-* commands (wp-backup*, wp-purge-cache, wp-list-env). Start by identifying the environment (production vs shadow vs local) and enforce safety: agents must not run destructive or state-changing commands on production. When production write is needed, provide exact copy-paste commands for the user. Use Seravo-specific CLI and workflows instead of generic WP guidance to avoid wrong commands and risky prod changes.
13ga4-query
Query Google Analytics 4 via the Data API. Use when the user asks about GA4, Google Analytics, website traffic, page views, sessions, users, realtime data, or analytics reports. Triggered by: GA4, Google Analytics, analytics, sessions, pageviews, activeUsers, traffic, realtime, bounce rate, engagement.
12local-ref
Local docs cache for the project. Always check docs/reference/ before fetching externally. Use for init (set up cache), update (refresh docs), lookup (local-first search), and save (persist fetched docs). If external docs are fetched (Context7/web), save a tailored topic file to docs/reference/ and add a verbal pointer in AGENTS.md.
8cli-review-fix
Send code review requests to external CLI tools (Codex CLI, Gemini CLI), critically evaluate findings, fix valid issues, and present a fix report. Auto-detects context (PR, branch, uncommitted changes). Use the bundled Codex diff-review wrapper for PRs and branch diffs so Codex stays focused on the actual patch. Run /cli-review-fix to launch all available CLIs, or /cli-review-fix codex for a specific one.
4codebase-guide
Generate a beginner-friendly Markdown guide explaining a codebase. Produces a single Markdown file covering purpose, tech stack, architecture, data flow, key files, and how to run.
3