Installation
$npx skills add TheMattBerman/google-ads-copilot --skill google-ads-intent-mapSummary
After loading this skill, an agent can ingest search term data from Google Ads (via MCP or manual export), cluster queries into intent classes (Buyer, Comparison, Informational, Navigational, Branded, Junk), profile performance by intent, and identify structural problems where mismatched intents share campaigns or ad groups. Invoke when analyzing account intent routing, designing campaign structure, or debugging underperforming search traffic.
SKILL.MD
Google Ads Intent Map
Read first:
google-ads/references/operator-thesis.mdgoogle-ads/references/intent-map.mdgoogle-ads/references/query-patterns.mdgoogle-ads/references/deliverable-templates.md
Read workspace if available:
workspace/ads/account.mdworkspace/ads/goals.mdworkspace/ads/intent-map.mdworkspace/ads/queries.mdworkspace/ads/winners.mdworkspace/ads/learnings.md
Data Acquisition
Connected Mode (MCP available)
Pull via the search tool on google-ads-mcp:
Primary: All search terms for clustering — last 30 days:
SELECT
search_term_view.search_term,
campaign.name,
campaign.advertising_channel_type,
metrics.impressions,
metrics.clicks,
metrics.cost_micros,
metrics.conversions,
metrics.conversions_value,
metrics.all_conversions
FROM search_term_view
WHERE segments.date DURING LAST_30_DAYS
ORDER BY metrics.impressions DESC
LIMIT 1000
Retrieval ladder — if the primary query returns no rows, follow the shared retrieval ladder in data/search-term-retrieval.md. In pmax-fallback mode, use rows for clustering but note that performance metrics are unavailable for intent-class profiling. In limited mode, clustering is blocked — request a UI export.
Supplementary: Campaign and ad group structure (for routing analysis):
SELECT
campaign.name,
campaign.advertising_channel_type,
ad_group.name,
ad_group.status,
metrics.impressions,
metrics.clicks,
metrics.cost_micros,
metrics.conversions
FROM ad_group
WHERE campaign.status = 'ENABLED'
AND ad_group.status = 'ENABLED'
AND segments.date DURING LAST_30_DAYS
ORDER BY campaign.name, ad_group.name
See data/gaql-recipes.md for additional queries.
Date Range Fallback
If LAST_30_DAYS returns too few terms for meaningful clustering (<20 terms), fall back to LAST_90_DAYS, then all-time. Intent mapping benefits from volume — more search terms means better clustering. Always state the date range used.
Export Mode (no MCP)
Ask the user for:
- Search Terms report: last 30 days, all terms (not just top spenders)
- Include: Search term, Campaign, Ad group, Impressions, Clicks, Cost, Conversions, Conv. value
- Campaign names are essential for routing analysis
See data/export-formats.md for recommended format.
Process
- Announce mode (connected/export).
- In connected mode, run the shared retrieval ladder (
data/search-term-retrieval.md). Reportretrieval_modein the output header. - If
pmax-fallback, use rows for clustering but note that performance profiling is unavailable. Iflimited, clustering is blocked — request a UI export. - Load existing Intent Map from
workspace/ads/intent-map.mdif it exists. - Identify recurring query clusters and modifiers across all terms.
- Classify clusters into intent classes:
- Buyer — high commercial intent, ready to convert
- Comparison — evaluating options, not yet committed
- Informational — learning, researching, no purchase signal
- Navigational — looking for a specific brand/page
- Branded — searching for your brand specifically
- Junk — no plausible path to conversion
- For each class: note representative queries, performance profile, and current routing (which campaign/ad group they land in).
- Separate high-confidence signals from ambiguous ones.
- Infer structural implications — which classes are incorrectly sharing optimization buckets?
- Build or update
workspace/ads/intent-map.md. - Use the operator summary template when presenting results.
Always Answer
- What query patterns signal a likely buyer?
- What patterns signal weak or misleading intent?
- What traffic types should never be optimized together?
- What language repeats among likely winners?
- What should be cut, isolated, or tested next?
- Where is intent mixing causing structural problems?
Draft Output
Structure Draft
Trigger: Two or more distinct intent classes are sharing a single campaign or ad group, AND the performance gap between them is significant (e.g., 2x+ CPA difference, or one class converts and the other doesn't).
Create a draft using drafts/templates/structure-draft.md:
- Write to
workspace/ads/drafts/YYYY-MM-DD-[account-slug]-structure.md - Specify exactly which intent classes to separate, which campaigns/ad groups to split
- Include keyword lists or patterns that should route to each new bucket
- Update
workspace/ads/drafts/_index.md
Negative Draft (secondary)
Trigger: Intent Map reveals a clear junk class that should be excluded account-wide.
Create using drafts/templates/negative-draft.md if the junk class is better solved by exclusion than by structure.
Always update workspace memory:
workspace/ads/intent-map.md— the primary deliverable. Rebuild or update the map.workspace/ads/queries.md— notable clustersworkspace/ads/findings.md— strategic observations about intent routing
Output Shape
- Account Status block — account name, CID, status, date range used, tracking confidence, mode
- Data summary (terms analyzed, date range)
- Intent Map (classes with representative queries, performance, current routing)
- Routing problems (intent classes sharing wrong buckets)
- Structural implications (what should be separated)
- Emerging patterns (new intent classes forming)
- Confidence assessment per class
- Drafts created (with paths and summaries)
- Memory updates
Rules
- Do not confuse underperformance with irrelevance.
- Do not recommend negatives where isolation is the better move.
- Prefer pattern interpretation over checklist regurgitation.
- The Intent Map is the most strategic artifact in the workspace. Treat updates seriously — it compounds across every other skill.
- When in doubt between "exclude" and "isolate," prefer isolation. You can always exclude later. You can't un-exclude query data you never saw.