← Blog

Tooling

Cloudflare temp accounts: 19 valkuilen voor scrapers

Negentien valkuilen die we tegenkwamen met Cloudflare temp accounts bij een prijsmonitor van 4.800 pagina's per week op Magento 2.4. Gerangschikt naar hoe stil ze je data slopen.

Jacob Molkenboer· Oprichter · A Brand New Company· 22 jun 2026· 9 min
Stapel manila kaarten met touw, groen papieren tabje, koperen label en rubberen stempel op ivoren bureau.

Het is 23:14 op een dinsdag in mei. De scraper is net klaar met zijn nachtelijke ronde over 4.800 productpagina's voor een prijsmonitor die we bouwden voor een Eindhovense distributeur. Elke request gaf 200 OK terug. Elke prijs onder €1.200 parste correct. Elke prijs boven €1.200 kwam terug als null.

We routeerden die agent al zes weken via Cloudflare's temporary accounts voor AI-agents. Het is een echte vooruitgang ten opzichte van residential proxy pools: schonere trust, schonere quota, schonere audit. Het is ook een nieuw oppervlak, en de failure modes zijn niet de failure modes die je al kent.

Dit is de cheatsheet van negentien valkuilen die we vastlegden, gerangschikt naar hoe stil ze je data corrupt maken. Nummer één tot en met vijf doen je prijzen kwijtraken zonder dat er een alert afgaat. Nummer zeventien tot negentien zijn alleen vervelend.

De setup

Veertien webshops. Acht op Magento 2.4 met full-page cache via Varnish plus een ESI-laag voor het variant pricing block. Twee op Shopware. Vier op maatwerk-PHP. Cart en checkout draaien bij de helft op aparte subdomeinen — een multi-domain overdracht die de merchants hadden overgeërfd van een redesign uit 2017 en nooit hadden ontward.

De taak van de agent: één keer per uur de actuele prijs, voorraad en variant-specifieke bundle pricing ophalen, dedupliceren en de deltas naar de Snowflake van de klant schrijven. Zo'n 4.800 page-loads per week, plus retries op transient 5xx.

We kozen om drie redenen voor temporary Cloudflare accounts. Identiteit per agent, zodat een buggy run geïsoleerd en ingetrokken kan worden. Geen proxy-pool tax. En de bonus dat Cloudflare's bot detection verkeer van zijn eigen temp accounts soepeler behandelt dan onbekende residential IPs. Dat laatste punt is precies waarom dit oppervlak interessant is, en precies waarom de fouten stil zijn.

Waarom we rangschikten in plaats van opsomden

Een platte lijst valkuilen is nutteloos. Wat je nodig hebt is welke ervan de rijen corrumperen die je in een price-history tabel schrijft, en welke je alleen latency of geld kosten. De eerste soort is gevaarlijk omdat de alert nooit afgaat. De tweede soort verschijnt een uur na het begin in een Grafana-panel.

Waarschuwing

Een 200 OK van een Magento-pagina achter een CDN vertelt je dat de HTTP-request slaagde. Het vertelt je niet dat het prijsblok rendert, dat de cache fris was, of dat de cookie die je valuta selecteerde de round trip overleefde. Valideer de body, niet de status code.

Tier 1 — stil dataverlies

Dit zijn de vijf waar we echt geld aan verloren. Als je scraper direct naar een downstream systeem schrijft, fix deze voordat je iets anders op deze lijst aanpakt.

  1. Het €1.200 ESI-fragment. Magento rendert het high-value variant block via een afgeschermd ESI-gat. Cloudflare temp accounts respecteren Cache-Control: private op de parent, maar het fragment heeft een eigen key en blijft langer hangen dan zijn opgegeven TTL. Resultaat: de parent-pagina is fris, het prijsblok erin is twintig minuten oud. We betrapten dit alleen omdat een sales lead vroeg waarom ons dashboard €1.149 toonde op een artikel dat de merchant net naar €1.289 had verhoogd.
  2. Session-cookie drop bij multi-domain overdracht. Een session die op shop.example.com is uitgegeven reist niet betrouwbaar mee naar checkout.example.com onder een temp account, omdat __cf_bm gebonden is aan de uitgevende host en niet aan de eTLD+1. De overdracht slaagt, het session id rouleert stil, de agent denkt dat hij uitgelogd is, doet een retry, en je vuurt dubbel.
  3. JS-challenge HTML gecachet op de page-URL. Als het temp account een soft challenge raakt, kan de challenge-HTML in cache landen onder de URL-key van de echte pagina. De volgende request geeft 200 OK op het challenge-document. Je parser ziet geen itemprop="price" en schrijft null. Geen 4xx, geen logregel, geen Sentry-event.
  4. Dubbele Set-Cookie samengevouwen. Als de upstream twee cookies met dezelfde naam stuurt (Magento stuurt twee form_key cookies op cart-pagina's), behoudt de worker layer alleen de laatste. De helft van je B2B-prijsvarianten hangt af van de cookie die gedropt werd.
  5. Origin gestript bij sibling-domain. Een cross-origin fetch() vanuit een temp-account context naar een sibling domain stript Origin stil als het temp account geen expliciete binding voor beide hosts heeft. Magento's GraphQL price endpoint weigert dan met een lege 200-OK body, wat je retry-logica niet vangt omdat de status code prima is.

Tier 2 — cookies, headers, fingerprints

  1. SameSite downgrade. SameSite=Lax cookies gedragen zich als Strict wanneer de temp-account proxy zijn eigen X-Forwarded-* headers injecteert en de upstream de request leest als een top-level navigatie.
  2. Varnish session re-key bij rotatie. Magento draait achter Varnish; sessions krijgen een nieuwe key bij elke credential-rotatie van het temp account. Je geauthenticeerde prijsoverzicht wordt halverwege guest, en guest-prijzen laten de loyalty discount band helemaal vallen.
  3. Per-eTLD+1 jar-lek. Cookie-isolatie tussen temp-account contexten loopt alleen per registreerbaar domein. shop.example.fr en shop.example.nl delen een jar, dus valuta en locale lekken tussen agents die je dacht dat onafhankelijk waren.
  4. Secure-flag gestript bij scheme upgrade. Als een temp account HTTP onderweg upgradet naar HTTPS, verliezen cookies die in die hop terugkomen hun Secure-flag. De volgende request kan ze zonder waarschuwing downgraden naar een plain channel.
  5. JA3-shift binnen één session. De TLS-fingerprint verschuift tussen requests onder load. Bot fight mode leest dat als hetzelfde IP dat zich opeens als twee clients gedraagt. Je krijgt een uur soft-block, en het symptoom is geen 403; het zijn vertraagde 200s met de verkeerde valuta geselecteerd.
  6. Referer herschreven op cross-origin scripts. Magento's legacy JSONP-style prijs-fetches breken omdat het temp account Referer herschrijft op cross-origin script tags. Het price endpoint geeft 200 OK terug met een JS error string in plaats van JSON.

Tier 3 — latency, quota, geografie

  1. Spin-up kosten. De eerste request op een vers temp account kost in onze metingen 400 tot 900ms. Op menselijk tempo te dragen; pijnlijk bij 4.800 pagina's per week waar retries de cold-start tax vermenigvuldigen.
  2. Quota op parent-niveau. Request quota wordt gedeeld over alle temp accounts onder één parent. Eén op hol geslagen scraper trekt de rest leeg, en het per-temp-account dashboard vertelt je dat je headroom hebt die je in werkelijkheid niet hebt.
  3. Vaste colo. Een temp account zit voor zijn hele leven vast aan één Cloudflare colo. EU-gehoste Magento met een US-routed temp account voegt zo'n 120ms per round trip toe. Vanaf week twee dwongen we colo-selectie via een region tag af.
  4. WebSocket upgrade-broosheid. Het 101 Switching Protocols pad door een temp-account proxy faalt als de upstream een niet-lege body meestuurt met de upgrade. Magento's admin pub-sub doet dat; de storefront niet, dus deze bijt alleen interne tooling.
  5. HTTP/2 push gestript. Server-gepushte resources worden op de proxy-laag gedropt. Magento's preload-hints worden een volledige waterfall, wat je render-budget-rekensom verschuift als je voor screenshot-diffing leunt op Above-the-Fold timings.

Tier 4 — alleen vervelend

  1. User-Agent drift. De UA-string van het temp account verandert op geen enkel publiek schema. Als je er een regex op zet voor tagging, breekt je tagger stil.
  2. Vertraging in audit log. Logs lopen 6 tot 12 uur achter. Debuggen van "wat verzond mijn agent om 03:14 vorige vrijdag" wordt een geloofsoefening.
  3. Verkeerde rate-limit header. X-RateLimit-Remaining rapporteert de pool van het parent account, niet die van het temp account. Het getal dat je vertrouwt is het verkeerde getal.

De assertion die de helft hiervan oploste

De wijziging met de hoogste ROI die we maakten: weigeren om een rij te schrijven waarvan het prijsveld faalde op een per-template presence check. Status codes werden adviserend. De parser werd leidend.

def assert_price(html: str, template: dict) -> float:
    """Return parsed price or raise. HTTP 200 is not a guarantee."""
    m = PRICE_RE[template["id"]].search(html)
    if not m:
        raise ScrapeError("price_block_missing", template["id"])
    value = float(m.group(1).replace(".", "").replace(",", "."))
    if not 0 < value < 1_000_000:
        raise ScrapeError("price_implausible", value)
    if template["variant_required"] and "data-variant-sku" not in html:
        raise ScrapeError("variant_block_missing", template["id"])
    return value

De variant-block assertion alleen ving valkuil één in productie binnen veertig minuten na deployment. Het had hem zes weken eerder kunnen vangen.

Bredere context om mee te nemen

Twee aanpalende verschuivingen horen op hetzelfde plan. Eén: Anthropic begint op 8 juli 2026 met ID-verificatie voor bepaalde capabilities; als je scraper geparste HTML naar Claude pijpt voor variant-extractie, lopen je provider-side auth posture en je fetch-side auth posture nu op verschillende klokken, en wil je één dashboard voor beide. Twee: het bredere gesprek over het bouwen van betrouwbare agentic AI-systemen convergeert op de les die deze cheatsheet leert: de fouten die ertoe doen zijn de fouten die een succesvolle status code teruggeven.

Wat we vanaf dag één anders zouden doen

Valideer elke geparste pagina tegen een per-template price-presence assertion vóór insert. Pin temp accounts vanaf de eerste deployment aan een region tag. Stempel de resolved colo, de JA3-hash en de parent-cookie hash op elke request-logregel zodat je valkuilen vijf tot tien kunt correleren zonder iets opnieuw te draaien. Behandel een 200 OK met een leeg prijsveld als een harde fout, niet als een rij om opnieuw te proberen.

Toen we de prijsmonitor voor die Eindhovense distributeur bouwden, was punt één op deze lijst waar we steeds tegenaan liepen — het ESI-fragment dat verouderd raakt onder een fris ogende parent. We losten het op met een Worker rule die een Vary op de variant-cookie afdwong, plus een periodieke AI-agent sweep die elk product boven het prijsplafond met cache busting opnieuw ophaalde voordat de rij als compleet gold.

Vijf-minuten audit die je vandaag kunt draaien: grep de output van afgelopen week van je scraper op rijen waar price null is maar stock positief. Die ratio is je silent-failure ondergrens.

Kern

Een 200 OK van een Magento-pagina achter een CDN bewijst dat de request slaagde, niet dat de prijs rendeerde — valideer de body, rangschik valkuilen op stil dataverlies en fix die eerst.

FAQ

Zijn Cloudflare temporary accounts beter dan residential proxies voor scraping?

Voor trust, audit en quota zijn ze duidelijk beter. Voor data-correctheid introduceren ze een nieuwe klasse stille fouten, vooral rond gecachte fragmenten en multi-domain cookies. Plan voor beide oppervlakken.

Waarom falen prijzen boven €1.200 vaker op Magento 2.4?

High-value varianten renderen vaak via een apart ESI-fragment met een eigen cache key. Een verse parent-pagina kan een verouderd variant block omsluiten, en de agent ziet een geldig ogende maar achterhaalde prijs.

Wat is de fix met de hoogste ROI?

Weiger elke rij te schrijven waarvan het geparste prijsveld faalt op een per-template presence- en plausibility-check. Maak de parser leidend, niet de HTTP status code.

data scrapingai agentstoolingmagentoautomationintegrations

Iets bouwen?

Start een project