Local Rank Tracking in Python: Track a Keyword in a Place

By Serpent API Team · · 6 min read

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.

ParameterWhat it does
qThe keyword. Add a city or region ("dentist austin") to capture location-qualified local intent
enginegoogle, bing, yahoo, or ddg — five engines including Brave
countryTwo-letter ISO code (us, gb, de, in, 50+ more) — returns the rankings a searcher in that country sees
languageTwo-letter ISO 639-1 code (en, es, de...) to set result language; auto-detected from country when omitted
numHow many organic results to return, up to 100 (default 10) — pull deep to catch competitors below the fold
pagesHow many result pages to fetch, 110. 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 Key

Explore: 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).