Rank Tracking API: Build Your Own Google Rank Tracker With Two Sources

Key takeaways

One API is free and only sees your own site. The other costs money and sees everything. Combine them and you own a rank tracker that costs less than a seat licence. Here is the build, the request math, and the guardrails.

A rank tracking API is not one thing. Developers searching for "rank tracking API" usually want a single endpoint that returns positions, and the market answers with vendor listicles. The honest answer is that you need two sources, and they answer different questions.

The Search Console API is free, official, and permanently limited to properties you can verify. A SERP API is paid, unofficial, and can check any keyword anywhere, including keywords you have never ranked for. Neither one alone is a rank tracker. Together, they are about 120 lines of Python and a cron entry.

This is the build. It assumes you can run a script and store a file. It does not assume you want to build a product.

What you will finish with

Who this is for: a developer or technical marketer who already has Search Console access and wants positions on a schedule without paying per seat.

What you will have when you are done: two working pull functions, one merged output file per run, and a comparison rule that stops the numbers from lying to you.

Time: about 90 minutes for the first build, then roughly 10 minutes of review per run.

Done looks like: a dated JSON file containing your own positions by query and device, plus live SERP snapshots for a frozen keyword list, and a short diff against the previous run.

Before you start: what each source can and cannot do

Get this split right and the rest of the build is mechanical. Get it wrong and you will spend a month building something either useless or expensive.

Search Console API

SERP API

Whose positions

Your verified properties only

Anyone, including competitors

Keywords

Queries you already appear for

Any keyword you type

Cost

Free

Billed per request

Device split

Yes, as a dimension

Yes, per request

Location

Countries you rank in

Any location the vendor supports

Data type

Aggregate clicks, impressions, position

Point-in-time result page

Historical depth

The range you request

Only from the day you start storing it

Official status

Google's own data

A third party's reading of a public page

The two sources will disagree, and that disagreement is informative rather than a bug. Search Console averages every impression across the date range and every device. A SERP pull is one result page at one moment. If you compare them directly you will chase phantom drops, which is why step five below defines a comparison rule.

Three numbers worth knowing before you write code. The Search Console API accepts a row limit between 1 and 25,000 per request and defaults to 1,000, so a mid-size site can pull three months of query and device data in a single call. It allows 1,200 queries per minute per site and per user. And it enforces load quotas measured in 10-minute chunks, where a long date range costs more than a short one, which is exactly why Google's own guidance says to avoid re-querying the same data.

Two-source architecture diagram showing the Search Console API feeding own-site positions and a SERP API feeding external keyword snapshots into one merged tracker file

Two sources, one output. Search Console answers "where do I appear", a SERP API answers "what does the page look like".

Step 1: freeze the keyword set before you write any code

A tracker that pulls a different keyword list every run cannot answer whether anything changed. Pick the list first and keep it for a quarter.

Three groups, and they come from different sources.

  • From Search Console: every query with at least 20 impressions in the last 90 days. You do not choose these; your impressions do. This is the group where movement means something, because there is already demand attached.
  • From the business: the ten to twenty queries that map to revenue, whether or not you rank for them yet.
  • From competitors: the queries a competitor ranks for that you do not. These need a SERP API because Search Console will never show them.

Write the list to a file, version it, and treat additions as a deliberate change rather than a drift.

Step 2: pull your own positions for free

This half is official, free, and gives you device split and click data that no SERP API has.

python
from google.oauth2 import service_account
from googleapiclient.discovery import build

service = build(
    "searchconsole", "v1",
    credentials=service_account.Credentials.from_service_account_file(
        "gsc-key.json",
        scopes=["https://www.googleapis.com/auth/webmasters.readonly"],
    ),
)

body = {
    "startDate": "2026-06-14",
    "endDate": "2026-09-11",
    "dimensions": ["query", "device"],
    "type": "web",
    "dataState": "final",
    "rowLimit": 25000,
}

rows = service.searchanalytics().query(
    siteUrl="sc-domain:example.com", body=body
).execute().get("rows", [])

Two details in that request do most of the work.

dataState: "final" excludes fresh data that Google may still revise. Without it, the newest two or three days shift between runs and your diff shows movements that never happened.

dimensions: ["query", "device"] is what makes the output useful later. Adding device now costs nothing. Re-pulling three months of history later costs a full run and gives you nothing for the days you already skipped.

Expected output: one row per query and device, with clicks, impressions, CTR, and average position.

Quality check: the row count should be under 25,000. If it hits exactly 25,000, you are truncated and need a second call with startRow: 25000.

If it fails: a 403 usually means the service account email was never added as a user on the property. Add it in Search Console, wait a few minutes, retry.

Step 3: pull the SERPs you cannot see in your own data

The second half covers everything Search Console structurally cannot. This is a minimal working call.

python
import base64, json, urllib.request

LOGIN, PASSWORD = "your-login", "your-password"

def serp(keyword, depth=100):
    token = base64.b64encode(f"{LOGIN}:{PASSWORD}".encode()).decode()
    payload = json.dumps([{
        "keyword": keyword,
        "location_name": "United States",
        "language_name": "English",
        "depth": depth,
    }]).encode()
    request = urllib.request.Request(
        "https://api.dataforseo.com/v3/serp/google/organic/live/advanced",
        data=payload,
        headers={"Authorization": f"Basic {token}",
                 "Content-Type": "application/json"},
        method="POST",
    )
    return json.loads(urllib.request.urlopen(request, timeout=120).read())

Set `depth` to 100, not 200. We tested this in September 2026 by requesting 200 results across six queries. Google returned 83 to 128 organic results and stopped, with the deepest position anywhere in the test at 142. The full test is here. Asking for 200 does not get you 200 results, and depending on the vendor it may still bill you for the depth you requested. Request 100 and you will almost always receive everything that exists.

Bar chart showing the number of organic results Google served for six test queries, all below 130, against a requested depth of 200

Requesting 200 results and receiving 83 to 128. Depth above roughly 140 buys nothing on most commercial queries.

Expected output: a JSON payload containing organic items with position, URL, title, and domain.

Quality check: confirm the payload contains an ai_overview item type when one is present. If you only extract organic items you will miss why a page lost clicks while holding its position.

If it fails: a 401 is a base64 or credential error. A 40200-style code means your account balance is empty, which is the most common failure in the first month.

Step 4: store the raw payload, not the summary

This is the decision people regret skipping.

Storing a table of positions works until you need to ask a question you did not anticipate: did the SERP get longer, did video take over, did a competitor enter, did an AI Overview appear above the fold. A summary cannot answer those. The raw payload can, at zero extra cost.

The practical version: write one file per run, named for the date and time, containing the merged output. Keep the last 90 days. That is small enough to live in a repository and complete enough to re-answer old questions.

Step 5: write the comparison rule before you schedule anything

A tracker that compares the last run to this run produces a false alarm on most days. Our own numbers show why: across 124 queries with at least 30 impressions, the average query moved 4.57 positions from one day to the next. A four-position drop is a Tuesday.

So the rule needs a threshold and a direction.

text
Report a query only when:
  - absolute position change vs the previous run is 5 or more, AND
  - the query had at least 20 impressions in the comparison window, AND
  - the change is not explained by a device mix shift

Group the output by query class: money, comparison, brand, informational.
Do not suggest fixes.

The device clause is not decoration. The same query can sit 11 positions apart on mobile and desktop, and if the device mix moves between runs, the blended number moves too. We measured that separately and it is large enough to fake a trend.

What it costs

Vendor prices change, so build the model instead of chasing a quote.

  • One keyword checked once per day for 30 days is 30 requests per month.
  • A 200-keyword set checked daily is 6,000 requests per month.
  • The same set checked weekly is about 860 requests per month.
  • The Search Console half is free and is one request per view, regardless of how many keywords are inside it.

That multiplication is the whole decision. Almost every "should I buy a tool" question collapses to it: work out requests per month, multiply by your per-request price, and compare with the seat licence. Daily tracking of a large keyword set is usually cheaper as a subscription. Weekly tracking of a small set is usually cheaper as an API. Track a frozen list and the API side stays small.

When to buy instead of build

Build this if you want positions in your own pipeline, you already own a SERP API credential, or you need the raw result page for reasons beyond position.

Buy instead if you need historical positions from before today, if you need ten locations and five devices for the same keywords, or if nobody on the team will maintain a cron job. Vendor listicles are worth reading for exactly this reason, and there is a real cost to owning infrastructure that stops running when the person who built it changes teams.

If the output you actually need is a written weekly report rather than a JSON file, the Codex reporting workflow starts from the same two sources and ends in a document. For alerting on top of the file, the monitor design guide covers the thresholds.

Auspia view: the rank tracking API question is really a data ownership question. Search Console gives you official data on your own property for free and always will. Everything else is a snapshot you pay for. Build the free half first, add the paid half only where it answers a question you actually have.

FAQ

Does Google offer a rank tracking API? Not a public one. The Search Console API returns your average position for queries you already appear for, which is close but not the same thing. It cannot check a keyword you do not rank for, and it cannot check a competitor.

How deep can a SERP API go? Vendors will accept depth values well above 200, but Google stops serving results somewhere around 100 to 140 on most commercial queries. Requesting more does not produce more results.

Should I use daily or weekly checks? Weekly for a normal keyword set. Daily only for a short list of money queries. Daily checks on a large set multiply cost by seven and mostly measure noise, since the average daily movement in our own data was 4.57 positions.

Why does my API number differ from my rank tracker? Different devices, different locations, different moments, and often different data sources. The number is a sample. Fix the location and device in your request and re-pull before concluding that anything changed.

Can an agent run this for me? Yes, and it is a good fit because the task has the same shape every run. For the wider picture of what an agent can own in ranking work, see the SEO agent field guide. Keep the comparison rule in a written instruction file and let the agent produce the diff; keep the buy-or-build decision with a person.

Author: Rowan Blake, Content Automation Analyst for 100+ Publishing Pipelines at Auspia. Rowan writes about automated data pipelines, scheduled reporting, and the maintenance cost of systems that run without you.

Explore this topic

Keep following the same growth thread