Estimate Keyword Search Volume Without the Google Ads API
You have a list of 200 keywords and one question: which ones are worth writing for?
The obvious answer is "check the search volume." But the moment you open Google Keyword Planner, you hit a wall. No exact numbers. Just fuzzy ranges like "1K–10K." And the Google Ads API, the official way to pull this data programmatically, asks for an approved ad account before it gives you anything useful.
Here is the honest truth most tools won't tell you: you cannot get Google's exact internal search volume without playing Google's game. But you can build something almost as useful — a transparent, defensible relative demand score from signals that are sitting right there on the search results page.
This guide shows you how, with working Python and a real scored example.
TL;DR: Exact Google volume is locked behind active ad spend and an approved Google Ads API account. Instead, pull observable SERP signals — Related Searches count, People Also Ask count, ads presence, and organic density — from the Serpent search API and combine them into a weighted demand score. It is a relative prioritization tool, not Google's exact number, and saying so out loud is what makes it trustworthy.
Why Google hides exact search volume
Google deliberately shows broad ranges — not exact volume — to accounts that aren't spending on ads.
If your Google Ads account has no active campaigns, Keyword Planner returns volume in coarse logarithmic buckets: 10, 100, 1K–10K, 10K–100K, and so on. This is by design. The tool exists to help advertisers plan campaigns, so Google reserves precise figures for accounts that put real money on the table.
Run even a modest campaign — a few dollars a day — and the ranges typically tighten into specific monthly averages. That is the trade Google offers: precise data in exchange for ad spend.
For an SEO or indie hacker who just wants to triage a keyword list, paying for ads to unlock numbers you only need once is a poor deal. So most people stare at "1K–10K" and guess. We can do better than guessing.
Why the Google Ads API is a hurdle
The official programmatic route — the Google Ads API — is gated behind an approval process that most casual users never finish.
To call it, you need a Google Ads manager account, a developer token from the API Center, and OAuth credentials. The developer token starts in a restricted state and must be reviewed before it can hit production accounts at any real scale. Google's compliance team may email you for clarification during that review, and applications stall if you don't respond.
None of this is impossible. But it is a lot of friction for the simple goal of "rank my keyword list by likely demand." You can read the full requirements in the official developer-token docs.
The good news: the signal we need to prioritize keywords is public. It is on the search results page itself, and you can read it without ad accounts or token approvals.
The honest method: a relative demand score
You can't recover Google's exact number, but you can measure how much a topic looks in demand by reading the SERP — and that is enough to prioritize.
Think about what Google itself does. When a query is popular and explored from many angles, Google fills the page with extra features: a long list of Related Searches, a fat People Also Ask block, paid ads competing for the click, shopping units for commercial queries. A thin, low-interest query gets a sparse page.
That density is a demand signal. It is Google quietly telling you "lots of people search around this." We just have to read it consistently and turn it into a number we can sort by.
The output is a relative demand score: a single value, say 0–100, that lets you say "keyword A is a bigger, more commercial opportunity than keyword B." It is not a monthly-searches figure, and we never pretend it is. That distinction is the whole point — and it is the differentiator versus tools that sell you a confident-looking number invented from a model. For the broader workflow, see our guide on keyword research with a SERP API.
The SERP signals you can actually pull
Four observable signals from a single search call do most of the work, and each one maps to a piece of real-world demand.
Here is what each signal implies, and which field on the Serpent API response carries it.
| Signal | What it implies | Response field |
|---|---|---|
| Related Searches count | How many directions Google thinks people explore from this query. More refinements → richer, more-searched topic. | results.relatedSearches |
| People Also Ask count | Depth of curiosity and question intent. A full PAA block signals an actively explored topic. | results.peopleAlsoAsk |
| Ads present (and how many) | Commercial demand. Advertisers only bid where money changes hands — a strong "this is worth traffic" flag. | results.ads.totalCount |
| Organic result density | Whether the query returns a deep, fully-populated SERP versus a thin one. | results.organic (length) |
A quick honesty note: Serpent does not expose a dedicated keyword-autocomplete or volume endpoint. We're not going to pretend otherwise. Instead we work with the signals the standard search endpoint genuinely returns — the four above, plus optional SERP features like shopping or a featured snippet — and combine them ourselves. If you specifically want question and autocomplete-style mining, our free AnswerThePublic alternative walks through the PAA and related-search angle in depth.
Build the demand score in Python
The whole thing is one API call per keyword plus a transparent weighting function — under 60 lines of Python.
We hit https://api.apiserpent.com/api/search with the X-API-Key header, read the four signal fields, normalize each to 0–1, and combine them with weights you can see and tune. Nothing is hidden inside a black box.
import requests
API_KEY = "sk_live_your_key" # from your Serpent dashboard
BASE = "https://api.apiserpent.com/api/search"
# transparent weights — tune these to your goal
WEIGHTS = {
"related": 0.30, # exploration breadth
"paa": 0.25, # question/curiosity depth
"ads": 0.30, # commercial demand
"organic": 0.15, # SERP fullness
}
# soft caps so one huge signal can't dominate; value/cap, clipped to 1.0
CAPS = {"related": 8, "paa": 6, "ads": 7, "organic": 10}
def fetch_serp(keyword, country="us"):
headers = {"X-API-Key": API_KEY}
params = {"q": keyword, "engine": "google", "country": country,
"num": 10, "format": "full"}
r = requests.get(BASE, headers=headers, params=params, timeout=60)
r.raise_for_status()
return r.json().get("results", {})
def demand_score(results):
related = len(results.get("relatedSearches", []) or [])
paa = len(results.get("peopleAlsoAsk", []) or [])
ads = (results.get("ads", {}) or {}).get("totalCount", 0)
organic = len(results.get("organic", []) or [])
raw = {"related": related, "paa": paa, "ads": ads, "organic": organic}
norm = {k: min(raw[k] / CAPS[k], 1.0) for k in raw}
score = sum(norm[k] * WEIGHTS[k] for k in WEIGHTS) * 100
return round(score, 1), raw
def rank_keywords(keywords, country="us"):
rows = []
for kw in keywords:
results = fetch_serp(kw, country)
score, raw = demand_score(results)
rows.append({"keyword": kw, "score": score, **raw})
rows.sort(key=lambda x: x["score"], reverse=True)
return rows
if __name__ == "__main__":
keywords = [
"best running shoes",
"mesothelioma lawyer",
"how to tie a tie",
"serp api pricing",
"obscure 1970s synth model x9",
]
for row in rank_keywords(keywords):
print(f"{row['score']:>5} {row['keyword']:<32} "
f"rel={row['related']} paa={row['paa']} "
f"ads={row['ads']} org={row['organic']}")
Because the API returns up to 100 organic results in one call and handles access for you, you don't manage proxies, headless browsers, or block-handling — you just read JSON. Grab a key from the dashboard (10 free Google searches to test the flow) and run it.
Tip: Run the same list through Bing, Yahoo and DuckDuckGo by changing the engine param, then average the scores. Cross-engine agreement is a stronger demand signal than any single SERP. See programmatic SEO with a SERP API for scaling this to thousands of keywords.
A worked, scored keyword table
Here is what the output looks like on a small, deliberately mixed list — and it ranks the keywords exactly the way your intuition would.
The numbers below are illustrative of a typical run; your live figures will vary by day and country. What matters is the ordering the score produces.
| Keyword | Score | Related | PAA | Ads | Organic | Read |
|---|---|---|---|---|---|---|
| mesothelioma lawyer | 92.4 | 8 | 5 | 7 | 10 | Huge commercial demand |
| best running shoes | 81.0 | 8 | 6 | 4 | 10 | Popular + commercial |
| serp api pricing | 49.5 | 5 | 3 | 2 | 10 | Niche, some intent |
| how to tie a tie | 43.8 | 7 | 6 | 0 | 10 | High interest, no ads |
| obscure 1970s synth model x9 | 9.2 | 1 | 0 | 0 | 6 | Almost no demand |
Notice how the score separates the list cleanly. "Mesothelioma lawyer" tops it — a famously high-value query packed with ads. "How to tie a tie" scores below "best running shoes" despite being hugely popular, because it has zero commercial intent (no ads); if your goal is monetizable traffic, that ordering is correct. The obscure synth keyword drops to the bottom, where it belongs.
That is the value: a list you can sort, with a column you can defend in a meeting, built from data anyone can verify by looking at the SERP themselves.
Adding Google Trends for time & popularity
If you want a popularity-over-time dimension, blend in Google Trends — but understand it is also relative, not absolute.
Google Trends scores a term from 0 to 100, where 100 is its own peak over the chosen region and period, not a raw search count. Per Google's own Trends FAQ, the numbers are normalized and "do not represent absolute search volume." Change the time range or comparison terms and the scale shifts.
That makes Trends a perfect companion to a relative SERP score — both speak the same honest language. You can pull it with the community pytrends library and fold it into the weighting.
from pytrends.request import TrendReq
def trends_score(keyword, geo="US"):
pt = TrendReq(hl="en-US", tz=0)
pt.build_payload([keyword], timeframe="today 12-m", geo=geo)
df = pt.interest_over_time()
if df.empty:
return 0.0
# mean of the 0–100 relative interest over the last 12 months
return float(df[keyword].mean()) # already 0–100, relative
# blend example: 70% SERP demand, 30% Trends interest
def blended(serp_score, keyword):
t = trends_score(keyword)
return round(0.70 * serp_score + 0.30 * t, 1)
Compare two related terms in a single Trends request to keep their 0–100 scales aligned. Used this way, Trends tells you whether a keyword is rising, fading, or seasonal — context the SERP snapshot alone can't give you.
What this score is — and is not
This is a relative prioritization score, full stop. It is not Google's monthly search volume, and treating it as one will burn you.
Use it to rank a list — "write about A before B" — not to forecast "this page will get 4,300 visits a month." For that promise you would need real volume data, which means the Google Ads API and ad spend, or a paid dataset.
The honesty cuts both ways. A keyword with no ads isn't worthless — informational queries (like "how to tie a tie") are real traffic, just not commercial. Tune the weights to your goal: drop the ads weight for a content site, raise it for an affiliate or ecommerce play.
Where this score truly shines is at scale and as input to other systems — feeding a rank tracker, prioritizing a cannibalization audit, or scoring a thousand-row list before you commit writers. And because it is built from raw SERP fields, you can drop the same data straight into Google Sheets for the rest of your team.
Build the score, label it honestly, and you'll trust your own keyword decisions more than a tool that hands you a suspiciously precise number it can't actually know.
Score your keyword list today — no ad account required
Serpent returns the exact SERP signals this score needs — Related Searches, People Also Ask, ads, and up to 100 organic results — from one clean API call. 10 free Google searches on signup, pay-as-you-go from $0.03 per 10K, no subscription.
Get Your Free API KeyExplore: Google SERP API · Live Playground · Pricing
FAQ
Can I get exact Google search volume without the Google Ads API?
No. Exact monthly volume lives only inside Google and is unlocked in Keyword Planner with active ad spend. What you can build instead is a defensible relative demand score from observable SERP signals to rank and prioritize keywords.
Why does Keyword Planner show ranges like 1K–10K?
Accounts without active ad spend see broad logarithmic ranges (10, 100, 1K–10K, 10K–100K). Google narrows these to precise figures only once you run paying campaigns, since the tool is built for ad buyers.
What SERP signals indicate keyword demand?
Useful signals include the count of Related Searches, the number of People Also Ask questions, whether paid ads appear (commercial demand), and total organic result density. More refinements and questions generally mean a richer, more-searched topic.
Is a SERP-based demand score the same as search volume?
No, and that honesty is the point. It is a relative prioritization score, not Google's exact internal number. It tells you which keywords are likely bigger and more commercial — perfect for ranking a list, not for forecasting precise traffic.
Does Serpent API have an autocomplete or keyword-volume endpoint?
Serpent does not expose a dedicated autocomplete or volume endpoint. It returns the SERP signals you need — relatedSearches, peopleAlsoAsk, ads presence and organic results — from the standard search endpoint, which you combine into your own score.
Can I add Google Trends to this score?
Yes. Google Trends gives a relative 0–100 interest figure (not absolute volume). Pulling it with a library like pytrends and blending it into your weighted score adds a useful time-and-popularity dimension to the SERP signals.



