DEV Community

SteadyScrape
SteadyScrape

Posted on

How to get Google keyword search volume in bulk without a Google Ads account (Python)

Google Keyword Planner only shows exact search volumes if you run an active ad campaign. Without one you get ranges like "1K–10K", which is useless for deciding which article to write first.

This post shows how to get exact monthly search volume, CPC, competition and keyword difficulty for a list of keywords from Python, then save it as a CSV you can sort. No Google Ads account, no OAuth app, no developer token.

What you need

  • Python 3.9+
  • An Apify account (the free plan includes $5/month of usage) and your API token from Console → Settings → API & Integrations
  • pip install apify-client (this post uses v3)

The data comes from the Keyword Search Volume Actor on Apify, which wraps a Google Ads–sourced keyword data provider and caches results for 30 days.

The script

import csv, os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])

keywords = [
    "crm software", "crm for small business", "free crm", "best crm",
    "crm for startups", "simple crm", "crm app", "real estate crm",
    "crm for nonprofits", "what is a crm",
]

run = client.actor("steady-scrape/keyword-search-volume").call(logger=None, run_input={
    "keywords": keywords,
    "location": "United States",
    "language": "English",
    "includeMonthlyTrend": True,
})
rows = list(client.dataset(run.default_dataset_id).iterate_items())

def trend(monthly):
    """Last 3 months vs the 3 before, as a % change."""
    v = [m["searchVolume"] or 0 for m in sorted(monthly or [], key=lambda m: m["month"])]
    if len(v) < 6 or sum(v[-6:-3]) == 0:
        return None
    return round(100 * (sum(v[-3:]) / sum(v[-6:-3]) - 1))

with open("keywords.csv", "w", newline="") as f:
    w = csv.writer(f)
    w.writerow(["keyword", "volume", "cpc_usd", "competition", "difficulty", "intent", "trend_3m_pct"])
    for r in sorted(rows, key=lambda r: r.get("searchVolume") or 0, reverse=True):
        if r.get("status") != "ok":
            continue
        w.writerow([r["keyword"], r["searchVolume"], r.get("cpc"), r.get("competition"),
                    r.get("keywordDifficulty"), r.get("searchIntent"), trend(r.get("monthlySearches"))])
        print(f'{r["keyword"]:<24} {r["searchVolume"]:>8,}  ${r.get("cpc") or 0:>6.2f}  KD {r.get("keywordDifficulty")}')
Enter fullscreen mode Exit fullscreen mode

Run it:

export APIFY_TOKEN=...   # never commit this
python keyword_volume.py
Enter fullscreen mode Exit fullscreen mode

trend_3m_pct compares the last three months with the three before. It's a quick way to spot keywords that are growing or fading without opening a chart.

Real output (US / English, data month 2026-09)

keyword volume CPC competition KD intent 3-month trend
crm software 201,000 $37.13 LOW 59 commercial +5%
what is a crm 22,200 $15.63 LOW 70 informational +7%
free crm 5,400 $67.26 MEDIUM 38 commercial −28%
crm for small business 4,400 $51.28 LOW 31 commercial +59%
real estate crm 4,400 $37.34 MEDIUM 36 commercial −4%
best crm 2,400 $63.56 MEDIUM 35 commercial +9%
crm for nonprofits 2,400 $58.70 MEDIUM 35 commercial −4%
crm app 1,300 $44.41 LOW 58 commercial −9%
simple crm 590 $60.53 MEDIUM 33 commercial −12%
crm for startups 390 $95.77 LOW 10 commercial −8%

Two things jump out that a "1K–10K" range would hide:

  • "crm for small business" has 4,400 searches, a difficulty of 31 and is up 59% over three months. That's a much better first article than "crm software" (KD 59).
  • "crm for startups" is tiny (390/month) but has the highest CPC ($95.77) and KD 10. Advertisers pay a lot for that click, so it's worth a page even at low volume.

competition is the Google Ads competition level (how many advertisers bid). It is not SEO difficulty. Use keywordDifficulty (0–100) for organic ranking.

What it cost

I ran exactly this 10-keyword list on Nov 1, 2026. At the free-plan list price:

  • 1 live lookup for the run: $0.12 (skipped when every keyword is already in the 30-day cache)
  • 10 keyword results × $0.003 = $0.03
  • Actor start: $0.00005

Total: about $0.15 for 10 keywords, in 3.7 seconds. The fixed lookup fee is per run, so batch your keywords: 1,000 keywords in one run is about $3.12, not 100 × $0.15. Paid Apify plans get lower per-result prices.

Tips

  • Pass "location": "United Kingdom" (or another country) and "language" to get local volumes. The cache is per location and language.
  • Keywords are normalized and deduplicated by default, so "CRM Software" and "crm software " count once.
  • Keep includeMonthlyTrend on. The 12-month series is what makes seasonality and the trend column possible.
  • Rows with status other than ok (no data, invalid keyword) aren't billed as results. The script skips them.

Disclosure: SteadyScrape publishes the Actor used in this post. Numbers above are from a real run on Nov 1, 2026; volumes change monthly.

Top comments (1)

Collapse
 
alexcodebytes profile image
Oleksandr •

The '1K–10K is useless for deciding which article to write first' is the exact problem I've had with Keyword Planner. You can't prioritize with a range. Seeing the actual numbers (4,400 for 'crm for small business' vs. 201,000 for 'crm software') changes the decision completely.