Use cases · Ad verification

Residential proxies for ad verification

Check that your ads, landing pages and tracking links work in every country you pay for. Follow each redirect from a real home connection, and see your Google text ads as JSON. $1.00/GB.

Landing pages by country

Load your landing page through a home connection in each country you target, and check that the right version loads.

Whole redirect chains

A sticky session keeps every hop of a tracking link on one exit, so the chain you record is the one a single visitor gets.

Text ads as JSON

The Search API returns the text ads Google showed for a query, with title, displayed URL and position.

Tracking links often pass through several domains before the landing page. Each domain is a new proxy connection, and with rotation each connection can get a different exit. A sticky session keeps the whole chain on one exit:

import os
import secrets
from urllib.parse import quote

import requests

USER = quote(os.environ["PACKETSTREAM_USER"], safe="")
AUTH_KEY = os.environ["PACKETSTREAM_AUTH_KEY"]


def follow(url, country):
    label = secrets.token_hex(6)
    password = quote(f"{AUTH_KEY}_country-{country}_session-{label}", safe="")
    proxy = f"https://{USER}:{password}@proxy.packetstream.io:31111"
    response = requests.get(
        url, proxies={"http": proxy, "https": proxy}, timeout=30, allow_redirects=True
    )
    return [(hop.status_code, hop.url) for hop in response.history + [response]]


for country in ("US", "GB", "CA"):
    print(country)
    for status, hop in follow("https://track.example/c/spring-sale", country):
        print("  ", status, hop)

Check that the last URL is the landing page you paid for in that country, and that no hop returns an error. To see what the landing page contains, save response.text or load the URL in a headless browser such as Playwright with the same proxy settings.

Check your Google text ads

For type: search, the Search API returns an ads block when Google showed text ads. It lists up to 10 ads with position, block_position (top or bottom), title, displayed_url and an optional snippet:

import os

import requests

response = requests.post(
    "https://api.packetstream.io/v1/search",
    headers={"Authorization": f"Bearer {os.environ['PACKETSTREAM_API_KEY']}"},
    json={"query": "running shoes sale", "country": "gb"},
    timeout=35,
)
response.raise_for_status()


def displayed_host(displayed_url):
    # Such as "https://www.example.com › sale" or "www.example.com/sale".
    words = displayed_url.split("://")[-1].split()
    return words[0].split("/")[0].lower() if words else ""


for ad in response.json().get("ads", []):
    host = displayed_host(ad["displayed_url"])
    if host == "example.com" or host.endswith(".example.com"):
        print(ad["block_position"], ad["position"], ad["title"])

Click-tracking links are never returned, so these checks never click your ads. The ads block appears only when Google showed ads and they could be read, and mobile searches carry fewer blocks. See responses.

Rules for ad checks

  • Check your own campaigns, or campaigns you are authorized to audit.
  • Never click ads through the proxy. Automated clicks are fake traffic for the advertiser who pays for them.
  • Don’t load ads in bulk. Request each landing page only as often as you need to verify it.

Honest limits

  • Country only. You can’t target a city, region, ISP or mobile carrier.
  • Exits are home connections. They are real home connections, but ad platforms and sites can still treat automated visits differently from people.
  • HTTP redirects only. requests follows HTTP redirects. A page that redirects with a meta refresh or JavaScript needs a browser such as Playwright.
  • No guarantee of what a person sees. Ads change by time, audience, device and history. A check is one sample.
  • Exits are home connections. One can drop in the middle of a check. If a check fails, run it again.

Pricing

Pay for what you use.

Proxy traffic

$1.00 per GB

Same price in every country. A redirect check without page assets uses little data.

Search API

$2.50 per 1,000

$0.0025 per successful search. Failed searches are free.

Billing

One prepaid balance

$50 minimum, no subscription. Purchased balance does not expire.

Start with $50.
Use it at your pace.