Ad verification for your own campaigns
Check that your geo-targeted ads and landing pages render, redirect and localize as planned, from the countries and on the device types you paid for.
Proxy URL, exit IP in United States
http://USERNAME-cc-US-session-a1b2c3d4-ttl-15:PASSWORD@mobile-us.netdash.io:4000Mobile exit IPs in United States
Illustrative routes, not live traffic. Exits are available in most countries; the countries shown are examples.
- Mobile and residential exits, one syntax
- Country-level targeting
- Sticky sessions for a full check
Ad verification proxies for geo-targeted campaigns
A campaign targeted at one country and one device type can’t be checked from your office network. A wrong language, a broken redirect or the wrong offer on a landing page often shows up only in the market and on the device the campaign targets. Ad verification proxies let you load your own ads and landing pages from an exit IP in that country, on a mobile or desktop client, and keep a record of what was served.
netdash gives you mobile and residential exits with one username and password. You name the campaign country in the username, and a sticky session holds one check, from the first redirect to the screenshot, on one exit IP.
Why you can’t check a country-targeted ad from the office
Ad delivery and landing pages vary by visitor country and device. Ad platforms choose what to serve from signals that include the visitor’s IP address, and landing pages often redirect or localize on the same signal. From your office you see your own market, on your own network.
To see an ad and its landing path the way your audience does, the check has to come from that country, on the right device class. Your ad platform’s preview shows the creative as configured; a check from the campaign’s market shows what the redirect chain and landing page return there. For your own site’s language and currency rules in general, see localization testing; for organic rankings by market, see SEO monitoring.
A verification pass, step by step
Step 1: Export the campaign plan
Landing URLs, the placements you own or manage, target countries and devices.
Step 2: Open one session per check
Exit country = campaign country. Mobile for mobile campaigns, Scale for desktop, sticky
Sticky sessions15so the redirect chain and landing page share one exit IP.Step 3: Load, don’t click
Open the landing URL or the page where your ad runs. Never click ads to test them.
Step 4: Record the evidence
Redirect chain, final URL, status, screenshot and the other fields in the table below.
Step 5: Compare with the plan
Language, currency, offer, final URL and status against what the campaign specifies.
Step 6: Archive and report
Store the evidence with its session details and send mismatches to the campaign owner.
What to record for each check
| Attribute | Why it matters |
|---|---|
| Campaign ID and expected targeting | Ties the check to the plan you compare it against |
| Exit country, plan and session ID | Shows where the check came from, so you can repeat it |
| UTC timestamp | Delivery changes over time; the time makes records comparable |
| Redirect chain with status codes | Finds broken hops, the wrong country site and unexpected redirects |
| Final URL | Confirms visitors land on the page the campaign specifies |
| HTTP status of the landing page | Catches errors that a screenshot alone can hide |
| Full-page screenshot | Shows what was rendered, for review by the campaign owner |
| Language, currency and offer shown | The localization details most often wrong in a single market |
Device and country configuration
Mobile campaigns use the Mobile plan; desktop campaigns use a residential plan. The examples use Scale: every residential plan uses the same syntax, and you switch plans by changing the host and port. The proxy string format explains each part of the username.
- Mobile campaign, United States
mobile-us.netdash.io:4000·USERNAME-cc-US-session-{SID}-ttl-15Puppeteer with a mobile device descriptor, so the page renders its mobile layout.
- Desktop campaign, Germany
scale-eu.netdash.io:2000·USERNAME-cc-DE-session-{SID}-ttl-15Puppeteer or Playwright with a desktop viewport.
- Session mode and TTL
Sticky,
15minutes per checkCovers the redirect chain, landing page and screenshot on one exit IP while that IP stays available.
- Session ID
First 8 hex characters of a hash of campaign ID, country and check time
Letters and digits only, no hyphens. A new ID starts a new session for the next check.
- Credentials
Your proxy username and password from the dashboard
Not your sign-in password. One pair for every residential and mobile plan.
- Volume
A small sample per campaign, country and device
A page load that shows an ad may register an impression, so check only as much as verification needs.
Proxy settings for one campaign check
Pick the campaign country and plan. Mobile is preselected with a 15-minute sticky session.
Your route
Through the gateway to an exit IP in , , on the Mobile plan.
Proxy URL
http://USERNAME-cc-US-session-a1b2c3d4-ttl-15:PASSWORD@mobile-us.netdash.io:4000Replace USERNAME and PASSWORD with the credentials from your dashboard.
Mobile, Americas gateway, exit IP in United States, sticky for 15 min.
curl --max-time 30 -x "http://USERNAME-cc-US-session-a1b2c3d4-ttl-15:PASSWORD@mobile-us.netdash.io:4000" \
"https://api.ipify.org?format=json"import requests
proxy = "http://USERNAME-cc-US-session-a1b2c3d4-ttl-15:PASSWORD@mobile-us.netdash.io:4000"
proxies = {"http": proxy, "https": proxy} # set both, or HTTPS requests bypass the proxy
response = requests.get("https://api.ipify.org?format=json", proxies=proxies, timeout=30)
response.raise_for_status()
print(response.text)import { ProxyAgent, fetch } from "undici";
const dispatcher = new ProxyAgent({
uri: "http://mobile-us.netdash.io:4000",
token: "Basic " + Buffer.from("USERNAME-cc-US-session-a1b2c3d4-ttl-15:PASSWORD").toString("base64"),
});
const res = await fetch("https://api.ipify.org?format=json", { dispatcher, signal: AbortSignal.timeout(30_000) });
console.log(await res.text());import { chromium } from "playwright";
const browser = await chromium.launch({
proxy: {
server: "http://mobile-us.netdash.io:4000",
username: "USERNAME-cc-US-session-a1b2c3d4-ttl-15",
password: "PASSWORD",
},
});
const page = await browser.newPage();
await page.goto("https://api.ipify.org?format=json");
console.log(await page.textContent("body"));
await browser.close();Example output
{"ip":"203.0.113.10"}Your output shows a different address in the country you chose.
Capture the redirect chain with Puppeteer
Chrome takes the gateway in --proxy-server; the username and password go to page.authenticate(). page.emulate() sets a mobile user agent and viewport before navigation, so the landing page renders its mobile layout.
redirectChain() returns the requests that were redirected before the final one, so the script appends the final request and records each URL with its status code. The screenshot and a JSON record go into evidence/, named by campaign, country and device.
- Loads pages only: no clicks, and no reloads to generate views
- For a desktop campaign, use
scale-eu.netdash.io:2000with-cc-DEand leave outemulate() - Syntax-checked. Setup details in the Puppeteer guide and the Playwright guide
import { createHash } from "node:crypto";
import { mkdir, writeFile } from "node:fs/promises";
import puppeteer, { KnownDevices } from "puppeteer";
const USER = process.env.NETDASH_USERNAME;
const PASS = process.env.NETDASH_PASSWORD;
// One check of your own campaign: one country, one device.
const check = {
campaignId: "spring-sale-us-mobile",
country: "US",
landingUrl: "https://www.yourcompany.example/spring-sale?utm_campaign=spring-sale",
};
const capturedAt = new Date().toISOString();
const sid = createHash("sha256").update(`${check.campaignId}:${check.country}:${capturedAt}`).digest("hex").slice(0, 8);
// Chrome takes the gateway here; the username and password go to page.authenticate().
const browser = await puppeteer.launch({ args: ["--proxy-server=http://mobile-us.netdash.io:4000"] });
try {
const page = await browser.newPage();
await page.authenticate({ username: `${USER}-cc-${check.country}-session-${sid}-ttl-15`, password: PASS });
await page.emulate(KnownDevices["iPhone 15"]); // mobile user agent and viewport, before navigating
const response = await page.goto(check.landingUrl, { waitUntil: "networkidle2", timeout: 60_000 });
if (!response) throw new Error("No response for the landing URL");
const chain = [...response.request().redirectChain(), response.request()].map((req) => ({
url: req.url(),
status: req.response()?.status() ?? null,
}));
await mkdir("evidence", { recursive: true });
const base = `evidence/${check.campaignId}-${check.country}-mobile`;
await page.screenshot({ path: `${base}.png`, fullPage: true });
const record = {
campaignId: check.campaignId,
exitCountry: check.country,
plan: "mobile",
session: sid,
capturedAt,
redirectChain: chain,
finalUrl: page.url(),
landingStatus: response.status(),
pageLang: await page.evaluate(() => document.documentElement.lang),
};
await writeFile(`${base}.json`, JSON.stringify(record, null, 2));
} finally {
await browser.close();
}Which product matches the campaign
Mobile proxies
Self-serveMobile campaigns: check placements and landing pages from mobile exit IPs. Carrier, city and network generation can’t be selected.
From $3.50/GB, graduated per order
Residential proxies
Self-serveDesktop campaigns, with the same credentials and username syntax. The examples use the Scale plan.
From $1.20/GB, graduated per order
Your campaigns only
Verify only campaigns you own or are authorized to verify, for example as the agency running them. Loading a page that shows an ad may register an impression, so keep samples small and use your ad platform’s own preview and verification tools where they exist. Never click ads to test them: our Terms of Service (§2) list click fraud and "any automated activity designed to mislead or defraud advertising systems" among prohibited uses. See how we expect netdash to be used.
Ad verification questions
Your own campaigns, or campaigns you’re authorized to verify, such as an agency checking the campaigns it runs for clients.
Loading a page that shows an ad may count as an impression. Keep samples small, never click ads, and use your ad platform’s preview tools where they exist.
No. Targeting is country-level, and the Mobile plan doesn’t let you pick a carrier or network generation.
Mobile for mobile campaigns, residential for desktop. Credentials and username syntax are the same; you switch by changing the host and port.
Long enough for one check. The 15-minute preset covers the redirect chain, landing page and screenshot on one exit IP. Use a new session ID for the next check.
Verify your next campaign
Start with one campaign, one country and one device, and compare the evidence record with the campaign plan before launch.