A rank tracking API tells you where a domain ranks on Google for a keyword, in a given country, on a given day. You can build one yourself in an afternoon: fetch the Google results page for each keyword with Scrape.ly's Google Search Scraper, read the position of the domains you care about, and run it on a schedule. It costs $3.30 per 1,000 checks, platform usage included, with no plan sized by keyword count.
This guide shows the setup, a real run of four keywords in the US and the UK from 26 October 2026, the Python code (tested against that run's data), a no-code CSV export with one row per position, scheduling with Google Sheets, and what the same tracking costs on SerpApi, ScraperAPI and SE Ranking.
What a rank tracking API gives you
SEO rank tracking needs five things, and the Google Search Scraper covers each one with an input field or an output field:
| You need | Where it comes from |
|---|---|
| The keyword | queries: one keyword per line, as many as you like in one run |
| The country and language | countryCode (Google's gl, such as us, gb, de) and languageCode (hl) |
| The ranking | organicResults[].position, with url, title and displayedUrl |
| Depth | maxPagesPerQuery: 1 page is about the top 10, 2 pages the top 20; positions count on across pages |
| A date and a history | Each run is dated, and a schedule runs it daily or weekly |
Each dataset item is one Google results page. It also records the query, country, language and device it was fetched for, under searchQuery, so every row you store knows where it came from. People Also Ask and related searches come along on the same item at no extra cost, which is handy for content research.
Off-the-shelf rank trackers sell the same data as a subscription sized by the number of keywords you track. Building on raw results means you pay per check, track any country, and keep the data in your own sheet or database.
A real run: four keywords, two countries
On 26 October 2026 we tracked four keywords: "rank tracking api", "serp api", "web scraping api" and "seo rank tracker". We ran them once with countryCode: "us" and once with "gb", one page each, in the default fast search mode. This is the input for the US run, close to the Store's 3 queries preset:
{
"queries": "rank tracking api\nserp api\nweb scraping api\nseo rank tracker",
"maxPagesPerQuery": 1,
"resultsPerPage": 10,
"countryCode": "us",
"languageCode": "en"
}Both runs finished in about 4 seconds. The US run returned 4 pages with 34 organic results, the UK run 4 pages with 36. Each run cost 4 × $0.0033 = $0.0132 at list price, so both together $0.0264 for eight checks. Our account was charged $0.01056 per run because its plan has a Store discount.
2026-10-26T14:38:20.407Z [scrapely.actor] INFO Using fast search mode. Pages switch to browser mode only if fast search mode fails.
2026-10-26T14:38:20.414Z [scrapely.actor] INFO queries=4 concurrency=8
2026-10-26T14:38:21.133Z [scrapely.actor] INFO Pushed 4 dataset items, 34 organic results, 0 failed pages in 0.7s. Pages handled in fast search mode: 4, in browser mode: 0.
2026-10-26T14:38:21.133Z [scrapely.actor] INFO [Status message]: 4 pages, 34 organic results, 0 failedHere's where five well-known sites ranked. A dash means not in the top 10 that day:
| Keyword | Domain | US position | UK position |
|---|---|---|---|
| rank tracking api | brightdata.com | 2 | 2 |
| rank tracking api | scrapingdog.com | 3 | 4 |
| rank tracking api | seranking.com | 4 | 3 |
| serp api | scraperapi.com | – | 5 |
| web scraping api | firecrawl.dev | 2 | 3 |
| web scraping api | scraperapi.com | 3 | 2 |
| seo rank tracker | seranking.com | – | 6 |
Two countries, same day, different rankings: SE Ranking is 4th in the US and 3rd in the UK for "rank tracking api", and ScraperAPI and Firecrawl swap places for "web scraping api". That's why rank tracking has to be per country.
The code: positions per keyword into a CSV
This script runs the keywords in each country, finds the best position of each tracked domain, and appends dated rows to rankings.csv. Install the client with pip install scrapely-client-python and set SCRAPELY_TOKEN (create one under Settings → API & Integrations).
import csv
import os
from datetime import date
from urllib.parse import urlparse
from scrapely_client import ScrapelyClient
KEYWORDS = ["rank tracking api", "serp api", "web scraping api", "seo rank tracker"]
TRACKED = ["seranking.com", "scraperapi.com", "firecrawl.dev", "brightdata.com"]
COUNTRIES = ["us", "gb"]
def domain(url):
host = urlparse(url).netloc.lower()
return host[4:] if host.startswith("www.") else host
def positions(page):
"""Best organic position of each tracked domain on one results page, or None."""
best = {d: None for d in TRACKED}
for result in page.get("organicResults", []):
d = domain(result["url"])
for t in TRACKED:
if (d == t or d.endswith("." + t)) and best[t] is None:
best[t] = result["position"]
return best
client = ScrapelyClient(os.environ["SCRAPELY_TOKEN"], api_url="https://api.scrape.ly")
with open("rankings.csv", "a", newline="") as f:
writer = csv.writer(f)
for country in COUNTRIES:
run = client.actor("querystone/google-search-scraper").call(
run_input={"queries": "\n".join(KEYWORDS), "maxPagesPerQuery": 1, "countryCode": country, "languageCode": "en"}
)
for page in client.dataset(run.default_dataset_id).iterate_items():
q = page["searchQuery"]
for d, pos in positions(page).items():
writer.writerow([date.today().isoformat(), q["term"], q["countryCode"], d, pos or ""])Run against the data of our two runs, it writes 32 rows, one per keyword, country and domain. The first lines:
2026-10-26,rank tracking api,US,seranking.com,4
2026-10-26,rank tracking api,US,scraperapi.com,
2026-10-26,rank tracking api,US,firecrawl.dev,
2026-10-26,rank tracking api,US,brightdata.com,2An empty position means the domain wasn't in the organic results you fetched. Raise maxPagesPerQuery to look deeper. Run the script daily and the CSV becomes your ranking history; load it into a spreadsheet or pandas to chart movement.
No code: one row per position as CSV
If you don't want to write code, the dataset API can reshape each run for you. Every results page holds a list of organic results; unwind=organicResults turns it into one row per result, and the CSV export adds the query and country as searchQuery/term and searchQuery/countryCode columns:
curl "https://api.scrape.ly/v2/actor-runs/RUN_ID/dataset/items?format=csv&fields=searchQuery,organicResults&unwind=organicResults" \
-H "Authorization: Bearer $SCRAPELY_TOKEN"Open that file in Excel or Google Sheets and filter the url column for your domain. Use format=xlsx for an Excel file. The dataset API docs list every export option.
Schedule it and send it to Google Sheets
A rank tracker earns its keep on a schedule:
- Open the Google Search Scraper, enter your keywords and country, and save the input.
- Click Automate this and choose On a schedule: daily at 9:00 is the default, and Custom takes a cron expression. The schedule follows your time zone.
- Add a delivery: Send results to Google Sheets (share the sheet with Scrape.ly's service account once), Slack, email or a webhook to your own database.
- Repeat with a second saved input per country, or put both runs in one automation.
The automations docs cover every trigger and delivery, and our guide to scheduling web scraping walks through a full setup.
You can also ask an AI agent. With Scrape.ly's MCP server at https://mcp.scrape.ly in Claude or Cursor, ask: "Use scrapely to check where seranking.com ranks on Google for 'rank tracking api' and 'seo rank tracker' in the US and the UK, and give me a table." The agent runs the Actor and reads the positions.
What rank tracking costs: Scrape.ly vs SerpApi, ScraperAPI and SE Ranking
On Scrape.ly one check is one Google results page of 10 results: $0.0033, platform usage included, from a prepaid balance. The free plan's $5 monthly credit covers about 1,500 checks.
Rank tracking vendors price differently: SerpApi sells monthly search allowances, ScraperAPI monthly credits at 25 per Google request, and SE Ranking's Core plan costs $129 a month. Here's the bill for three common setups, using each vendor's published prices, and what each check costs in that setup:
| Setup (top 10, one country) | Checks a month | Scrape.ly | SerpApi | ScraperAPI | SE Ranking |
|---|---|---|---|---|---|
| 100 keywords daily | 3,000 | $9.90 ($3.30 per 1,000) | $75 Developer ($25.00 per 1,000) | $49 Hobby ($16.33 per 1,000) | $129 Core ($43.00 per 1,000) |
| 200 keywords daily | 6,000 | $19.80 ($3.30 per 1,000) | $150 Production ($25.00 per 1,000) | $149 Startup ($24.83 per 1,000) | $129 Core ($21.50 per 1,000) |
| 2,000 keywords weekly | about 8,667 | $28.60 ($3.30 per 1,000) | $150 Production ($17.31 per 1,000) | $149 Startup ($17.19 per 1,000) | $129 Core ($14.88 per 1,000) |
The arithmetic: 200 keywords × 30 days = 6,000 checks × $0.0033 = $19.80. On ScraperAPI, 6,000 × 25 = 150,000 credits, more than Hobby's 100,000. On SerpApi, Developer covers 5,000 searches, so 6,000 needs Production. 2,000 keywords × 52 weeks ÷ 12 months ≈ 8,667 checks.
The pattern holds as long as you track a few hundred keywords daily or a few thousand weekly: the per-check price stays at $3.30 per 1,000 on Scrape.ly, while a plan sized for your peak makes every check in a quiet month more expensive. For more on the search side, see SerpApi pricing, ScraperAPI pricing and our list of the best SERP APIs.
SEO rank tracking: what to watch out for
- Fewer than 10 organic results is normal. Google mixes in videos, forums and other modules. In fast search mode, results without a snippet from the Discussions and forums box go to
discussionsAndForumsinstead oforganicResults. Our US page for "serp api" had 6 organic results. - Desktop results. Every item records
device: DESKTOP. Track the same keywords over time with the same settings so the trend is comparable. - City-level rankings cost a little more.
countryCodecovers countries in fast mode. For a city, set an exact location (locationUule): that runs in browser mode, which adds $0.07 per run and $0.0065 per page. - Deeper tracking means more pages. Each Google page of 10 results is one check, so the top 30 is 3 pages per keyword. Positions continue across pages: page 2 picks up after page 1's last result.
- Rankings move. Google results shift between checks, so a single reading can be off by a place. Compare daily or weekly trends, not single readings.
- Failed pages aren't charged. A page that isn't a results page isn't saved and is listed under
failedInputsin the run'sOUTPUTrecord, while the other keywords carry on. Set a maximum charge per run and the run stops cleanly before going over it. - AI answers are a separate channel. If you also want to know whether AI Overviews mention your brand, the Google AI Overviews Scraper and our guide to AI search visibility tracking cover it.
FAQ
What is a rank tracking API?
An API that returns where a domain or URL ranks on a search engine for a keyword, location and date. You can buy one as part of an SEO tool, or build it on a SERP API: fetch the results page and read the position. On Scrape.ly that costs $3.30 per 1,000 checks.
How much does SEO rank tracking cost per keyword?
On Scrape.ly, one daily top-10 check costs $0.0033, so one keyword tracked daily for a month costs about $0.10. Tool subscriptions price by tracked keywords per plan: SE Ranking's Core plan is $129 a month for 2,000 keywords tracked daily.
How often should I check rankings?
Daily for keywords you actively work on or that drive revenue, weekly for the long tail. With a per-check price, weekly tracking costs about a seventh of daily tracking, and a schedule makes both automatic.
Can I track rankings by country or city?
Yes. Set countryCode for the country and languageCode for the interface language, and run one input per market. For a city, use an exact location (locationUule), which runs in browser mode.
Can I track rankings in Google Sheets?
Yes. Add a Send results to Google Sheets delivery to a scheduled automation, or export each run as CSV or Excel with one row per position using unwind=organicResults, as shown above. Our guide to scraping Google search results covers every field you can put in the sheet.



