DEV Community

dodou
dodou

Posted on

How I monitor my brand's Google ranking for 90 cents a month

I needed to track where my domain ranks for ~100 keywords on Google. Every tool I tried was either too expensive ($50–$130/month), too fragile (the captcha treadmill), or too complex (full SEO suites with 200 features I didn't need).

So I built my own. 30 lines of Python, scheduled with cron, runs every morning. Total cost: $0.90 per month.

This post walks through the architecture, the code, and the math.

The cost ceiling

I gave myself a $1/month budget. The Starter Boost tier I picked is $3 for 10,000 searches, expires one month after purchase. That works out to $0.30 per 1,000 searches — and 3,000 searches is exactly what I needed for 100 keywords × 30 days.

If I needed more, the next tier up is $10 for 20,000 searches with no expiry. But I didn't need more, and the 1-month expiry on the Boost tier was actually useful — it kept me disciplined.

The endpoint

POST https://api.serpbase.dev/google/search
Enter fullscreen mode Exit fullscreen mode

Headers: X-API-Key: <your-key>

Body (JSON):

{
  "q": "serp api",
  "gl": "us",
  "hl": "en",
  "num": 10
}
Enter fullscreen mode Exit fullscreen mode

Each call costs 1 credit. If the dispatch fails (upstream timeout, QPS cap, whatever), the credit is automatically refunded. The response includes a request_id you can store for log correlation.

P50 latency is around 1.4 seconds. Not the fastest in the category — Serper is closer to 1.2s — but for a daily batch job, latency doesn't matter.

The code

import requests
import csv
import time
from datetime import datetime

API_KEY = "your-serpbase-key"
ENDPOINT = "https://api.serpbase.dev/google/search"
KEYWORDS = [
    "serp api",
    "cheap serp api",
    "serp api for llm",
    # ... your full list of ~100 keywords
]
BRAND_DOMAIN = "yourdomain.com"

def fetch_serp(keyword, gl="us", hl="en"):
    r = requests.post(
        ENDPOINT,
        headers={"X-API-Key": API_KEY},
        json={"q": keyword, "gl": gl, "hl": hl, "num": 10},
        timeout=10,
    )
    r.raise_for_status()
    return r.json()

def rank_for_keyword(keyword):
    data = fetch_serp(keyword)
    for i, item in enumerate(data.get("organic", []), 1):
        if BRAND_DOMAIN in item.get("link", ""):
            return i, item.get("title"), item.get("link")
    return None, None, None

def main():
    results = []
    for kw in KEYWORDS:
        rank, title, link = rank_for_keyword(kw)
        results.append({
            "ts": datetime.utcnow().isoformat(),
            "keyword": kw,
            "rank": rank,
            "title": title,
            "link": link,
        })
        time.sleep(0.2)  # don't blow through QPS

    with open("rank_log.csv", "a", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=results[0].keys())
        writer.writerows(results)

if __name__ == "__main__":
    main()
Enter fullscreen mode Exit fullscreen mode

That's the whole thing. 30 lines. time.sleep(0.2) between calls gives you ~5 QPS, well under any public QPS cap.

Scheduling it

crontab -e, add:

0 8 * * * /usr/bin/python3 /path/to/serp_rank.py
Enter fullscreen mode Exit fullscreen mode

8 AM UTC, every day. The script appends a row to rank_log.csv per keyword.

Reading the data

import pandas as pd

df = pd.read_csv("rank_log.csv")
df["ts"] = pd.to_datetime(df["ts"])
df.groupby("keyword")["rank"].plot(legend=True)
Enter fullscreen mode Exit fullscreen mode

Or push it to a Google Sheet if you want a dashboard. I just look at the CSV in a Jupyter notebook when I want to investigate a keyword that moved.

The math

Item Value
Keywords tracked 100
Days run 30
Searches / month 3,000
Cost per 1,000 $0.30 (Starter Boost)
Total / month $0.90
Cost per keyword per day $0.0003

If I had to use a $50/month subscription for 5,000 searches, I'd be paying ~55x more for the same data, and the unused searches would expire at month end.

What I learned

Three things I didn't expect:

1. The "rank not found" case is more useful than I thought. When my domain drops out of the top 10, that's the signal. Tracking presence is more actionable than tracking position.

2. request_id is the best debugging tool. I log every request_id, and when something looks off (e.g., a sudden rank change), I can look it up in the provider's dashboard and see the upstream Google response.

3. P50 latency doesn't matter for batch. I cared about latency when I was scraping with headless Chrome (8–15 seconds per request). With a JSON API at 1.4s, the difference between 1.2s and 1.4s is invisible when you're running 100 requests sequentially.

When NOT to use this approach

  • You need 10,000+ keywords. Use the larger prepaid tier (125,000 searches for $50, $0.40 per 1k) or a real rank tracker.
  • You need real-time updates. This runs once a day. For minute-level rank tracking, you need a different architecture.
  • You need Google Maps, News, Images, etc. Different endpoints, different credit costs. Same pattern, more code.
  • You don't have a server. The script needs to run somewhere. A $5/month VPS works fine.

The single thing I'd add

If I were doing this for a team, I'd add Slack alerts: when rank drops by more than 5 positions day-over-day, post to a channel. The data is there; the alert is what makes it useful.

Cost ceiling vs. the alternatives

Quick sanity check against the alternatives I considered:

Tool Cost / month Setup time Cost multiplier
Ahrefs $99 0 ~110x
SEMrush $130 0 ~144x
SerpApi (subscription) $50 (5k searches) 1h ~55x, expires
My script $0.90 2h 1x

The savings are real, but they only matter if you can spend 2 hours setting it up. If your time is worth $200/hour, just buy Ahrefs.

Conclusion

If you're an indie dev or small team with a small keyword list, a $0.90/month rank tracker is a viable alternative to paying for an SEO suite. The code is 30 lines, the math works, and the data is the same as what the expensive tools give you.

I built this on top of a low-cost SERP API I've been using for several projects — SerpBase. There's 100 free searches on signup, no card required: serpbase.dev.


Source: SERP API comparison, updated Apr 23, 2026.

Top comments (0)