Keyword Volume API Accuracy Problem
SEMrush groups close variants showing identical volumes. Keyword Planner shows ranges. How to cross-check keyword volume across DataForSEO, Scavio, and GSC.
SEMrush groups close keyword variants together and reports the same search volume for all of them. Google Keyword Planner shows ranges (1K-10K) instead of exact numbers unless you are running ads. Ahrefs uses clickstream data that underestimates long-tail queries. Every keyword volume source has known inaccuracies, and understanding them is more important than trusting any single number.
How each source distorts volume
- Google Keyword Planner: bucketed ranges (10-100, 100-1K, 1K-10K). Exact numbers require active ad spend. Merges close variants.
- SEMrush: groups "best crm" and "best crms" under the same volume. Useful for topic-level thinking, misleading for per-keyword decisions.
- Ahrefs: clickstream-derived estimates. Better for head terms, weaker for long-tail. Updates monthly.
- DataForSEO: returns Google Keyword Planner data programmatically. Same bucketing issues unless you use the live endpoint with an active Ads account.
The cross-checking approach
No single source is accurate. The practical approach: use two sources, compare, and treat volume as a directional signal rather than an exact number. A keyword showing 1K in Ahrefs and 1K-10K in Planner is probably in the low thousands. That is precise enough for prioritization.
import requests, os
H = {"x-api-key": os.environ["SCAVIO_API_KEY"]}
def check_serp_competition(keyword: str):
"""Use actual SERP data as a volume proxy.
More organic results with dates = more competitive = likely higher volume."""
resp = requests.post("https://api.scavio.dev/api/v1/search",
headers=H, json={"query": keyword})
data = resp.json()
organic = data.get("organic_results", [])
paa = data.get("people_also_ask", [])
return {
"keyword": keyword,
"organic_count": len(organic),
"has_paa": len(paa) > 0,
"has_ads": bool(data.get("ads", [])),
"has_ai_overview": bool(data.get("ai_overview")),
"related_searches": [r.get("query") for r in data.get("related_searches", [])[:5]],
}
# SERP features as volume/competition signals
result = check_serp_competition("best crm for startups 2026")
print(f"Organic results: {result['organic_count']}")
print(f"Has ads: {result['has_ads']} (ads = commercial intent + volume)")
print(f"Has AI Overview: {result['has_ai_overview']}")
print(f"Related searches: {result['related_searches']}")SERP features as volume proxies
Instead of trusting reported volume numbers, check what Google shows for the keyword. Ads indicate commercial intent and sufficient volume for advertisers to bid. People Also Ask boxes appear for queries with diverse intent. AI Overviews appear for informational queries with high volume. These SERP features are free signals you can check with any search API.
The practical rule
Treat keyword volume as a tier (low / medium / high / very high), not a number. Cross-check with SERP features and competition level. If a keyword has ads, PAA, and AI Overview, it has meaningful volume regardless of what any tool reports. If it shows a bare SERP with 10 blue links and no features, volume is likely low. The SERP itself is the most honest signal.