Calculating the effective cost per SERP API query requires factoring in utilization rate, feature gaps that force workarounds, engineering time spent on integration quirks, and LLM token overhead from verbose responses -- not just the sticker price per request. This tutorial builds a cost model that reveals the true per-query price for any SERP API so you can make apples-to-apples comparisons and avoid hidden expenses that inflate your bill.
Prerequisites
- Current SERP API billing data or pricing page details
- Python 3.9+ or Node.js 18+
- Estimate of monthly query volume and engineering hourly rate
Walkthrough
Step 1: Gather raw pricing inputs
Collect the sticker price, included query quota, overage rates, and any minimum commitments for each API you are comparing. Also record which features are included (structured data, knowledge panels, SERP features) versus which require additional calls.
providers = {
'provider_a': {
'plan_cost': 100,
'included_queries': 5000,
'overage_per_query': 0.025,
'has_structured_data': False,
'has_knowledge_panels': True,
'avg_response_tokens': 4200,
},
'scavio': {
'plan_cost': 100,
'included_queries': 28000, # $100/28K credits
'overage_per_query': 0.005,
'has_structured_data': True,
'has_knowledge_panels': True,
'avg_response_tokens': 1800,
},
}
monthly_queries = 15000
eng_hourly_rate = 75 # USDStep 2: Calculate base cost per query
Compute the base cost per query accounting for utilization. If you use only 60% of your included quota, the effective price per query is higher than the sticker price because you are paying for unused capacity.
def base_cost_per_query(provider, monthly_queries):
included = provider['included_queries']
plan_cost = provider['plan_cost']
if monthly_queries <= included:
# Paying for unused queries
utilization = monthly_queries / included
effective = plan_cost / monthly_queries
else:
overage = monthly_queries - included
total_cost = plan_cost + (overage * provider['overage_per_query'])
effective = total_cost / monthly_queries
utilization = 1.0
return {
'effective_per_query': round(effective, 5),
'utilization': round(utilization * 100, 1),
'monthly_total': round(effective * monthly_queries, 2),
}Step 3: Add feature gap surcharge
If a provider lacks structured data extraction, you need extra engineering time or additional API calls to get that data. Estimate the monthly engineering hours spent on workarounds and add that to the cost.
def feature_gap_cost(provider, monthly_queries, eng_hourly_rate):
hours_per_month = 0
extra_queries = 0
if not provider['has_structured_data']:
# Estimate 4 hours/month building and maintaining parsing logic
hours_per_month += 4
# 10% of queries need a follow-up call to get structured data
extra_queries += int(monthly_queries * 0.10)
eng_cost = hours_per_month * eng_hourly_rate
extra_query_cost = extra_queries * provider['overage_per_query']
return {
'eng_hours': hours_per_month,
'eng_cost': eng_cost,
'extra_queries': extra_queries,
'extra_query_cost': extra_query_cost,
'total_gap_cost': eng_cost + extra_query_cost,
}Step 4: Estimate LLM token overhead
If you pipe SERP results into an LLM, verbose API responses cost more in tokens. Calculate the monthly token cost difference based on average response size. At typical LLM input pricing of $3 per million tokens, this adds up quickly at scale.
def llm_token_cost(provider, monthly_queries, cost_per_million_tokens=3.0):
total_tokens = provider['avg_response_tokens'] * monthly_queries
cost = (total_tokens / 1_000_000) * cost_per_million_tokens
return {
'total_tokens': total_tokens,
'monthly_llm_cost': round(cost, 2),
'per_query_llm_cost': round(cost / monthly_queries, 6),
}Step 5: Compute total effective cost and compare
Sum up base cost, feature gap surcharge, and LLM token overhead to get the true effective cost per query. Print a comparison table so you can see which provider is actually cheapest for your workload.
print(f'Monthly volume: {monthly_queries:,} queries\n')
print(f'{"Provider":<15} {"Base":>8} {"Gaps":>8} {"LLM":>8} {"Total":>8} {"Per-Query":>10}')
print('-' * 65)
for name, p in providers.items():
base = base_cost_per_query(p, monthly_queries)
gaps = feature_gap_cost(p, monthly_queries, eng_hourly_rate)
llm = llm_token_cost(p, monthly_queries)
total = base['monthly_total'] + gaps['total_gap_cost'] + llm['monthly_llm_cost']
per_query = total / monthly_queries
print(f'{name:<15} ${base["monthly_total"]:>7.2f} ${gaps["total_gap_cost"]:>7.2f} ${llm["monthly_llm_cost"]:>7.2f} ${total:>7.2f} ${per_query:>9.5f}')Python Example
providers = {
'provider_a': {
'plan_cost': 100,
'included_queries': 5000,
'overage_per_query': 0.025,
'has_structured_data': False,
'has_knowledge_panels': True,
'avg_response_tokens': 4200,
},
'scavio': {
'plan_cost': 100,
'included_queries': 28000,
'overage_per_query': 0.005,
'has_structured_data': True,
'has_knowledge_panels': True,
'avg_response_tokens': 1800,
},
}
monthly_queries = 15000
eng_hourly_rate = 75
def base_cost_per_query(provider, monthly_queries):
included = provider['included_queries']
plan_cost = provider['plan_cost']
if monthly_queries <= included:
effective = plan_cost / monthly_queries
else:
overage = monthly_queries - included
total_cost = plan_cost + (overage * provider['overage_per_query'])
effective = total_cost / monthly_queries
return round(effective * monthly_queries, 2)
def feature_gap_cost(provider, monthly_queries, eng_rate):
hours = 0 if provider['has_structured_data'] else 4
extra_queries = 0 if provider['has_structured_data'] else int(monthly_queries * 0.10)
return hours * eng_rate + extra_queries * provider['overage_per_query']
def llm_token_cost(provider, monthly_queries):
tokens = provider['avg_response_tokens'] * monthly_queries
return round((tokens / 1_000_000) * 3.0, 2)
print(f'Monthly volume: {monthly_queries:,} queries')
print(f'{"Provider":<15} {"Base":>8} {"Gaps":>8} {"LLM":>8} {"Total":>8} {"Per-Query":>10}')
print('-' * 65)
for name, p in providers.items():
base = base_cost_per_query(p, monthly_queries)
gaps = feature_gap_cost(p, monthly_queries, eng_hourly_rate)
llm = llm_token_cost(p, monthly_queries)
total = base + gaps + llm
per_q = total / monthly_queries
print(f'{name:<15} ${base:>7.2f} ${gaps:>7.2f} ${llm:>7.2f} ${total:>7.2f} ${per_q:>9.5f}')JavaScript Example
const providers = {
provider_a: {
planCost: 100,
includedQueries: 5000,
overagePerQuery: 0.025,
hasStructuredData: false,
avgResponseTokens: 4200,
},
scavio: {
planCost: 100,
includedQueries: 28000,
overagePerQuery: 0.005,
hasStructuredData: true,
avgResponseTokens: 1800,
},
};
const monthlyQueries = 15000;
const engHourlyRate = 75;
function baseCost(p, queries) {
if (queries <= p.includedQueries) return p.planCost;
const overage = queries - p.includedQueries;
return p.planCost + overage * p.overagePerQuery;
}
function featureGapCost(p, queries, engRate) {
if (p.hasStructuredData) return 0;
const engCost = 4 * engRate;
const extraQueries = Math.floor(queries * 0.1) * p.overagePerQuery;
return engCost + extraQueries;
}
function llmTokenCost(p, queries) {
const tokens = p.avgResponseTokens * queries;
return (tokens / 1_000_000) * 3.0;
}
console.log(`Monthly volume: ${monthlyQueries.toLocaleString()} queries`);
console.log('Provider Base Gaps LLM Total Per-Query');
console.log('-'.repeat(60));
for (const [name, p] of Object.entries(providers)) {
const base = baseCost(p, monthlyQueries);
const gaps = featureGapCost(p, monthlyQueries, engHourlyRate);
const llm = llmTokenCost(p, monthlyQueries);
const total = base + gaps + llm;
const perQ = total / monthlyQueries;
console.log(
`${name.padEnd(15)} $${base.toFixed(2).padStart(7)} $${gaps.toFixed(2).padStart(7)} $${llm.toFixed(2).padStart(7)} $${total.toFixed(2).padStart(7)} $${perQ.toFixed(5).padStart(9)}`
);
}Expected Output
Monthly volume: 15,000 queries
Provider Base Gaps LLM Total Per-Query
-----------------------------------------------------------------
provider_a $350.00 $337.50 $189.00 $876.50 $0.05843
scavio $100.00 $0.00 $81.00 $181.00 $0.01207