SERP API Unit Semantics Decoded
SerpAPI charges 100 units per search, DataForSEO charges $0.0006 queue/$0.002 live. Scavio charges 1 credit = 1 request = $0.005. How unit semantics hide real costs.
SERP API pricing is nearly impossible to compare because every provider uses a different unit: DataForSEO charges per page of results, SerpAPI charges per search, Serper sells credit packs, Scavio charges one credit per request, and Exa charges per search plus per additional result. The only honest comparison normalizes everything to the same denominator: cost for 1,000 standard Google searches returning 10 organic results each.
The denominator problem
A "search" on SerpAPI includes one page of results. A "query" on DataForSEO returns one SERP page too, but queue pricing is 3x cheaper than live. Serper credits map 1:1 to searches but pack pricing varies by volume. Scavio credits are 1:1 with requests regardless of platform. Exa charges per search plus extra per batch of results beyond 10. You cannot compare headline numbers without normalizing.
Cost table: 1,000 Google searches, 10 results each
# Normalized cost for 1,000 Google SERP queries (10 organic results each)
cost_per_1k = {
"DataForSEO Queue": {"cost": 0.60, "unit": "$0.0006/query", "wait": "~5 min"},
"DataForSEO Live": {"cost": 2.00, "unit": "$0.002/query", "wait": "instant"},
"Serper (50k pack)": {"cost": 1.00, "unit": "$1/1k credits", "wait": "instant"},
"Serper (12.5M pack)": {"cost": 0.30, "unit": "$0.30/1k", "wait": "instant"},
"Scavio On-demand": {"cost": 5.00, "unit": "$0.005/credit", "wait": "instant"},
"Scavio Bootstrap": {"cost": 3.57, "unit": "$100/28k cr", "wait": "instant"},
"Exa Standard": {"cost": 7.00, "unit": "$7/1k searches", "wait": "instant"},
"SerpAPI Starter": {"cost": 25.00, "unit": "$25/1k searches","wait": "instant"},
}
print(f"{'Provider':<22} {'Cost/1k':>8} {'Unit':<20} {'Latency'}")
print("-" * 72)
for provider, d in sorted(cost_per_1k.items(), key=lambda x: x[1]["cost"]):
print(f"{provider:<22} ${d['cost']:>6.2f} {d['unit']:<20} {d['wait']}")Where each provider actually wins
DataForSEO queue is the cheapest option at scale if you can tolerate a five-minute delay. Serper wins on simplicity and speed at medium volumes. Scavio wins when you need multi-platform results (Google, Amazon, YouTube, Reddit, TikTok) under one API with one credit system. Exa wins for semantic search where you need meaning-based retrieval rather than keyword matching. SerpAPI wins on breadth of search engine coverage with support for dozens of engines.
Hidden multipliers that break your budget
# Common traps that inflate actual cost above headline pricing
traps = {
"Pagination": "Requesting page 2 of results = another query/credit on every provider",
"Localization": "Each country/language combo is a separate query",
"SERP features": "Some providers charge extra for AI overviews, shopping, etc.",
"Retries": "Failed requests may still count against your quota (check provider TOS)",
"Result depth": "Exa charges $1 per 1,000 additional results beyond first 10",
}
# Real scenario: daily monitoring of 50 keywords across 3 countries
daily_queries = 50 * 3 # 150 queries/day
monthly_queries = 150 * 30 # 4,500 queries/month
monthly_cost = {
"DataForSEO Queue": 4500 * 0.0006, # $2.70
"Serper (50k pack)": 4500 * 0.001, # $4.50
"Scavio On-demand": 4500 * 0.005, # $22.50
"Scavio Project": 30.00, # $30/mo for 7,000 credits (enough)
"SerpAPI Starter": 25.00, # $25/mo but only 1,000 searches
}
for provider, cost in sorted(monthly_cost.items(), key=lambda x: x[1]):
status = "OVER QUOTA" if provider == "SerpAPI Starter" else "OK"
print(f" {provider}: ${cost:.2f}/mo [{status}]")How to audit your real unit cost
import requests, os, time
def measure_effective_cost(provider_fn, queries: list, cost_per_query: float):
"""Run queries through a provider and compute effective cost including retries."""
total_calls = 0
successful = 0
for q in queries:
for attempt in range(3):
total_calls += 1
try:
result = provider_fn(q)
if result:
successful += 1
break
except Exception:
time.sleep(1)
effective_cost = total_calls * cost_per_query
cost_per_success = effective_cost / max(successful, 1)
return {
"total_calls": total_calls,
"successful": successful,
"retry_rate": (total_calls - successful) / total_calls,
"effective_cost_per_success": round(cost_per_success, 4),
}
# Example: Scavio effective cost measurement
def scavio_search(query):
resp = requests.post(
"https://api.scavio.dev/api/v1/search",
headers={"x-api-key": os.environ["SCAVIO_API_KEY"]},
json={"query": query, "platform": "google", "country_code": "us"},
timeout=10,
)
return resp.status_code == 200
# measure_effective_cost(scavio_search, keyword_list, 0.005)Picking the right unit for your use case
- Batch monitoring (daily keyword tracking): DataForSEO queue at $0.0006/query -- the delay does not matter
- Real-time agent workflows: Serper or Scavio -- both return in under 2 seconds
- Multi-platform search (Google + Amazon + Reddit): Scavio -- one API, one credit system, six platforms
- Semantic/meaning-based retrieval: Exa -- different category, not a direct SERP replacement
- Enterprise with existing SerpAPI integration: stay on SerpAPI unless cost is the primary concern
The cheapest API per unit is not always the cheapest in production. Factor in retries, pagination, multi-locale queries, and integration maintenance. Run a 1,000-query pilot on your actual workload before committing to annual contracts.