cdpfleet Docs Sign up free

Examples & benchmarks / #87 · 2026-11-08 · Example · Easy · for geo testing, web scraping

Geo compare: the same pages from five countries in one call, and reading the diff

One `POST /v1/functions/geo` per page loads it from the US, Germany, the UK, Japan and Brazil at once and returns each country's Markdown and HTML plus a diff against the first. A Steam store page, Google's home page, Nike's home page and example.com: prices and currency, language, cookie banners, country redirects — and what to check before you trust the diff. In five languages.

Camoufox

Run on production on 2026-11-10: ✓ Node.js ✓ Python ✓ Java ✓ C# ✓ Go

The problem

Prices, currency, language, cookie banners and even which page you get depend on where the visitor is. Checking that usually means one browser or proxy per country, the same page loaded in each, and a diff tool at the end. The geo compare Function does all of it in one HTTP request: it opens the page in up to five countries at once, each in its own tab with that country's exit IP, locale, timezone and Accept-Language, and returns every country's result plus a unified diff of each text format against the first country. This case runs it on four pages and reads what came back — including what the diff doesn't tell you.

What we used, and why

WhatWhy
POST https://cdpfleet.com/v1/functions/geocountries: ["us", "de", "gb", "jp", "br"] (2–5, the first is the baseline), formats: ["markdown", "html"] (any scrape formats), max_wait: 45. No proxy: each country runs through the Community proxy in that country.
results.<country>{status, partial?, url, markdown, html} for a country that loaded — url is the final URL after redirects — and {status: null, error} for one that didn't.
diff.markdown.<country>, diff.html.<country>A unified diff (--- us, +++ de, @@ hunks) of each text format against the first country; "" when the two are identical, null when this country or the baseline failed. The programs count its hunks and added/removed lines and pair the prices on removed and added lines ($9.99 → £8.19).
The HTML<html lang> for the language and an "accept all" button label (Accept all, Alle akzeptieren, Aceitar todos, すべて同意, …) for a cookie banner; prices in the Markdown by currency symbol.
x-call-id + GET /v1/me/sessionsThe call's record in the account's history: engine function:geo, its weight (one thread per country) and the thread-seconds billed.
One retryWhen the baseline country failed, the call is made once more: every diff is against it, and then every diff comes back null.
A failure on purposeThe Steam page from ["us", "de"] with max_wait: 1, Markdown only: no country can load it in a second, so the programs see what a failed call looks like.

How it works

  1. For each page (a Steam store page, Google's home page, Nike's home page, example.com as the control), one geo call with the five countries — one page after another.
  2. If the first country (us) didn't load, call once more and keep what the first attempt said.
  3. Per country: status or error, lang, final URL, title, prices and their currencies, whether a cookie banner is in the HTML, sizes, and whether the Markdown is identical to the baseline's.
  4. Per diff: bytes, hunks, lines added and removed, and the first price changes; per call: the time, the response size and how much of it is diff.
  5. Make the call that is meant to fail (max_wait: 1) and read its errors and its diff.
  6. Look each call up in the session history by its x-call-id: engine, weight and billed thread-seconds.

The code

The same program in five languages (also on GitHub, with the raw output). Set these environment variables first:

// Node.js 18+, no packages. env: CDPFLEET_API_KEY (five countries in one call hold five threads: a paid plan)
const KEY = process.env.CDPFLEET_API_KEY;
const API = 'https://cdpfleet.com';
const COUNTRIES = ['us', 'de', 'gb', 'jp', 'br']; // the first one is the baseline the diff compares with
const FORMATS = ['markdown', 'html'];
const MAX_WAIT = 45;
const PAGES = [
  ['Steam store page', 'https://store.steampowered.com/app/620/Portal_2/'],
  ['Google home page', 'https://www.google.com/'],
  ['Nike home page', 'https://www.nike.com/'],
  ['example.com (control)', 'https://example.com/'],
];
// Prices in the five countries' currencies: R$ before $, the symbol before or after the number.
// Plain [0-9] and [ \u00a0] rather than \d and \s, so the pattern means the same in all five languages.
const PRICE = /R\$[ \u00a0]?[0-9][0-9.,]*|US\$[ \u00a0]?[0-9][0-9.,]*|£[ \u00a0]?[0-9][0-9.,]*|€[ \u00a0]?[0-9][0-9.,]*|[0-9][0-9.,]*[ \u00a0]?€|[¥¥][ \u00a0]?[0-9][0-9,]*|[0-9][0-9,]*[ \u00a0]?円|\$[ \u00a0]?[0-9][0-9.,]*/g;
// The "accept all" button of a cookie banner, in the five countries' languages.
const CONSENT = /Accept all|Alle akzeptieren|Aceitar todos|Aceitar tudo|すべて同意|すべて受け入れる|すべて許可/i;
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
const bytes = (s) => (typeof s === 'string' ? Buffer.byteLength(s) : 0);
const since = new Date(Date.now() - 60000).toISOString();

const prices = (text) => (text.match(PRICE) || []).map((p) => p.replace(/[.,]$/, '').replace('\u00a0', ' '));
function currency(p) {
  if (p.startsWith('R$')) return 'BRL';
  if (p.includes('£')) return 'GBP';
  if (p.includes('€')) return 'EUR';
  if (/[¥¥円]/.test(p)) return 'JPY';
  return 'USD';
}
const attr = (html, re) => (re.exec(html) || [])[1] ?? null;

// What the Function's unified diff (one country against the baseline) says.
function readDiff(d) {
  if (typeof d !== 'string') return null;
  const lines = d.split('\n');
  const added = lines.filter((l) => l.startsWith('+') && !l.startsWith('+++'));
  const removed = lines.filter((l) => l.startsWith('-') && !l.startsWith('---'));
  const was = removed.flatMap(prices);
  const now = added.flatMap(prices);
  const changes = [];
  for (let i = 0; i < Math.min(was.length, now.length) && changes.length < 3; i++) if (was[i] !== now[i]) changes.push(`${was[i]} → ${now[i]}`);
  return { bytes: bytes(d), hunks: lines.filter((l) => l.startsWith('@@')).length, added: added.length, removed: removed.length, price_changes: changes };
}

// The call in the account's history (its x-call-id is the session id there): weight and billed thread-seconds.
async function billed(id) {
  for (let i = 0; i < 30 && id; i++) {
    const r = await fetch(`${API}/v1/me/sessions?from=${encodeURIComponent(since)}&limit=200`, { headers: { 'x-api-key': KEY } });
    const s = (await r.json()).sessions?.find((x) => x.session_id === id);
    if (s?.ended_at) return { engine: s.engine, weight: s.weight, thread_seconds: Math.round((Date.parse(s.ended_at) - Date.parse(s.started_at)) * s.weight / 100) / 10 };
    await sleep(2000);
  }
  return null;
}

async function geo(url, countries = COUNTRIES, maxWait = MAX_WAIT, formats = FORMATS) {
  const t = Date.now();
  const res = await fetch(`${API}/v1/functions/geo`, {
    method: 'POST',
    headers: { 'x-api-key': KEY, 'content-type': 'application/json' },
    body: JSON.stringify({ url, countries, formats, max_wait: maxWait }),
    signal: AbortSignal.timeout((maxWait + 30) * 1000),
  });
  const text = await res.text();
  let body = {};
  try { body = JSON.parse(text); } catch { /* not JSON */ }
  return { res, text, body, ms: Date.now() - t };
}
const loaded = (r) => r?.status >= 200 && r?.status < 400;

const pages = [];
for (const [name, url] of PAGES) { // one call per page, one after another
  let call = await geo(url);
  // Every diff is against the first country: if that one failed, the call is retried once.
  const first = call;
  if (call.res.status === 200 && !loaded(call.body.results?.[COUNTRIES[0]])) call = await geo(url);
  const { res, text, body, ms } = call;
  const results = body.results || {};
  const base = results[COUNTRIES[0]] || {};
  const countries = {};
  for (const c of COUNTRIES) {
    const r = results[c] || {};
    const html = r.html || '';
    const md = r.markdown || '';
    const found = prices(md);
    countries[c] = {
      status: r.status ?? null,
      error: r.error ?? null,
      partial: r.partial === true,
      lang: attr(html, /<html[^>]*\slang="([^"]+)"/i),
      url: r.url ?? null, // the final URL after redirects (only for a country that loaded)
      title: attr(html, /<title[^>]*>([^<]*)</i)?.trim() ?? null,
      currencies: [...new Set(found.map(currency))],
      prices: found.slice(0, 4),
      consent_banner: html ? CONSENT.test(html) : null,
      markdown_bytes: bytes(md),
      html_bytes: bytes(html),
      same_markdown_as_baseline: c === COUNTRIES[0] || !md || !base.markdown ? null : md === base.markdown,
      // A diff is a string ("" = identical), or null when this country or the baseline failed.
      diff: c === COUNTRIES[0] ? null : { markdown: readDiff(body.diff?.markdown?.[c]), html_bytes: body.diff?.html?.[c] === null ? null : bytes(body.diff?.html?.[c]) },
    };
  }
  pages.push({
    page: name,
    url,
    attempts: call === first ? 1 : 2,
    first_attempt: call === first ? null : {
      call_id: first.res.headers.get('x-call-id'),
      errors: Object.fromEntries(COUNTRIES.filter((c) => !loaded(first.body.results?.[c])).map((c) => [c, first.body.results?.[c]?.error ?? null])),
      diffs: Object.fromEntries(Object.entries(first.body.diff?.markdown || {}).map(([c, d]) => [c, d === null ? null : bytes(d)])),
    },
    status: res.status,
    error: body.error ?? null,
    seconds: Math.round(ms / 100) / 10,
    call_id: res.headers.get('x-call-id'),
    warning: res.headers.get('x-cdpfleet-warning'),
    response_bytes: bytes(text),
    diff_bytes: { markdown: Object.values(body.diff?.markdown || {}).reduce((a, d) => a + bytes(d), 0), html: Object.values(body.diff?.html || {}).reduce((a, d) => a + bytes(d), 0) },
    ok_countries: COUNTRIES.filter((c) => loaded(results[c])),
    countries,
  });
}
// What a failure looks like: the same Steam page with max_wait 1, so no country can load it in time.
const failed = await geo('https://store.steampowered.com/app/620/Portal_2/', ['us', 'de'], 1, ['markdown']);
const failure = {
  status: failed.res.status, max_wait: 1,
  results: Object.fromEntries(Object.entries(failed.body.results || {}).map(([c, r]) => [c, { status: r.status ?? null, error: r.error ?? null }])),
  diff: failed.body.diff?.markdown ?? null,
};

for (const p of pages) {
  p.billed = await billed(p.call_id);
  if (p.first_attempt) p.first_attempt.billed = await billed(p.first_attempt.call_id);
}

console.log(JSON.stringify({ language: 'node', countries: COUNTRIES, formats: FORMATS, max_wait: MAX_WAIT, pages, failure, measured_at: new Date().toISOString().slice(0, 10) }, null, 2));

What we got

PageCountryResultlangFinal URLPricesCookie bannerMarkdown diff vs usCallMeasured
Steam store pageus200enhttps://store.steampowered.com/app/620/Portal_2/$9.99, $1.99 (USD)nobaseline35.4 s · 175.9 thread-s · 3.0 MB, diffs 140 KB Markdown + 1.4 MB HTML2026-11-10
Steam store pagede200 (partial)dehttps://store.steampowered.com/app/620/Portal_2/9,69€, 1,59€ (EUR)yes46 KB: +226 −224 lines; $9.99 → 9,69€, $1.99 → 1,59€, $19.98 → 19,38€—2026-11-10
Steam store pagegb200enhttps://store.steampowered.com/app/620/Portal_2/£8.19, £1.69 (GBP)yes3.3 KB: +20 −12 lines; $9.99 → £8.19, $1.99 → £1.69, $19.98 → £16.38—2026-11-10
Steam store pagejp200jahttps://store.steampowered.com/app/620/Portal_2/¥ 1,400, ¥ 205 (JPY)no48 KB: +179 −179 lines; $9.99 → ¥ 1,400, $1.99 → ¥ 205, $19.98 → ¥ 2,800—2026-11-10
Steam store pagebr200pt-brhttps://store.steampowered.com/app/620/Portal_2/R$ 33,99, R$ 4,49 (BRL)no42 KB: +171 −171 lines; $9.99 → R$ 33,99, $1.99 → R$ 4,49, $19.98 → R$ 67,98—2026-11-10
Google home pageus200enhttps://www.google.com/—nobaseline33 s · 164.1 thread-s · 3.2 MB, diffs 22 KB Markdown + 1.7 MB HTML2026-11-10
Google home pagede200 (partial)dehttps://www.google.com/—yes8.5 KB: +141 −16 lines—2026-11-10
Google home pagegb200en-GBhttps://www.google.com/—yes6.8 KB: +137 −13 lines—2026-11-10
Google home pagejp200jahttps://www.google.com/—no3.7 KB: +18 −16 lines—2026-11-10
Google home pagebr200pt-BRhttps://www.google.com/—no3.5 KB: +17 −17 lines—2026-11-10
Nike home pageus200en-UShttps://www.nike.com/—nobaseline46.8 s · 231.9 thread-s · 13.6 MB, diffs 176 KB Markdown + 7.7 MB HTML2026-11-10
Nike home pagede200 (partial)de-DEhttps://www.nike.com/de/50 €, £50 (EUR, GBP)no53 KB: +494 −810 lines—2026-11-10
Nike home pagegbpage_timeout————null (no comparison)—2026-11-10
Nike home pagejp200 (partial)ja-JPhttps://www.nike.com/jp/—no56 KB: +606 −792 lines—2026-11-10
Nike home pagebr200en-UShttps://www.nike.com/—no67 KB: +596 −592 lines—2026-11-10
example.com (control)us200enhttps://example.com/—nobaseline7.1 s · 35.1 thread-s · 19 KB, diffs 0 bytes Markdown + 0 bytes HTML2026-11-10
example.com (control)de200enhttps://example.com/—no"" (identical)—2026-11-10
example.com (control)gb200enhttps://example.com/—no"" (identical)—2026-11-10
example.com (control)jp200enhttps://example.com/—no"" (identical)—2026-11-10
example.com (control)br200enhttps://example.com/—no"" (identical)—2026-11-10

From the Node.js run on 2026-11-10. IP addresses are replaced with placeholders (203.0.113.x); equal addresses stay equal. The other languages produced the same findings.

Raw output (Node.js)
{
  "language": "node",
  "countries": [
    "us",
    "de",
    "gb",
    "jp",
    "br"
  ],
  "formats": [
    "markdown",
    "html"
  ],
  "max_wait": 45,
  "pages": [
    {
      "page": "Steam store page",
      "url": "https://store.steampowered.com/app/620/Portal_2/",
      "attempts": 1,
      "first_attempt": null,
      "status": 200,
      "error": null,
      "seconds": 35.4,
      "call_id": "c27880d3-30ae-4993-a3f6-15a89cfd2d45",
      "warning": null,
      "response_bytes": 3096123,
      "diff_bytes": {
        "markdown": 143433,
        "html": 1477835
      },
      "ok_countries": [
        "us",
        "de",
        "gb",
        "jp",
        "br"
      ],
      "countries": {
        "us": {
          "status": 200,
          "error": null,
          "partial": false,
          "lang": "en",
          "url": "https://store.steampowered.com/app/620/Portal_2/",
          "title": "Portal 2 on Steam",
          "currencies": [
            "USD"
          ],
          "prices": [
            "$9.99",
            "$1.99",
            "$19.98",
            "$14.98"
          ],
          "consent_banner": false,
          "markdown_bytes": 22994,
          "html_bytes": 223766,
          "same_markdown_as_baseline": null,
          "diff": null
        },
        "de": {
          "status": 200,
          "error": null,
          "partial": true,
          "lang": "de",
          "url": "https://store.steampowered.com/app/620/Portal_2/",
          "title": "Portal 2 bei Steam",
          "currencies": [
            "EUR"
          ],
          "prices": [
            "9,69€",
            "1,59€",
            "19,38€",
            "14,54€"
          ],
          "consent_banner": true,
          "markdown_bytes": 23898,
          "html_bytes": 185916,
          "same_markdown_as_baseline": false,
          "diff": {
            "markdown": {
              "bytes": 47265,
              "hunks": 1,
              "added": 226,
              "removed": 224,
              "price_changes": [
                "$9.99 → 9,69€",
                "$1.99 → 1,59€",
                "$19.98 → 19,38€"
              ]
            },
            "html_bytes": 399478
          }
        },
        "gb": {
          "status": 200,
          "error": null,
          "partial": false,
          "lang": "en",
          "url": "https://store.steampowered.com/app/620/Portal_2/",
          "title": "Portal 2 on Steam",
          "currencies": [
            "GBP"
          ],
          "prices": [
            "£8.19",
            "£1.69",
            "£16.38",
            "£12.28"
          ],
          "consent_banner": true,
          "markdown_bytes": 23472,
          "html_bytes": 226029,
          "same_markdown_as_baseline": false,
          "diff": {
            "markdown": {
              "bytes": 3365,
              "hunks": 9,
              "added": 20,
              "removed": 12,
              "price_changes": [
                "$9.99 → £8.19",
                "$1.99 → £1.69",
                "$19.98 → £16.38"
              ]
            },
            "html_bytes": 334452
          }
        },
        "jp": {
          "status": 200,
          "error": null,
          "partial": false,
          "lang": "ja",
          "url": "https://store.steampowered.com/app/620/Portal_2/",
          "title": "Steam:Portal 2",
          "currencies": [
            "JPY"
          ],
          "prices": [
            "¥ 1,400",
            "¥ 205",
            "¥ 2,800",
            "¥ 2,100"
          ],
          "consent_banner": false,
          "markdown_bytes": 26593,
          "html_bytes": 233295,
          "same_markdown_as_baseline": false,
          "diff": {
            "markdown": {
              "bytes": 49372,
              "hunks": 1,
              "added": 179,
              "removed": 179,
              "price_changes": [
                "$9.99 → ¥ 1,400",
                "$1.99 → ¥ 205",
                "$19.98 → ¥ 2,800"
              ]
            },
            "html_bytes": 397752
          }
        },
        "br": {
          "status": 200,
          "error": null,
          "partial": false,
          "lang": "pt-br",
          "url": "https://store.steampowered.com/app/620/Portal_2/",
          "title": "Portal 2 no Steam",
          "currencies": [
            "BRL"
          ],
          "prices": [
            "R$ 33,99",
            "R$ 4,49",
            "R$ 67,98",
            "R$ 50,98"
          ],
          "consent_banner": false,
          "markdown_bytes": 24260,
          "html_bytes": 225064,
          "same_markdown_as_baseline": false,
          "diff": {
            "markdown": {
              "bytes": 43431,
              "hunks": 2,
              "added": 171,
              "removed": 171,
              "price_changes": [
                "$9.99 → R$ 33,99",
                "$1.99 → R$ 4,49",
                "$19.98 → R$ 67,98"
              ]
            },
            "html_bytes": 346153
          }
        }
      },
      "billed": {
        "engine": "function:geo",
        "weight": 5,
        "thread_seconds": 175.9
      }
    },
    {
      "page": "Google home page",
      "url": "https://www.google.com/",
      "attempts": 1,
      "first_attempt": null,
      "status": 200,
      "error": null,
      "seconds": 33,
      "call_id": "99126d18-87e8-4bd0-9a52-ab97c6876ccc",
      "warning": null,
      "response_bytes": 3353632,
      "diff_bytes": {
        "markdown": 22951,
        "html": 1751591
      },
      "ok_countries": [
        "us",
        "de",
        "gb",
        "jp",
        "br"
      ],
      "countries": {
        "us": {
          "status": 200,
          "error": null,
          "partial": false,
          "lang": "en",
          "url": "https://www.google.com/",
          "title": "Google",
          "currencies": [],
          "prices": [],
          "consent_banner": false,
          "markdown_bytes": 1612,
          "html_bytes": 240533,
          "same_markdown_as_baseline": null,
          "diff": null
        },
        "de": {
          "status": 200,
          "error": null,
          "partial": true,
          "lang": "de",
          "url": "https://www.google.com/",
          "title": "Google",
          "currencies": [],
          "prices": [],
          "consent_banner": true,
          "markdown_bytes": 6927,
          "html_bytes": 340188,
          "same_markdown_as_baseline": false,
          "diff": {
            "markdown": {
              "bytes": 8679,
              "hunks": 1,
              "added": 141,
              "removed": 16,
              "price_changes": []
            },
            "html_bytes": 461245
          }
        },
        "gb": {
          "status": 200,
          "error": null,
          "partial": false,
          "lang": "en-GB",
          "url": "https://www.google.com/",
          "title": "Google",
          "currencies": [],
          "prices": [],
          "consent_banner": true,
          "markdown_bytes": 5585,
          "html_bytes": 321343,
          "same_markdown_as_baseline": false,
          "diff": {
            "markdown": {
              "bytes": 6956,
              "hunks": 2,
              "added": 137,
              "removed": 13,
              "price_changes": []
            },
            "html_bytes": 442400
          }
        },
        "jp": {
          "status": 200,
          "error": null,
          "partial": false,
          "lang": "ja",
          "url": "https://www.google.com/",
          "title": "Google",
          "currencies": [],
          "prices": [],
          "consent_banner": false,
          "markdown_bytes": 2137,
          "html_bytes": 276475,
          "same_markdown_as_baseline": false,
          "diff": {
            "markdown": {
              "bytes": 3765,
              "hunks": 1,
              "added": 18,
              "removed": 16,
              "price_changes": []
            },
            "html_bytes": 462954
          }
        },
        "br": {
          "status": 200,
          "error": null,
          "partial": false,
          "lang": "pt-BR",
          "url": "https://www.google.com/",
          "title": "Google",
          "currencies": [],
          "prices": [],
          "consent_banner": false,
          "markdown_bytes": 1880,
          "html_bytes": 263962,
          "same_markdown_as_baseline": false,
          "diff": {
            "markdown": {
              "bytes": 3551,
              "hunks": 1,
              "added": 17,
              "removed": 17,
              "price_changes": []
            },
            "html_bytes": 384992
          }
        }
      },
      "billed": {
        "engine": "function:geo",
        "weight": 5,
        "thread_seconds": 164.1
      }
    },
    {
      "page": "Nike home page",
      "url": "https://www.nike.com/",
      "attempts": 1,
      "first_attempt": null,
      "status": 200,
      "error": null,
      "seconds": 46.8,
      "call_id": "23dd89ec-6913-408b-b490-2b64a8479cfa",
      "warning": null,
      "response_bytes": 14223084,
      "diff_bytes": {
        "markdown": 180248,
        "html": 8065612
      },
      "ok_countries": [
        "us",
        "de",
        "jp",
        "br"
      ],
      "countries": {
        "us": {
          "status": 200,
          "error": null,
          "partial": false,
          "lang": "en-US",
          "url": "https://www.nike.com/",
          "title": "Nike. Just Do It. Nike.com",
          "currencies": [],
          "prices": [],
          "consent_banner": false,
          "markdown_bytes": 33868,
          "html_bytes": 1510798,
          "same_markdown_as_baseline": null,
          "diff": null
        },
        "de": {
          "status": 200,
          "error": null,
          "partial": true,
          "lang": "de-DE",
          "url": "https://www.nike.com/de/",
          "title": "Nike. Just Do It. Nike DE",
          "currencies": [
            "EUR",
            "GBP"
          ],
          "prices": [
            "50 €",
            "£50",
            "100 €",
            "£50"
          ],
          "consent_banner": false,
          "markdown_bytes": 19388,
          "html_bytes": 847795,
          "same_markdown_as_baseline": false,
          "diff": {
            "markdown": {
              "bytes": 54511,
              "hunks": 1,
              "added": 494,
              "removed": 810,
              "price_changes": []
            },
            "html_bytes": 2363409
          }
        },
        "gb": {
          "status": null,
          "error": "page_timeout",
          "partial": false,
          "lang": null,
          "url": null,
          "title": null,
          "currencies": [],
          "prices": [],
          "consent_banner": null,
          "markdown_bytes": 0,
          "html_bytes": 0,
          "same_markdown_as_baseline": null,
          "diff": {
            "markdown": null,
            "html_bytes": null
          }
        },
        "jp": {
          "status": 200,
          "error": null,
          "partial": true,
          "lang": "ja-JP",
          "url": "https://www.nike.com/jp/",
          "title": "Nike. Just Do It. Nike.com (JP).オンラインストア (通販サイト)",
          "currencies": [],
          "prices": [],
          "consent_banner": false,
          "markdown_bytes": 22074,
          "html_bytes": 1243359,
          "same_markdown_as_baseline": false,
          "diff": {
            "markdown": {
              "bytes": 57299,
              "hunks": 1,
              "added": 606,
              "removed": 792,
              "price_changes": []
            },
            "html_bytes": 2759200
          }
        },
        "br": {
          "status": 200,
          "error": null,
          "partial": false,
          "lang": "en-US",
          "url": "https://www.nike.com/",
          "title": "Nike. Just Do It. Nike.com",
          "currencies": [],
          "prices": [],
          "consent_banner": false,
          "markdown_bytes": 33939,
          "html_bytes": 1513445,
          "same_markdown_as_baseline": false,
          "diff": {
            "markdown": {
              "bytes": 68438,
              "hunks": 1,
              "added": 596,
              "removed": 592,
              "price_changes": []
            },
            "html_bytes": 2943003
          }
        }
      },
      "billed": {
        "engine": "function:geo",
        "weight": 5,
        "thread_seconds": 231.9
      }
    },
    {
      "page": "example.com (control)",
      "url": "https://example.com/",
      "attempts": 1,
      "first_attempt": null,
      "status": 200,
      "error": null,
      "seconds": 7.1,
      "call_id": "aaa4766c-4092-42d0-9c48-1f8237c32ae6",
      "warning": null,
      "response_bytes": 19513,
      "diff_bytes": {
        "markdown": 0,
        "html": 0
      },
      "ok_countries": [
        "us",
        "de",
        "gb",
        "jp",
        "br"
      ],
      "countries": {
        "us": {
          "status": 200,
          "error": null,
          "partial": false,
          "lang": "en",
          "url": "https://example.com/",
          "title": "Example Domain",
          "currencies": [],
          "prices": [],
          "consent_banner": false,
          "markdown_bytes": 1360,
          "html_bytes": 2373,
          "same_markdown_as_baseline": null,
          "diff": null
        },
        "de": {
          "status": 200,
          "error": null,
          "partial": false,
          "lang": "en",
          "url": "https://example.com/",
          "title": "Example Domain",
          "currencies": [],
          "prices": [],
          "consent_banner": false,
          "markdown_bytes": 1360,
          "html_bytes": 2373,
          "same_markdown_as_baseline": true,
          "diff": {
            "markdown": {
              "bytes": 0,
              "hunks": 0,
              "added": 0,
              "removed": 0,
              "price_changes": []
            },
            "html_bytes": 0
          }
        },
        "gb": {
          "status": 200,
          "error": null,
          "partial": false,
          "lang": "en",
          "url": "https://example.com/",
          "title": "Example Domain",
          "currencies": [],
          "prices": [],
          "consent_banner": false,
          "markdown_bytes": 1360,
          "html_bytes": 2373,
          "same_markdown_as_baseline": true,
          "diff": {
            "markdown": {
              "bytes": 0,
              "hunks": 0,
              "added": 0,
              "removed": 0,
              "price_changes": []
            },
            "html_bytes": 0
          }
        },
        "jp": {
          "status": 200,
          "error": null,
          "partial": false,
          "lang": "en",
          "url": "https://example.com/",
          "title": "Example Domain",
          "currencies": [],
          "prices": [],
          "consent_banner": false,
          "markdown_bytes": 1360,
          "html_bytes": 2373,
          "same_markdown_as_baseline": true,
          "diff": {
            "markdown": {
              "bytes": 0,
              "hunks": 0,
              "added": 0,
              "removed": 0,
              "price_changes": []
            },
            "html_bytes": 0
          }
        },
        "br": {
          "status": 200,
          "error": null,
          "partial": false,
          "lang": "en",
          "url": "https://example.com/",
          "title": "Example Domain",
          "currencies": [],
          "prices": [],
          "consent_banner": false,
          "markdown_bytes": 1360,
          "html_bytes": 2373,
          "same_markdown_as_baseline": true,
          "diff": {
            "markdown": {
              "bytes": 0,
              "hunks": 0,
              "added": 0,
              "removed": 0,
              "price_changes": []
            },
            "html_bytes": 0
          }
        }
      },
      "billed": {
        "engine": "function:geo",
        "weight": 5,
        "thread_seconds": 35.1
      }
    }
  ],
  "failure": {
    "status": 200,
    "max_wait": 1,
    "results": {
      "us": {
        "status": null,
        "error": "page_timeout"
      },
      "de": {
        "status": null,
        "error": "page_timeout"
      }
    },
    "diff": {
      "de": null
    }
  },
  "measured_at": "2026-11-10"
}

Takeaways