Log in Sign up
Rank tracking

Proxies for rank tracking with the country in the link

Search engines show results by region, so a rank checker needs an IP from the right country for every query batch. Resi Core gives a home address in any of 200+ countries right in the connection string, while unlimited packages with a country filter cover large keyword lists. A separate section covers tracking Google AI answers, which also depend on the country and city.

  • Resi Core: country in the string
  • a new IP on every request
  • packages for large keyword lists
Monitor with a climbing position chart on a desk
Rank tracking

What a rank checker needs and what the package gives

Positions depend on where the query comes from. The pool has to answer that question first.

What the task needsWhat the plans give

Addresses from the country you track

Resi Core: the country goes in the login; on packages a country column in the CSV export

A new IP for each query batch

Resi Core changes the address on every request, and packages replace about a third of addresses daily

Enough parallel queries for a large keyword list

No thread limit on Resi, 500 to 5,000 threads on packages

Works with the checker you already run

Resi by login and password in the string, packages by IP; A-Parser, Key Collector and Rank Tracker accept HTTP and SOCKS5

Residential proxies

Work out traffic for your keyword list

A results page weighs little, so one gigabyte covers thousands of queries. The price per GB drops with the order size.

Residential proxy price per 1 GB by order size
Order sizeResi CoreResi Prime
1 GB+$0.85$2.29
10 GB+save 7%$0.79$2.09
50 GB+$0.72$1.95
100 GB+$0.65$1.75
500 GB+$0.57$1.55
1000 GB+$0.49$1.39

Prices are in US dollars per 1 GB. You buy whole gigabytes, starting with a single one.

Pool

  • 2M+ home IPs across 200+ countries
  • A fresh address on every request or one per session while the device is available
  • Mail from your own inbox: 465 and 587 to send, IMAP 993 and POP3 995 to receive, port 25 closed
  • Up to 1,000 lines at once, and the list refreshes itself every N minutes
Total
$19.75
Per 1 GB
$0.79
Tier
10–49 GB

You save 7% ($1.50) against the 1 GB+ price

Add 25 GB and every gigabyte drops to $0.72

Buy this amount

You can use the gigabytes for 3 months from the purchase date; whatever is left after that is written off.

About residential

Three steps to a tracked keyword list

Choose the region

Track Google.de through Europe, Yandex through CIS, Baidu through China. World MIX covers the rest and the biggest pools.

Export by country

Take the CSV export and keep the rows whose country column matches the market you track; the ready builder writes a per-country ip:port file for you.

Feed the tool

Rank checkers take a proxy file or a URL. Set the refresh to 10 minutes and the list stays current on its own.

Ready checker: SERP position from a chosen country

Set DOMAIN and COUNTRY, put your keywords in keywords.txt. The script asks the search engine through a proxy of that country and writes the position of your domain to a CSV. Feed it a clean pool from the proxy checker.

CSV export link from your dashboard
ISO 3166-1 alpha-2: positions are read from this country
keep proxies with speed >= this value
the domain whose position you track
one keyword per line
{q}=keyword, {cc}=country
keyword;position;proxy is written here
Values come from the form; copy or download the ready file.
Show the script code
Python 3.8+ · rank.py
#!/usr/bin/env python3
"""Search-position checker for Advanced.name proxies.

Reads the CSV proxy export, keeps one country, then asks a search engine for each
keyword through a proxy from that country and reports where your domain sits in
the results. Standard library only. Edit CONFIG and run: python3 rank.py
"""

# ================================ CONFIG ====================================
CSV_URL = "https://get.advanced.name/YOUR_LIST_ID.csv"  # CSV export link from your dashboard
COUNTRY = "DE"          # ISO 3166-1 alpha-2: positions are read from this country
MIN_SPEED = 3           # keep proxies with speed >= this value
DOMAIN = "example.com"  # the domain whose position you track
KEYWORDS_FILE = "keywords.txt"           # one keyword per line
SEARCH_URL = "https://www.bing.com/search?q={q}&count=50&setlang={cc}"  # {q}=keyword, {cc}=country
OUT_FILE = "positions.csv"               # keyword;position;proxy is written here
TIMEOUT = 20
# ============================================================================

import csv
import io
import re
import sys
import urllib.parse
import urllib.request

COL_IP, COL_PORT, COL_COUNTRY, COL_SPEED = 0, 1, 2, 3
UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/124.0 Safari/537.36"
HREF = re.compile(r'href="https?://([^/"]+)', re.I)


def load_proxies():
    raw = urllib.request.urlopen(CSV_URL, timeout=30).read().decode("utf-8", "replace")
    pool = []
    for row in csv.reader(io.StringIO(raw), delimiter=";"):
        if len(row) <= COL_SPEED or not row[COL_PORT].strip().isdigit():
            continue
        if COUNTRY and row[COL_COUNTRY].strip().upper() != COUNTRY.upper():
            continue
        if int(row[COL_SPEED] or 0) < MIN_SPEED:
            continue
        pool.append(row[COL_IP].strip() + ":" + row[COL_PORT].strip())
    return pool


def position(html, domain):
    """First place the domain shows up among the result links, or 0 if absent."""
    rank, seen = 0, set()
    for host in HREF.findall(html):
        host = host.lower()
        if "bing.com" in host or "microsoft.com" in host or host in seen:
            continue
        seen.add(host)
        rank += 1
        if host == domain or host.endswith("." + domain):
            return rank
    return 0


def main():
    proxies = load_proxies()
    if not proxies:
        sys.exit("No proxies for COUNTRY=%r." % COUNTRY)
    with open(KEYWORDS_FILE, encoding="utf-8") as fh:
        keywords = [line.strip() for line in fh if line.strip()]
    print("proxies: %d (%s), keywords: %d" % (len(proxies), COUNTRY, len(keywords)))

    with open(OUT_FILE, "w", encoding="utf-8", newline="") as out:
        writer = csv.writer(out, delimiter=";")
        writer.writerow(["keyword", "position", "proxy"])
        for i, keyword in enumerate(keywords):
            proxy = proxies[i % len(proxies)]
            url = SEARCH_URL.format(q=urllib.parse.quote(keyword), cc=COUNTRY.lower())
            handler = urllib.request.ProxyHandler({"http": "http://" + proxy, "https": "http://" + proxy})
            req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept-Language": COUNTRY.lower()})
            try:
                html = urllib.request.build_opener(handler).open(req, timeout=TIMEOUT).read().decode("utf-8", "replace")
                pos = position(html, DOMAIN.lower())
            except Exception as exc:
                pos = "err: %s" % exc.__class__.__name__
            writer.writerow([keyword, pos, proxy])
            print("%-40s %s" % (keyword[:40], pos))
    print("written %s" % OUT_FILE)


if __name__ == "__main__":
    main()

Script: is there an AI block, and does it cite your domain

Paste a Resi line from your dashboard, set DOMAIN and put the keywords in keywords.txt. The script opens the results in a real Chromium through the proxy, waits for the AI block to finish loading and writes to CSV whether the block is there, which domains it cites and whether yours is among them. It closes the EU cookie banner itself and flags a captcha or a proxy error on a separate line. Google changes its markup, so the block heading lives in LABELS.

host:port:login:password line from your dashboard
the domain you want to see among the cited sources
one keyword per line
{q}=keyword
interface language of the results page
country of the results, keep it equal to the country in the login
heading text of the AI block, separated by |
cookie banner buttons in EU countries, in the HL language
keyword;ai_block;cited;your_domain is written here
time for the AI block to finish drawing
set False to watch the browser
Values come from the form; copy or download the ready file.
Show the script code
Python 3.8+ · ai_overview.py
#!/usr/bin/env python3
"""AI Overview tracker for Advanced.name residential proxies.

Opens Google results for every keyword through a Resi Core or Resi Prime line
in a real Chromium, because the AI block is drawn by JavaScript. Records
whether the page shows the AI block and which domains it cites.
Setup: pip install playwright && python -m playwright install chromium
"""

# ================================ CONFIG ====================================
PROXY = "res.advanced.name:9000:USER-type-residential-country-us:PASS"  # host:port:login:password line from your dashboard
DOMAIN = "example.com"  # the domain you want to see among the cited sources
KEYWORDS_FILE = "keywords.txt"  # one keyword per line
SEARCH_URL = "https://www.google.com/search?q={q}&hl={hl}&gl={gl}"  # {q}=keyword
HL = "en"  # interface language of the results page
GL = "us"  # country of the results, keep it equal to the country in the login
LABELS = "AI Overview|AI Mode"  # heading text of the AI block, separated by |
CONSENT = "Reject all|Accept all"  # cookie banner buttons in EU countries, in the HL language
OUT_FILE = "ai_overview.csv"  # keyword;ai_block;cited;your_domain is written here
WAIT_MS = 4000  # time for the AI block to finish drawing
HEADLESS = True  # set False to watch the browser
# ============================================================================

import csv
import sys
import urllib.parse

from playwright.sync_api import sync_playwright

FIND_BLOCK = """(labels) => {
  const heads = [...document.querySelectorAll('h1,h2,h3,div,span')]
    .filter(e => e.children.length === 0 && labels.includes(e.textContent.trim()));
  if (!heads.length) return null;
  let box = heads[0];
  for (let i = 0; i < 8 && box.parentElement; i++) {
    box = box.parentElement;
    const links = [...box.querySelectorAll('a[href^="http"]')];
    if (links.length >= 2 && box.innerText.length > 200) return links.map(a => new URL(a.href).hostname);
  }
  return [];
}"""


def proxy_of(line):
    host, port, user, password = line.strip().split(":", 3)
    return {"server": "http://%s:%s" % (host, port), "username": user, "password": password}


def bare(host):
    host = host.lower()
    return host[4:] if host.startswith("www.") else host


def main():
    keywords = [k.strip() for k in open(KEYWORDS_FILE, encoding="utf-8") if k.strip()]
    labels = [x.strip() for x in LABELS.split("|") if x.strip()]
    consent = [x.strip() for x in CONSENT.split("|") if x.strip()]
    rows = []
    with sync_playwright() as pw:
        browser = pw.chromium.launch(headless=HEADLESS, proxy=proxy_of(PROXY))
        page = browser.new_page(locale=HL)
        for kw in keywords:
            url = SEARCH_URL.format(q=urllib.parse.quote_plus(kw), hl=HL, gl=GL)
            try:
                resp = page.goto(url, wait_until="domcontentloaded", timeout=60000)
                if resp is None or resp.status >= 400:
                    status = "http %s" % (resp.status if resp else "none")
                    print("%-40s %s" % (kw[:40], status), file=sys.stderr)
                    rows.append([kw, status, "", ""])
                    continue
                for name in consent:
                    button = page.get_by_role("button", name=name)
                    if button.count():
                        button.first.click()
                        page.wait_for_load_state("domcontentloaded")
                        break
                if "/sorry/" in page.url:
                    print("%-40s captcha: change the session id in the login" % kw[:40], file=sys.stderr)
                    rows.append([kw, "captcha", "", ""])
                    continue
                page.wait_for_timeout(WAIT_MS)
                hosts = page.evaluate(FIND_BLOCK, labels)
            except Exception as exc:
                print("%-40s error: %s" % (kw[:40], str(exc).splitlines()[0]), file=sys.stderr)
                rows.append([kw, "error", "", ""])
                continue
            if hosts is None:
                print("%-40s no AI block" % kw[:40])
                rows.append([kw, "no", "", ""])
                continue
            cited = sorted({bare(h) for h in hosts if "google." not in h})
            mine = any(h == DOMAIN or h.endswith("." + DOMAIN) for h in cited)
            print("%-40s AI block, %d sources, %s %s" % (kw[:40], len(cited), DOMAIN, "cited" if mine else "not cited"))
            rows.append([kw, "yes", " ".join(cited), "yes" if mine else "no"])
        browser.close()
    with open(OUT_FILE, "w", encoding="utf-8", newline="") as f:
        out = csv.writer(f, delimiter=";")
        out.writerow(["keyword", "ai_block", "cited", "your_domain"])
        out.writerows(rows)
    print("saved", OUT_FILE)


if __name__ == "__main__":
    main()
Setup

Setting up a rank tracker

A-Parser, Key Collector, Rank Tracker

In A-Parser and Key Collector paste the ip:port list into the proxy field and set the check interval so one keyword hits one address at most once a day. Rank Tracker and similar desktop tools read a proxy file; point them at the list the builder writes per country.

Positions depend on where the query comes from, so keep a separate list per market: run one tracker instance per country and give each the addresses of that country only.

Reading positions in your own code

The script above asks the search engine through a country proxy and records your domain's place. Send the language and region parameters of the engine together with the proxy: the address sets the country, the parameters set the city.

Check the pool before a run with the proxy checker; for a light manual test the free proxy list works. A background primer on regional SERPs will live in the articles.

Google AI answers: AI Overviews and AI Mode

More and more often Google puts an AI block above the regular results: a short answer with links to sources. Part of the clicks goes there, so you need to know whether your site made it into the sources and which queries show no block at all. The block is built for the user location: for one query Berlin and Munich can see different sources.

A regular results scraper never sees this block: Google draws it with JavaScript after the page loads. You need a real browser, such as Chromium through Playwright, and a home IP in the right country. List addresses often hit a captcha on these results, which is why Resi Core and Resi Prime do the job here.

For country-level tracking Resi Core with the country code in the login is enough. When the client cares about a city, take Resi Prime with the city in the string and a fixed session per query batch: the whole batch then leaves from one address in that city.

What to record and how often

Run the keyword list once a day or once a week: the AI block changes more slowly than regular positions. For every query write the date, the country or city, whether the block is there, which domains it cites and whether yours is among them. After a month you can see which pages the AI takes into its answer and which dropped out.

The second script above writes exactly these fields to CSV. The first script tracks regular positions in the same country, so both reports line up by query.

In practice

Positions as they look from each country

Four settings that make position data honest

  1. Query one keyword from one IP no more than once a day; the pool is large enough to spread the load.
  2. Keep the IP list per country separate: mixed addresses mix the SERPs.
  3. Add the language and location parameters of the search engine; the proxy sets the country, the parameters set the city.
  4. Use the free-proxies page for a quick sanity test, then switch to Resi Core or a package for daily tracking.

This task by country

Show all countries
FAQ

Questions about this task

Which region for Google?
Google shows results by the searcher’s country. On Resi Core put the country code in the login, and every request leaves from a home IP in that country. On packages filter the CSV export by the country column: Europe for the EU, World MIX for the US and the rest of the world, CIS for Russian-speaking markets.
How do I track Google AI answers?
Through Resi Core or Resi Prime and a real browser: JavaScript draws the AI block, so a plain HTTP request never sees it. The script on this page opens the results in Chromium and records whether the block is there and whether it cites your domain. For different cities take Resi Prime.
How many keywords per day?
Resi Core has no thread limit, so the traffic you buy sets the ceiling. With 1,000 threads on package #2 a checker handles tens of thousands of queries a day; keep one IP per keyword per day.
Do I need a login and password?
Not on packages: access is bound to the IP of the machine running the checker. Resi Core uses the login and password from the string and needs no whitelist.
How do I track the results of a specific city?
The search engine location parameters set the city with any proxy. When the results depend on the IP, take Resi Prime: you set the city in the connection string.
Plans for this task

What to take for rank tracking

Track country results through Resi Core and city results through Resi Prime, and run large keyword lists every day on an unlimited package for less.

Resi Core

Country resultsBest fit

2M+ IPs · 200+ countries · no thread limit

A home IP from the right country on every request. A results page weighs little, so one gigabyte covers thousands of queries.

from $0.49 per GB1 GB for $0.85

Resi Prime

City results

30M+ IPs · 220 countries · no thread limit

City and region in the connection string give the results a user from that city sees.

from $1.39 per GB1 GB for $2.29

Unlimited proxies

Large keyword lists

Package #2 · World MIX · 12,000 IP · 1,000 threads

Tens of thousands of queries a day with no traffic meter. You pick the market country by the column in the CSV export.

$378 per monthor $2.10 per hour

See real positions tomorrow morning

Take 1 GB of Resi Core, set the country in the string and run the checker on live addresses.

Pricing Grab a free hour