google-ads-query
Skill72 starsChanged 4 months agoMITView on GitHub
Query Google Ads data and save to CSV. AUTO-ACTIVATE for: search terms, campaigns, keywords, ad groups, conversions, budgets, assets, geo performance. Also triggered by account names or "get/pull/show me" + Google Ads resource.
- Installs packages
In this repository41 other files it gives its agents.
- account-diagnosticSkill
- ad-copy-generation-frameworkSkill
- ad-copy-verification-standardSkill
- add-account-negative-keywordsSkill
- ads-checkerSkill
- budget-guardianSkill
- budget-recommendation-calculatorSkill
- change-history-checkerSkill
- client-communication-standardsSkill
- competitor-analysis-v2Skill
- conversion-tracking-healthSkill
- dgen-automation-disableSkill
- fair-housing-complianceSkill
- ga4-campaign-cross-referenceSkill
- ga4-cross-analysisSkill
- ga4-lead-quality-investigationSkill
- gaql-query-patternsSkill
- geo-conflict-analyzerSkill
- google-ads-api-setupSkill
- google-ads-samplesSkill
- impression-share-diagnosticsSkill
- investigation-methodologySkill
- lead-quality-pattern-analysisSkill
- lead-quality-recommendation-prioritizationSkill
- markdown-to-sheets-presenterSkill
- mcc-hack-auditSkill
- mutation-safetySkill
- neg-conflict-finderSkill
- non-serving-keyword-scannerSkill
- pmax-asset-automationSkill
- pmax-builderSkill
- portfolio-health-prioritizationSkill
- portfolio-pacing-rulesSkill
- rsa-bulk-editSkill
- rsa-refreshSkill
- rsa-single-accountSkill
- shared-budget-updaterSkill
- sqr-classifierSkill
- sqr-pipelineSkill
- underspending-investigationSkill
- youtube-placement-auditSkill
The file
We split this skill into the rules it gives an agent
3 rules. About 0 are common, 0 are distinctive, and 3 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 74
If the ask doesn't map cleanly to one of the eight (different segment, grain, or filter), stop and make the template-vs-custom call per …
- Very specific: line 119
Every failure prints ERROR: <detail> to stderr and exits 1 — resolution errors carry their own suggestions (ambiguous-name candidates, the …
- Very specific: line 124
Before re-running any surprise, check the false-alarm table in rules.md — most surprises are per-template scope filters doing their …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Google Ads Query Skill
Owns one workflow: turn a natural-language data request into a template-driven GAQL pull whose results land in a CSV file — returning only the file path and row count to the conversation. Read-only — SELECT queries, never mutations.
Purpose
This skill implements the CSV-first pattern for context-efficient analysis:
- Query API data
- Save to CSV file (data stays outside context)
- Return only file path + row count
- Analyze the CSV as a separate step, only when asked (read the file then, not before)
The judgment layer — template vs custom GAQL, registry vs bare CID, when the
CSV actually gets read — is rules.md. The exact resolution,
date, and CSV mechanics are
references/query-contract.md.
Deliberately does NOT do
- No mutations, ever — there is no code path that writes to Google Ads.
- No auto-analysis — a completed query reports path + row count and stops; reading the file waits for an analysis question.
- No raw data in conversation — no sample rows, no previews, no pastes.
- No portfolio sweeps by default — one account per run; a multi-account pull is an explicit loop, not an assumption.
- No alias/fuzzy matching inside the script — name resolution vocabulary
is the agent's parsing job (see
references/resources.md); the script takes exact resource names and exact/partial registry matches only.
Command Format
Get [resource] for [account] [days]dExamples:
Get search terms for Riverside Flats→ 30 days (default)Get campaigns for Riverside Flats 60d→ 60 daysGet keywords for 1234567890 90d→ bare CID works too
Defaults: 30 days; sort built into each template (cost DESC on seven,
conversions DESC on conversions). Note the contract's date semantics:
--days 30 spans 31 calendar dates including today's partial data, and
conversions ignores --days entirely (all-time template).
Prerequisites
google-ads.yamlat project root (or--config <path>) — see the google-ads-api-setup skill for creating it. Querying client accounts through a manager account requireslogin_customer_idin the yaml.- Python with the
google-adspackage (pip install google-ads) - Optional: an
accounts.jsonregistry so requests can use account names instead of CIDs — copyaccounts.example.jsonand edit. Without it, bare CIDs work fine. The registry-or-CID call is inrules.md.
Process
Step 1: Parse Request
Extract:
- Resource — short name. Eight ship:
search-terms,campaigns,keywords,ad-groups,conversions,budgets,assets,geo— mappings, aliases, and the template format live inreferences/resources.md. Map user phrasing ("sqr", "kw") to the exact short name here — the script won't. - Account — a CID, or a name/alias if a registry exists
- Days — time period (default 30)
If the ask doesn't map cleanly to one of the eight (different segment, grain,
or filter), stop and make the template-vs-custom call per rules.md before
running anything.
Step 2: Resolve Account
- Request contains a CID → use
--ciddirectly; no registry needed. - Request names an account → resolve via
accounts.json(--accountmatches key, name, or alias; partial matches suggest candidates — full ladder in the contract). - Name given but no
accounts.jsonpresent → ask for the CID, or offer to set up the registry fromaccounts.example.json. CID route first — it needs no setup.
Step 3: Execute Query
# By CID
python scripts/query.py --cid 1234567890 --resource search-terms --days 30
# By registry name/alias
python scripts/query.py --account "riverside flats" --resource campaigns --days 60Useful flags: --config <path> (default ./google-ads.yaml), --accounts <path> (default ./accounts.json), --output <path> (default data/[YYYYMMDD]-[account]-[resource].csv).
Step 4: Return Minimal Output
The script prints exactly two lines on success:
File: data/20260723-riverside-flats-search-terms.csv
Rows: 4127Relay them (row count prints plain — no thousands separator) and close with the standing offer: "Ask for analysis to dig in, or run another query."
DO NOT:
- Display raw data in conversation
- Show sample rows
- Auto-analyze (wait for user to request)
Error Handling
Every failure prints ERROR: <detail> to stderr and exits 1 — resolution
errors carry their own suggestions (ambiguous-name candidates, the first
registry keys, the both-fixes message when a name is used with no registry).
Relay the script's suggestions and let the user pick; never auto-pick. A
zero-row run is not an error: Rows: 0 (no file written - …), exit 0.
Before re-running any surprise, check the false-alarm table in
rules.md — most surprises are per-template scope filters doing
their documented job (contract table).
After a Query (status leg)
data/is the run record:<YYYYMMDD>-<slug>-<resource>.csvnames tell a cold session what was pulled and when. Same-day same-target re-pulls overwrite; zero-row runs leave no file (contract, "Reading run state cold").- Findings that turn into work route onward — table below.
Files in this skill
| File | Role |
SKILL.md | This file — workflow + routing |
rules.md | Judgment: template-vs-custom, registry-vs-CID, CSV reading, false alarms |
examples.md | Three worked reads (routine pull, the PMax-scope zero, the ninth template) |
references/query-contract.md | Exact resolution/date/CSV mechanics + per-template scope table |
references/resources.md | Resource → template mappings + parse-time aliases |
references/*.gaql | The 8 query templates — each file is the source of truth for its fields |
accounts.example.json | Registry starter — copy to accounts.json and edit |
scripts/query.py | The query → CSV engine |
Runtime artifacts (never committed): data/*.csv outputs, your
accounts.json, your google-ads.yaml.
When to load sibling skills
| Load | When |
gaql-query-patterns | The ask doesn't map to the 8 templates — write custom GAQL there; promote repeat queries to a ninth template per the contract |
google-ads-api-setup | First run, or any credentials error |
sqr-pipeline | The search-terms pull is step one of negatives work — classification and upload live there, not here |
change-history-checker | The question is "what changed," not "how did it perform" |
account-diagnostic | The question is really "how healthy is this account" — run the inspection, not ad-hoc pulls |
markdown-to-sheets-presenter | CSV findings need to become a client-facing formatted Sheet |
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

