Simple Rank Tracker in Python: Build a Complete SEO Tool in 7 Steps

Simple Rank Tracker

Build a simple rank tracker in Python that checks keyword positions through a compliant SERP API, stores history, and charts movement, no manual spreadsheet checking required.

Development Python Rank Tracking SERP API

Typing forty keywords into an incognito window every Monday is not rank tracking, it is a chore that produces unreliable numbers. A simple rank tracker in python runs the same check the same way, every time, and remembers what it found.

A client once tracked two hundred keywords by hand in a spreadsheet. Someone spent most of a Monday morning searching each one and writing down where the site landed.

The numbers were never quite trustworthy. Personalization, location, and small mistakes in a long manual process all crept in somewhere along the way.

A simple rank tracker in python fixes both problems at once. It checks every keyword the same way every time, and it never gets tired on keyword one hundred and eighty.

This guide builds one using a proper SERP API rather than scraping Google directly, stores the results with history attached, and turns raw positions into a chart that actually shows movement.

None of it needs a paid rank tracking platform. A SERP API key, a Python environment, and a place to store a growing CSV cover the whole build.

200+keywords a script checks in the time one manual search used to take
1 methodstays reliable long term: a proper SERP API, not direct scraping
0personalization bias, since every check uses the same clean parameters
01

Why a Simple Rank Tracker in Python Beats Manual Checking

Manual rank checking has a quality problem before it even has a scale problem. Google personalizes results based on location, device, and search history, so the same query can return a different order for two different people.

Incognito mode helps a little. It does not remove location signals or device differences, which means two people checking the same keyword in incognito can still see two different rankings.

A script run with fixed parameters does not have that inconsistency. The same location, the same device setting, and the same query structure every single time make the resulting numbers actually comparable week to week.

Comparing keyword rank against a broader keyword research process becomes far more useful once the tracking data behind it is this consistent.

02

Choosing a Compliant Way to Check Rankings

How a rank tracker actually gets its data matters more than most guides admit. Scraping Google's results pages directly sits outside Google's terms of service, and it tends to break the moment a CAPTCHA shows up.

A dedicated SERP API is the sustainable choice. These services run the search on Google's behalf through infrastructure built for exactly this, and return clean, structured results instead of raw HTML to parse and hope holds together.

MethodComplianceReliabilityCost
Direct scraping of Google resultsOutside Google's termsBreaks often, blocked frequentlyFree until it stops working
Dedicated SERP APICompliant, run through licensed infrastructureConsistent, structured resultsUsage based, this guide's approach
Search Console average positionFully compliant, official Google dataAggregated, not a per search snapshotFree with a verified property

This guide builds around a SERP API, using SerpApi as the working example. The same pattern applies to comparable providers, since most return organic results in a similar structured shape.

03

Setting Up Your Python Environment

Terminal: project setup
# create an isolated environment so package versions don't clash
python -m venv venv
source venv/bin/activate      # Windows: venv\Scripts\activate

pip install google-search-results python-dotenv pandas

The google-search-results package is SerpApi's official client, despite the slightly generic sounding name. python-dotenv keeps the API key out of the code, and pandas holds every result once it comes back.

04

Checking a Single Keyword's Position

A single search returns a list of organic results, each with its own position. Finding your own domain in that list is the entire job.

rank_checker.py
import os
from dotenv import load_dotenv
from serpapi import GoogleSearch

load_dotenv()
API_KEY = os.getenv("SERPAPI_KEY")

def check_rank(keyword: str, target_domain: str, location: str = "United States") -> dict:
    params = {
        "engine": "google",
        "q": keyword,
        "location": location,
        "api_key": API_KEY,
    }

    search = GoogleSearch(params)
    results = search.get_dict()
    organic = results.get("organic_results", [])

    for result in organic:
        if target_domain in result.get("link", ""):
            return {"keyword": keyword, "position": result.get("position"), "url": result.get("link")}

    return {"keyword": keyword, "position": None, "url": None}

A None position is not an error, it is real information. The domain genuinely did not appear in the organic results the API returned for that search.

05

Tracking Multiple Keywords and Locations

A real tracker checks a whole list, and often needs to check it against more than one location if the business serves more than one market.

batch_check.py
import time
import pandas as pd
from rank_checker import check_rank

KEYWORDS = ["python for seo", "rank tracker api", "seo automation tools"]
LOCATIONS = ["United States", "United Kingdom"]
TARGET_DOMAIN = "brandella.in"

def run_batch() -> pd.DataFrame:
    rows = []

    for location in LOCATIONS:
        for keyword in KEYWORDS:
            result = check_rank(keyword, TARGET_DOMAIN, location)
            result["location"] = location
            rows.append(result)
            time.sleep(1)   # stay well under API rate limits

    return pd.DataFrame(rows)

The one second pause between calls, using Python's own time.sleep(), is not strictly required by every provider, but it keeps a large batch well behaved and avoids tripping a rate limit partway through a run.

06

Storing Rank History Over Time

A single day of positions is a snapshot. History is what actually makes a simple rank tracker in python worth running, since movement only means something when you can see it against what came before.

append_history.py
import os
from datetime import date
import pandas as pd

HISTORY_PATH = "data/rank_history.csv"

def append_history(df: pd.DataFrame):
    df["checked_on"] = date.today().isoformat()

    if os.path.exists(HISTORY_PATH):
        existing = pd.read_csv(HISTORY_PATH)
        combined = pd.concat([existing, df]).drop_duplicates(
            subset=["keyword", "location", "checked_on"]
        )
    else:
        combined = df

    combined.to_csv(HISTORY_PATH, index=False)

Running this daily or weekly through GitHub Actions, the same scheduling pattern used across the rest of this series, is what turns a one time check into an actual tracker.

07

Visualizing Rank Movement

A table of numbers is accurate but hard to read at a glance. A simple line chart, built with matplotlib, makes movement obvious in a way a spreadsheet full of positions never quite does.

plot_history.py
import pandas as pd
import matplotlib.pyplot as plt

def plot_keyword_history(history_path: str, keyword: str):
    df = pd.read_csv(history_path)
    subset = df[df["keyword"] == keyword].sort_values("checked_on")

    plt.plot(subset["checked_on"], subset["position"], marker="o")
    plt.gca().invert_yaxis()   # position 1 should sit at the top
    plt.title(f"Ranking history: {keyword}")
    plt.xlabel("Date checked")
    plt.ylabel("Position")
    plt.xticks(rotation=45)
    plt.tight_layout()
    plt.savefig(f"charts/{keyword.replace(' ', '_')}.png")

Inverting the axis is a small detail that matters a lot. Without it, a page climbing from position ten to position one draws a line heading downward, which reads backward to anyone glancing at the chart.

08

Handling No Rank Results, Volatility, and API Costs

A working script still needs a few judgment calls built in, or the numbers it produces will mislead more than they inform. Search Engine Journal's guide to rank tracking covers several of these same pitfalls from a broader, tool agnostic angle worth reading alongside a simple rank tracker in python.

  • Not ranked is a real answer: treat a missing position as data, not a bug, and record it as such rather than skipping the row.
  • Single day swings are common: positions naturally move a spot or two day to day. Look at a multi day trend before reacting to any one number.
  • API calls cost money at scale: a large keyword list checked daily across several locations adds up fast. Budget for it before committing to a schedule.
  • Location genuinely changes results: never assume a national average position reflects what a searcher in a specific city actually sees.
  • Keep the target domain check flexible: match on domain, not full URL, so a page that changes its path does not silently vanish from tracking.

Monthly SERP API Cost Estimator

Estimate the monthly call volume for a tracking schedule, based on keywords, locations, and check frequency.

100 keywords
1 check per week
400Estimated API calls per month
4Tracking runs per month
09

Watch: A Quick Tour of a SERP API in Practice

SerpApi, the company whose API this guide builds around, published an official walkthrough of the same search endpoint and response structure used in the code above.

Video credit: SerpApi, LLC.

Seeing the raw response structure in the video makes it clear why parsing organic_results in Python is as simple as the code in this guide shows it to be.

Keyword List and Locations SERP API Call Position Match History Chart

Frequently Asked Questions

Directly scraping Google's results pages falls outside Google's terms of service and tends to get blocked quickly. A licensed SERP API runs the same search through infrastructure built for exactly this, which is the compliant and durable approach.

Just as accurate for the core number, since both pull from the same kind of SERP API data underneath. Paid platforms mostly add convenience features like dashboards and alerts on top of the same raw check.

Weekly is a reasonable default for most sites. Daily checks make sense for a small set of high value keywords, but running the full list daily usually costs more than the extra detail is worth.

Yes. Most SERP APIs accept a location parameter, and looping the same keyword across several locations is exactly what the batch checking example in this guide does.

It means the target domain did not appear anywhere in the organic results the API returned for that search, typically the first page or two. It is a real result worth recording, not something to filter out.

What We Learn Today

1

Manual checks are inconsistent

Personalization and location make hand checked rankings hard to compare over time.

2

Method matters more than speed

A compliant SERP API beats direct scraping on reliability, not just on legality.

3

Position matching is simple

Finding a domain inside organic results is a short loop, not complex logic.

4

History is the actual product

A single check is a snapshot. Stored history is what makes movement visible.

5

Charts beat spreadsheets

An inverted line chart makes rank movement obvious at a glance.

6

Cost scales with ambition

More keywords, more locations, and more frequency all add up in API calls.

Ready to Track Rankings on Your Own Terms?

Pair a simple rank tracker in python with a wider SEO toolkit to see the full picture behind every ranking change.

0 Votes: 0 Upvotes, 0 Downvotes (0 Points)

Leave a reply

Loading Next Post...
Search
Popular Now
Loading

Signing-in 3 seconds...

Signing-up 3 seconds...