Local Rank Tracking in Python: Track a Keyword in a Place
Local rank tracking answers a question that ordinary rank tracking cannot: where does my site rank for a keyword when a searcher in a specific place looks for it? “Best dentist austin” and “best dentist” are different searches. And the SERP for a keyword looks different from Austin than it does from London, Berlin, or Delhi. If your business serves specific cities, states, or countries, the only ranking that matters is the one a local searcher actually sees.
The good news is that the whole thing reduces to a single field. Every organic result returned by Serpent's search endpoint ships with a 1-indexed position field — no opt-in, no special flag. This tutorial walks through tracking a keyword in a place, from the first request to a loop that monitors the same keyword across many locations.
TL;DR: Call /api/search?q=KEYWORD&country=US&engine=google with an X-API-Key header. Every item in results.organic carries a 1-indexed position. Find your domain, read its position, and loop the same keyword over a list of locations to build a multi-location local rank tracker. Supports Google, Bing, Yahoo, DuckDuckGo, and Brave.
What local rank tracking actually measures
Local rank tracking is position tracking with a location attached. Instead of asking “where do I rank for this keyword?” you ask “where do I rank for this keyword as seen from this country or city?” That distinction is why agencies and multi-location businesses treat local rank tracking as its own discipline — a business with branches in five cities can rank first in one and miss the top 50 in another.
The primitive underneath it is the position field: a 1-indexed integer on every organic result, on every engine, always present. Position 1 is the first organic result a searcher sees; position 40 means your page is well into the deep results. You never guess or interpolate — the field is returned for every result, so your tracker is only ever one filter away from an answer.
The endpoint and the parameters that matter
Local rank tracking runs on the same search endpoint as everything else: /api/search. What makes it local is the set of parameters you send alongside the query.
| Parameter | What it does |
|---|---|
q | The keyword. Add a city or region ("dentist austin") to capture location-qualified local intent |
engine | google, bing, yahoo, or ddg — five engines including Brave |
country | Two-letter ISO code (us, gb, de, in, 50+ more) — returns the rankings a searcher in that country sees |
language | Two-letter ISO 639-1 code (en, es, de...) to set result language; auto-detected from country when omitted |
num | How many organic results to return, up to 100 (default 10) — pull deep to catch competitors below the fold |
pages | How many result pages to fetch, 1–10. Positions stay sequential across pages |
That is the whole surface for a local tracker. A request that targets a country looks like this:
https://apiserpent.com/api/search?q=emergency+plumber+austin&engine=google&country=us&num=100
The country parameter is what localizes the results. Change it and you get the SERP a searcher in that market would see, from the same code path.
A working example in Node and Python
Here is the entire local rank check in Node.js with fetch, sending the keyword, engine, and country target, and looking up your own domain in the results:
const res = await fetch(
'https://apiserpent.com/api/search?q=emergency+plumber+austin&engine=google&country=us&num=100',
{ headers: { 'X-API-Key': 'YOUR_API_KEY' } }
);
const json = await res.json();
for (const r of json.results.organic) {
if (r.url.includes('yoursite.com')) {
console.log('Rank #' + r.position + ':', r.title, r.url);
}
}
The same call in Python is nearly identical — swap fetch for requests:
import requests
resp = requests.get(
"https://apiserpent.com/api/search",
headers={"X-API-Key": "YOUR_API_KEY"},
params={"q": "emergency plumber austin", "engine": "google",
"country": "us", "language": "en", "num": 100},
)
for r in resp.json()["results"]["organic"]:
if "yoursite.com" in r["url"]:
print("Rank #" + str(r["position"]), r["title"])
Either way, the pattern is the same: request, iterate, filter on your domain, read the position. If your domain never appears, the keyword is outside the top num results — pull a larger num to confirm.
Reading the response: the position field
Each organic result is a small object with position, title, url, and snippet. The response shape is identical across every engine, which is what makes cross-engine tracking so cheap to build:
{
"success": true,
"engine": "google",
"country": "us",
"results": {
"organic": [
{
"position": 1,
"title": "...",
"url": "https://example.com",
"snippet": "..."
},
{ "position": 2, "title": "...", "url": "...", "snippet": "..." },
{ "position": 3, "title": "...", "url": "...", "snippet": "..." }
]
},
"metadata": { "totalOrganicResults": 100 }
}
Notice position on every item. There is no separate “local ranking” endpoint to learn and no per-engine response shape to handle — the field is always there, and it is the only thing your tracker needs to store to build a ranking history.
One keyword, many locations
Multi-location tracking is just the single call above, repeated. Loop the same keyword over every location you serve, store each position, and you get a per-location ranking matrix for one keyword:
const locations = [["us", "en"], ["gb", "en"], ["de", "de"], ["in", "en"]];
for (const [country, language] of locations) {
const res = await fetch(
`https://apiserpent.com/api/search?q=emergency+plumber&engine=google&country=${country}&language=${language}`,
{ headers: { 'X-API-Key': 'YOUR_API_KEY' } }
);
const json = await res.json();
const hit = json.results.organic.find(r => r.url.includes('yoursite.com'));
console.log(country, hit ? '#' + hit.position : 'not ranked');
}
Schedule that loop on any interval — daily is typical — and store each row in a database. You now have a continuous local rank history: which markets you lead, which you lost ground in, and exactly when a position changed.
Local pack and map pack visibility
For local-intent queries — “plumber near me”, “best dentist”, “[service] [city]” — the SERP a local searcher sees includes a local pack or map pack. The response captures that surface too, so you can monitor your local pack presence and watch which competitors hold the top local positions. Run the same query on a schedule and store each result set to chart how your local pack visibility changes over time. You are not limited to Google either: the same position-based contract works across all tracked engines, which is handy for agencies that report on more than one search engine.
Pricing and getting started
Local rank tracking is priced per call, not per tracked keyword. Google rankings start at $0.03 per 1,000 pages at the Scale tier. There is no subscription and no per-keyword or per-location fee — you pay for what you request. Every account gets 10 shared free calls on eligible endpoints to start, and depositing $100 unlocks 10x lower pricing (20x at $500). Tracking a few hundred local keywords across several locations daily costs cents per month.
Read the position. Track the place.
Serpent returns the 1-indexed position on every organic result for Google, Bing, Yahoo, DuckDuckGo, and Brave through one endpoint. New accounts include 10 shared free calls on eligible endpoints, then pay-as-you-go pricing with no subscription.
Get Your Free API KeyExplore: Local Rank Tracking API · Rank Tracking API · Docs · Playground
FAQ
How does local rank tracking work?
You send a keyword plus a location target — a country code and optionally a language code — and read the 1-indexed position field on every organic result. Find your domain in the results and its position is your rank as a searcher in that location would see it.
Which search engines can I track local rankings on?
Google, Bing, Yahoo, DuckDuckGo, and Brave. Pass engine=google, engine=bing, engine=yahoo, or engine=ddg. Each engine returns the same response shape with a position field on every organic result, so the tracking code is identical across engines.
How is location targeting handled?
Pass country with a two-letter ISO code (country=us, country=gb, country=de, country=in, and 50+ more) to get the rankings a searcher in that country sees, and language with a two-letter code to set the result language. Combine that with location-qualified keywords like "dentist austin" to capture city-level local intent.
How much does local rank tracking cost?
Google rankings start at $0.03 per 1,000 pages at the Scale tier. There is no subscription and no per-tracked-keyword fee — you pay per call. Every account gets 10 shared free calls on eligible endpoints to start, and depositing $100 unlocks 10x lower pricing (20x at $500).

