PORTAL / LIBRARY / keyword-research

[ PAID MEDIA ]

/keyword-research

Google Keyword Planner via the Google Ads API.

Download the skill file (.md)

Placeholders like ACME Agency, <id> and you@example.com mark values that are per-agency — your install fills them with YOUR clients and accounts. If a section references a helper script you don't have yet, it ships with that workflow's install.

Keyword Research

What this does

Wraps Google's <id> (<id> and generateKeywordIdeas) so we can pull real Keyword Planner data without using the Ads UI. Same data you'd see in the Ads Manager UI, but scriptable.

Prerequisites — Standard Access

Status: APPROVED and working. The Keyword Planner endpoints require Google Ads API Standard Access, and our developer token now has it — generateKeywordIdeas / <id> return exact volumes, competition, and CPC ranges (confirmed 2026-06-16, ACME Agency run). No <id> errors.

Calling-account caveat still applies: search-volume accuracy depends on the calling account (--customer-id / the client's google_ads_id) having recent ad spend. Active spenders return exact numbers; truly dormant accounts can return bucketed ranges ("1K–10K"). Kaiser's account (Meta-only, low Google spend) still returned exact numbers, so most of our accounts qualify — but if you get bucketed ranges, pass --customer-id of a high-spend account in the MCC.

(Historical note: the token previously had Basic Access only; Standard Access was applied for via https://support.google.com/adspolicy/contact/new_token_application and has since been granted.)

Modes

1. Historical — validate existing keywords

Given a campaign's keyword list, pull monthly search volume + competition for each. Highlights:

node ACME Agency/scripts/keyword_research.mjs \
  --client "ACME Agency" --geo AT \
  --keywords-file "ACME Agency/clients/ACME Agency/at_keywords.json"

Accepted keyword-file shapes:

2. Ideas — discover new keywords

Seed with keywords, a URL, or both:

# From seed keywords
node ACME Agency/scripts/keyword_research.mjs \
  --client "ACME Agency" --geo DE \
  --seeds "bioklimatische pergola,lamellendach,terrassenüberdachung"

# From a competitor URL
node ACME Agency/scripts/keyword_research.mjs \
  --client "ACME Agency" --geo AT \
  --url "https://www.competitor.at/pergolen"

# Both
node ACME Agency/scripts/keyword_research.mjs \
  --client "ACME Agency" --geo AT \
  --seeds "pergola" --url "https://anmeldung.<id>.de/"

Languages

Default behavior: local language for the geo + English. Rationale: many users in DE/AT/HR have their browser/account set to English even when searching in their local language, so excluding English under-counts demand.

Override:

Built-in geo + language mapping (see ACME Agency/scripts/lib/keyword_planner.mjs):

For anything else, pass the numeric ID directly (e.g. --geo 2792 for Turkey).

Output

For each run:

CSV columns (historical): ad_group, keyword, intended_match_type, avg_monthly_searches, competition, competition_index, low_bid_eur, high_bid_eur, <id>, volume_drop_vs_intent, note

CSV columns (ideas): keyword, avg_monthly_searches, competition, competition_index, low_bid_eur, high_bid_eur, <id>

Match-type recommendation heuristic

The script applies a simple rule to suggest a match type:

Avg monthly searchesRecommended match type
0DROP — no demand, kills Quality Score
1–99PHRASE if competition=HIGH, otherwise BROAD
100–999PHRASE
≥ 1000EXACT

These are starting points — humans override based on intent.

Customer ID

The script uses the client's google_ads_id from clients.json as the calling customer. Search-volume accuracy depends on the calling account having recent ad spend — dormant accounts return bucketed ranges (e.g. "1K–10K") instead of exact numbers. All our active client accounts qualify.

If a client doesn't have a Google Ads account yet (or you want to probe a niche from scratch), pass --customer-id <id> of any spending account in the MCC.