Your cart is currently empty!
Author: Xavier Fok
-
GDPR compliance for web scraping in 2026: a practical guide
GDPR compliance for web scraping in 2026: a practical guide
GDPR web scraping compliance is the single most-cited legal blocker that engineering teams hit when they try to scale data collection across European targets. The regulation does not ban scraping. It does not even mention scraping. What it does is impose a strict regime on how personal data is collected, processed, and stored, and almost every meaningful scraping project sweeps up at least some personal data along the way. The result is a gap between what teams think they are doing (collecting public information) and what regulators see (processing personal data without a documented lawful basis). This guide walks through what GDPR actually says, how the EU enforcement environment shifted in 2024 and 2025, what scraping operators in 2026 must put in place to stay defensible, and where the live court rulings draw the line.
The guide is built for technical leads, data engineers, and product owners who already run or are planning a scraping pipeline that touches EU traffic. It is not a substitute for counsel. It is a working framework so you walk into that conversation with the right map.
What GDPR actually covers in scraping context
The General Data Protection Regulation (Regulation (EU) 2016/679) applies to the processing of personal data of individuals in the EU and EEA, regardless of where the processor sits. That extraterritorial reach (Article 3) is the part most non-EU teams underestimate. If you scrape a dataset that contains EU residents’ personal data, GDPR applies even if your servers are in Singapore, your team is in the US, and the website you scraped is hosted in Brazil.
Personal data under Article 4(1) is any information relating to an identified or identifiable natural person. The bar is very low. A name, an email, a username, an IP address, a cookie identifier, a device fingerprint, a profile photo, a location signal, a job title combined with a company, even a forum post that reveals an opinion attached to a pseudonym that can be re-identified, all of these qualify. The European Data Protection Board (EDPB) has consistently taken an expansive view. If a human can plausibly be re-identified from your dataset, even after combination with other public sources, the data is personal.
Processing under Article 4(2) is also broad: collection, storage, structuring, retrieval, dissemination, alignment, and erasure all count. Scraping is collection. Storing the result in a database is storage. Running it through an LLM is processing. Sending it to a customer is dissemination. Each step needs a lawful basis.
The lawful bases are set out in Article 6. The two that matter for scraping are consent (almost always impossible to obtain at scrape time) and legitimate interest (the workhorse for B2B and research scraping, but it requires a documented Legitimate Interest Assessment, often called an LIA). The remaining bases (contract, legal obligation, vital interest, public interest) rarely apply.
For a wider tour of the personal-versus-public-data question, see the personal vs public data scraping framework. For US-side parallels, the CCPA compliance guide for scrapers is the right next read.
The legitimate interest pathway in practice
Article 6(1)(f) allows processing where it is necessary for the legitimate interests pursued by the controller, except where those interests are overridden by the rights and freedoms of the data subject. That balancing test is the entire game.
A practical LIA has three parts. First, the purpose test: is the interest you are pursuing genuine, lawful, and clearly articulated? Market research, fraud prevention, journalism, and competitive intelligence all generally pass. Mass profile harvesting for cold outbound spam usually does not.
Second, the necessity test: can the same outcome be achieved with less personal data? If your downstream use case only needs aggregated counts, you should not be storing names. If you need company-level signals, you should not be storing individual contributor profiles. Data minimisation under Article 5(1)(c) is not optional.
Third, the balancing test: do the data subjects’ interests, rights, or fundamental freedoms override yours? This is where you weigh expectations. A user who posted on a public forum reasonably expects that post to be readable by other humans. They probably do not expect it to be ingested by a competitor’s LLM training pipeline at industrial scale and re-surfaced in unrelated contexts. The test is contextual.
Document the LIA. Date it. Sign it. Re-run it whenever the scope, source list, or downstream use changes. EU regulators in 2025 increasingly asked for the LIA on first contact during investigations, and absence of one is itself evidence of non-compliance.
Compliance checklist for scraping operators
Control What it requires Why it matters Lawful basis documented Written LIA per scraping target Article 6 evidence Privacy notice published Public page describing your processing Article 14 transparency Data minimisation by design Scrape only fields you actually use Article 5(1)(c) Purpose limitation Define use cases; do not silently expand Article 5(1)(b) Storage limits Set retention windows; auto-delete Article 5(1)(e) Right-to-erasure mechanism Public email or form for deletion requests Article 17 DPO or contact appointed If at scale, appoint a Data Protection Officer Articles 37-39 Records of processing Article 30 register listing each scraping activity Article 30 DPIA where high risk Required for large-scale profiling or sensitive data Article 35 Vendor and processor agreements Article 28 contracts with proxy and storage providers Article 28 Cross-border transfer mechanism SCCs or adequacy if data leaves EEA Chapter V Breach response plan 72-hour notification protocol to supervisory authority Article 33 Pseudonymisation Strip direct identifiers where not strictly needed Article 25 A team that ticks every row above is genuinely defensible. A team that ticks fewer than half is one regulator letter away from a problem.
How EU enforcement shifted in 2024 and 2025
Two trends matter. First, regulators moved from reactive enforcement (responding to complaints) to proactive sweeps targeting AI training data, news scraping, and B2B contact databases. The Italian Garante, the French CNIL, and the Dutch Autoriteit Persoonsgegevens all opened investigations of scraping operators in 2024 and 2025, several of which closed with seven-figure fines. Second, the line between data controller and data processor in scraping pipelines tightened. Buying scraped datasets from third parties no longer insulates you. If you process the data, you are a controller for that processing, full stop, and your Article 28 contract with the seller does not change that.
The Meta v. Bright Data ruling in the Israeli court, while not GDPR per se, was widely cited by EU regulators in 2025 because it addressed the same fact pattern: scraping public profiles at scale. The court found that scraping logged-out public data did not violate Meta’s terms (they only bind logged-in users), but the EU regulators were quick to point out that absence of a contract violation does not equal a lawful basis under GDPR. Public availability is not a get-out-of-GDPR card.
For the deeper US-side analysis of similar fact patterns, see the HiQ Labs v LinkedIn ruling explainer.
Decision tree for an EU-touching scrape
Use this before you queue a new target.
Q1: Does the target site host personal data of EU/EEA residents? ├── No -> GDPR likely not in scope. Document the assessment. └── Yes -> Q2 Q2: Do you have a documented lawful basis (LIA preferred)? ├── No -> Stop. Write the LIA first. └── Yes -> Q3 Q3: Have you minimised fields to only what you need? ├── No -> Trim the schema before launching. └── Yes -> Q4 Q4: Is there a published privacy notice describing this processing? ├── No -> Publish the notice; link it in your contact form. └── Yes -> Q5 Q5: Is data leaving the EEA after processing? ├── Yes -> Confirm SCCs or adequacy decision are in place. └── No -> Q6 Q6: Is the volume or sensitivity high enough to trigger DPIA? ├── Yes -> Run the DPIA before launch. └── No -> Proceed; log the assessment in your Article 30 register.Each branch produces an artefact. That paper trail is what defends you in an investigation.
Special cases: AI training data, journalism, and B2B
AI training is the highest-risk scraping use case in 2026. The European AI Act now layers obligations on top of GDPR for any training pipeline that touches personal data. Transparency about training data sources is becoming an audit expectation, not a nice-to-have. If you scrape to train a model, document each source, the lawful basis, the consent state, and the opt-out mechanism. Several large model providers were fined in 2025 for scraping personal data without an LIA.
Journalism and academic research enjoy a partial exemption under Article 85. Member states implement this differently, so a French journalist and a German academic operate under different practical rules even though both fall under the journalism exemption. The exemption is not a blanket immunity; it requires the processing to be genuinely for journalism or research purposes, not commercial repackaging.
B2B scraping is the gray zone where most commercial teams live. Contact data of identified individuals at companies (jane.doe@acmecorp.com plus a job title) is personal data, full stop. The fact that it is professional context does not remove personhood. Member states diverge on how strictly this is enforced (Germany strict, UK pragmatic, Spain mid), but the safe assumption for cross-border B2B scrapers is that contact-level processing requires an LIA plus an opt-out path.
Data subject rights and how to honour them
Articles 12 to 22 grant data subjects rights that survive scraping. The two that bite scrapers hardest are the right to erasure (Article 17) and the right to object (Article 21).
You must publish a clear way for any individual to request deletion of their data from your stored corpus. Email is acceptable. A public form is better. The response window is one month, extendable to three months for complex requests. You must verify the request (to prevent malicious deletion) but you cannot use verification as a delay tactic.
Right to object is broader. Anyone can object to processing based on legitimate interest, and you must stop unless you can demonstrate compelling legitimate grounds that override their interests. In practice, most teams just delete and move on, because litigating each objection is more expensive than the marginal data point.
For internal policy guidance on how to operationalise these rights, see building an ethics-first scraping policy.
External references
For the canonical regulation text and EDPB guidance, the official source is gdpr.eu and the EDPB guidelines library at edpb.europa.eu. For the Meta v. Bright Data ruling text and EU regulator commentary on it, the EDPB published a working note in late 2024 that summarises the cross-border implications.
Comparison: GDPR vs other major privacy regimes for scrapers
Regime Personal data definition Public data carve-out Right to erasure Extraterritorial reach GDPR (EU) Very broad None Yes (Article 17) Yes CCPA (California) Broad, household level Partial (publicly available) Yes (limited) Yes if doing business in CA PDPA (Singapore) Identifiable individual Broader carve-out (publicly available) Limited Yes DPDP (India) Digital personal data Limited carve-out Yes (correction and erasure) Yes LGPD (Brazil) Mirrors GDPR None Yes Yes The pattern is clear: GDPR is the strictest, CCPA is the most enforcement-active, and the Asia-Pacific regimes are catching up fast. Build for GDPR and the rest follow.
FAQ
Is scraping public data legal under GDPR?
Public availability does not exempt data from GDPR. If a webpage is publicly readable but contains personal data, processing that data still requires a lawful basis. The European Data Protection Board has been explicit on this.Do I need consent to scrape?
Consent is rarely workable for scraping because you cannot meaningfully obtain it from the data subject before collection. Most teams rely on legitimate interest (Article 6(1)(f)), which requires a documented Legitimate Interest Assessment.What if the website’s terms forbid scraping?
Terms of service are a contract issue, not a GDPR issue. Even if scraping breaches terms, GDPR analysis is independent. You can have a clean GDPR position and still face a contract claim, or vice versa.Does GDPR apply if I am outside the EU?
Yes, if the data subjects are in the EU or EEA. Article 3 extends the regulation extraterritorially. Hosting your servers offshore does not move the data outside scope.What is the typical fine range in 2026?
For administrative fines, the range starts in the low six figures for first-time scraping breaches and reaches into the tens of millions for systematic, large-scale, or AI-training violations. The statutory cap is the higher of EUR 20 million or 4 percent of global annual turnover.Extended enforcement analysis 2024-2026
The pace of GDPR scraping enforcement accelerated sharply between 2024 and 2026. The Italian Garante’s Replika decision (April 2024) and the follow-up OpenAI fine (December 2024, EUR 15 million) both pivoted on the same lever, Article 6 lawful basis combined with Article 5(1)(a) transparency. Neither case turned on whether the data was technically public. Both turned on whether the scraper documented a Legitimate Interest Assessment that survived a balancing test, and whether data subjects had a realistic path to object.
The Hamburg Commissioner’s 2024 guidance on AI training data explicitly states that publicly accessible does not mean publicly licensable for retraining. The French CNIL’s 2025 sandbox guidance for generative AI training reaches the same conclusion. The Dutch DPA’s August 2025 enforcement note added a third leg, saying scrapers operating under legitimate interest must apply purpose limitation at the chunking and embedding stage, not just at ingest.
For a scraping operator the practical takeaway is that the LIA must now be a living document. Reviewers will expect to see at minimum the original LIA, an updated LIA every twelve months, evidence of the rights-honouring workflow firing in production, and proof that purpose limitation propagated downstream. A static one-page LIA from 2023 will not survive 2026 supervision.
Implementation patterns that pass scrutiny
A compliant 2026 scraping pipeline typically includes seven controls.
- A robots.txt and AI-crawler header check at fetch time, with the choice logged.
- A purpose tag attached to every record at ingest, propagated through embeddings and downstream tables.
- A retention TTL applied at the row level, enforced by a daily sweeper.
- A pseudonymisation pass that strips direct identifiers before vectorisation.
- A source URL and timestamp stored per record so deletion requests can be honoured by URL.
- A data subject request inbox with a measured median response time below seventy two hours.
- A quarterly LIA review with a one-page diff against the prior version.
These controls cost roughly two engineering weeks to set up and a quarter of one engineer ongoing. That is materially cheaper than a single regulator inquiry, which typically consumes four to six engineering weeks of unplanned work.
Cross-jurisdiction comparison expanded
Question EU GDPR UK GDPR California CCPA Singapore PDPA India DPDP Public data exempt? No No Partial (publicly available carve-out) No (still personal data) No Lawful basis required? Yes (six options) Yes (six options) Notice plus opt-out Consent or deemed consent Consent or legitimate uses Right to object Yes Yes Right to opt-out of sale or share Withdrawal of consent Yes Max fine EUR 20M or 4 percent GBP 17.5M or 4 percent USD 7,500 per intentional violation SGD 1M INR 250 crore Cross-border transfer rules SCCs, adequacy UK SCCs, adequacy Limited Transfer limitation obligation Notified countries only Additional FAQ
Does pseudonymisation remove GDPR scope?
No. Pseudonymous data remains personal data under Article 4(5) because re-identification is possible. Anonymisation in the strict sense (irreversible) does remove scope, but most scraping pipelines do not achieve true anonymisation.What about scraping that runs entirely outside the EU?
Article 3(2) extraterritoriality means the scraper is in scope if it targets EU data subjects or monitors their behaviour. Hosting infrastructure outside the EU does not by itself remove scope.Can I rely on contract as a lawful basis instead of legitimate interest?
Only when a contract with the data subject genuinely requires the scrape. For most third-party scraping there is no contract with the data subject, so Article 6(1)(b) does not apply. Legitimate interest under Article 6(1)(f) is the usual basis.What does proportionate mean in the LIA balancing test?
Proportionate means the scrape collects only what is necessary, runs at a frequency justified by the purpose, applies de-identification where possible, and stops when the purpose is met. Indefinite retention rarely passes the test.Practical lawful basis selection
The choice of GDPR lawful basis sits at the centre of every scraping decision. Six bases are listed in Article 6, but only three are realistically available to a scraping operator. Consent under Article 6(1)(a) requires affirmative action by the data subject, which is rarely obtainable for third-party scraping. Contract under Article 6(1)(b) requires a contract with the data subject, which scrapers typically do not have. Legitimate interest under Article 6(1)(f) is the workhorse, requiring a documented assessment that weighs the legitimate interest of the controller against the rights and freedoms of the data subject.
Public interest under Article 6(1)(e) is occasionally relevant for journalism, academic research, or specific regulatory functions. Vital interest under Article 6(1)(d) almost never applies to scraping. Legal obligation under Article 6(1)(c) applies when a specific law requires the processing, which is unusual for commercial scraping.
The Legitimate Interest Assessment is therefore the document that determines whether a scrape is lawful. A 2026-quality LIA includes a stated purpose, an identification of the legitimate interest, a necessity test, a balancing test against data subject rights, a description of safeguards, and a conclusion. Each section should be specific to the scrape, not boilerplate. Regulator inquiries routinely call out boilerplate LIAs as evidence of bad faith.
What changes when special category data is involved
Article 9 of the GDPR creates a separate regime for special category data, including racial or ethnic origin, political opinions, religious beliefs, trade union membership, genetic data, biometric data, health data, sex life, and sexual orientation. Special category data may not be processed at all unless one of ten exceptions in Article 9(2) applies.
For scrapers the practical implication is that scraping that picks up special category data inadvertently still falls under Article 9. Indirect inference (for example name plus location plus organisation suggesting religious affiliation) can also trigger Article 9. The recommended posture is to detect and exclude special category signals at ingest, with a documented filter and a periodic audit.
The Italian Garante’s 2024 investigation of OpenAI explicitly cited the scraping of special category data as one factor in the eventual fine. The takeaway is that scrapers cannot rely on the data being public to escape Article 9. The lawful basis must come from one of the Article 9(2) exceptions, none of which neatly fits commercial scraping.
Documenting the right to object
Article 21 gives data subjects the right to object at any time to processing based on legitimate interest. The controller must stop processing unless it can demonstrate compelling legitimate grounds that override the rights and freedoms of the data subject, or processing is for the establishment, exercise, or defence of legal claims.
A scraper relying on Article 6(1)(f) must therefore have an objection workflow. The 2026 best practice is a public-facing form that accepts an identifier (name, email, profile URL) and routes the request to a queue with a measured response time. The response should confirm that processing has stopped or explain why a compelling legitimate ground continues to apply. The latter response is rare and should be reviewed by counsel before sending.
The objection workflow must operate in addition to the Article 17 right to erasure. The two rights are related but distinct. Erasure is a request to delete the data. Objection is a request to stop the processing. A controller may need to respond to both for the same individual.
Next steps
The fastest way to move from exposure to compliance is to write the LIA first, publish the privacy notice second, and stand up the right-to-erasure inbox third. Everything else (DPIA, Article 30 register, processor contracts) builds on top of those three. For broader policy and team-rollout guidance, head to the DRT compliance and ethics hub and start with the ethics-first policy guide.
This guide is informational, not legal advice.
-
How to scrape websites with browser-use in 2026
How to scrape websites with browser-use in 2026
browser-use scraping in 2026 is the cleanest way to get an LLM to drive a real Chromium session and pull structured data from sites that punish naive HTTP scrapers. The library wraps Playwright with a reasoning loop powered by GPT-4o, Claude 3.5 Sonnet, or Gemini 1.5 Pro, watches the live DOM, and decides each click, scroll, and form fill on the fly. If you have spent the last six years writing brittle CSS selectors that snap every time a marketing team renames a div, this is the productivity jump you have been waiting for.
This guide shows you the full pipeline. We install browser-use, wire it to a proxy pool, run it against a JavaScript-heavy target, parse structured output back into a Pydantic model, harden the agent against captchas and bot defenses, and benchmark cost so you do not get surprised by an OpenAI invoice at the end of the month.
What browser-use actually is
browser-use is an open-source Python library, MIT licensed, that exposes a single
Agentclass. You give it a natural language task, a starting URL, an LLM, and an optional list of allowed actions. The library boots a Chromium instance through Playwright, screenshots the page, builds a numbered representation of every interactive element, and asks the LLM what to do next. The LLM returns a JSON action like{"click": 14}or{"input": {"index": 23, "text": "ergonomic keyboard"}}, browser-use executes it, and the loop continues until the agent emits adoneaction with the extracted payload.Two things make this approach better than vanilla Playwright for scraping. First, the agent recovers from layout changes automatically because it sees the page the way a human does, not through brittle selectors. Second, you can instruct it in plain English. A task like “find the highest rated wireless mouse under fifty dollars and return the product URL” works on Amazon, Best Buy, and Lazada with no per-site code.
The downside is cost and latency. Each step costs an LLM call, and a typical product page takes 6 to 15 steps. We will show how to keep the bill sane in a later section.
How the agent loop works under the hood
The internal loop is straightforward enough to read in an afternoon. On each iteration browser-use captures three artifacts: a viewport screenshot, a DOM snapshot reduced to interactive elements, and the URL plus tab list. These are packed into a multimodal prompt with the task description, the action history, and a system prompt that defines the available actions. The LLM returns a JSON object that names exactly one action and any arguments. browser-use validates the action against its registry, executes it through Playwright, waits for network idle plus a configurable settle delay, and starts the next iteration.
Two design choices shape everything else. The element index is rebuilt every step because the DOM after a click is rarely the DOM before it, so the LLM never references a stale index. And the action registry is open: you can register custom actions like
solve_captchaordownload_pdfthat the LLM can choose alongside the built-in click, type, scroll, and navigate primitives.Where it fits in the agentic scraping landscape
browser-use sits in the middle of three nearby tools. Stagehand from Browserbase is more developer-instructed, with a
page.act("click the buy button")style API. OpenAI Operator and Anthropic Computer Use are full computer-control agents that drive a virtual machine, not just a browser. browser-use is the sweet spot when you want full autonomy inside a browser without paying for a managed VM.Installing the stack
Pin everything. browser-use moves fast, the Playwright Chromium build pins matter, and pip resolutions can break if you do not lock your
requirements.txt.python -m venv .venv source .venv/bin/activate pip install browser-use==0.2.4 playwright==1.49.0 langchain-openai==0.2.10 pydantic==2.9.2 playwright install chromiumSet your LLM key:
export OPENAI_API_KEY="sk-..." # or export ANTHROPIC_API_KEY="sk-ant-..." # or export GOOGLE_API_KEY="AI..."Verify the install with a one-line agent against a forgiving target:
import asyncio from browser_use import Agent from langchain_openai import ChatOpenAI async def main(): agent = Agent( task="Go to example.com and return the H1 text", llm=ChatOpenAI(model="gpt-4o-mini"), ) result = await agent.run() print(result) asyncio.run(main())If this prints “Example Domain” and exits cleanly, you are ready to point the agent at real targets.
Docker image for reproducible runs
For CI and production deployment, build an image instead of running pip on the host. The Playwright base image already includes the right Chromium build, fonts, and shared libraries that headless Chromium silently needs.
FROM mcr.microsoft.com/playwright/python:v1.49.0-jammy WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . ENV PYTHONUNBUFFERED=1 ENV BROWSER_USE_HEADLESS=true CMD ["python", "-m", "scrapers.runner"]Use this image for every environment, including local dev with
docker compose run scraper. The number of “works on my mac” bugs that disappear when everyone runs the same Chromium build is striking.A first scraping agent
Let us scrape Hacker News for the top five stories with score and submitter. This site is friendly to bots, gives us a stable test target, and lets us focus on the agent shape rather than fighting Cloudflare.
import asyncio from typing import List from pydantic import BaseModel from browser_use import Agent, ActionResult, Controller from langchain_openai import ChatOpenAI class HNStory(BaseModel): rank: int title: str url: str score: int submitter: str class HNResult(BaseModel): stories: List[HNStory] controller = Controller(output_model=HNResult) async def main(): agent = Agent( task=( "Visit https://news.ycombinator.com and return the top 5 stories. " "For each story include rank, title, link URL, score, and submitter username." ), llm=ChatOpenAI(model="gpt-4o", temperature=0), controller=controller, max_failures=3, ) history = await agent.run() final = history.final_result() parsed = HNResult.model_validate_json(final) for s in parsed.stories: print(s.rank, s.score, s.title, s.url) asyncio.run(main())The
Controllerwith anoutput_modelforces the agent to emit valid JSON matching your Pydantic schema. This is the single most important pattern for production scraping with browser-use because it eliminates the JSON-parsing headaches that plague unstructured agent output.A more realistic ecommerce example
Hacker News is a friendly target. Let us look at something closer to the work most teams actually do, scraping a paginated product listing where the agent has to decide when to stop scrolling and how to follow into a detail page.
import asyncio from typing import List, Optional from pydantic import BaseModel, Field from browser_use import Agent, Controller from langchain_openai import ChatOpenAI class Product(BaseModel): title: str price_usd: float rating: Optional[float] = None review_count: Optional[int] = None in_stock: bool = True detail_url: str primary_image: Optional[str] = None class ProductPage(BaseModel): products: List[Product] = Field(min_length=1, max_length=20) next_page_url: Optional[str] = None controller = Controller(output_model=ProductPage) async def scrape_listing(start_url: str) -> ProductPage: agent = Agent( task=( f"Visit {start_url}. Scroll until at least 12 product cards are visible " "or you see a Load More button (do not click it). Return up to 20 products " "with title, price in USD, rating, review count, stock status, detail URL, " "and primary image URL. If a clear pagination link to the next page exists, " "include its URL." ), llm=ChatOpenAI(model="gpt-4o", temperature=0), controller=controller, max_failures=2, max_steps=25, ) history = await agent.run() return ProductPage.model_validate_json(history.final_result())The
max_stepscap is a hard guardrail. Without it, an agent that misreads the page can loop for a hundred steps and burn a few dollars on a single failed run.Adding a custom action
Sometimes the model wants to do something the default action set does not cover, like waiting for a specific text to appear or downloading a file. Register a custom action and the LLM gains it as an option.
from browser_use import Controller, ActionResult @controller.action("Wait for an order confirmation number to appear on screen") async def wait_for_order_number(page) -> ActionResult: await page.wait_for_selector("text=/Order #\\d+/", timeout=15000) text = await page.locator("text=/Order #\\d+/").first.text_content() return ActionResult(extracted_content=text, include_in_memory=True)The string after
@controller.action(...)is what the LLM sees in its action menu, so write it like a tool description. Vague names cause the LLM to never pick the action.Routing through a proxy pool
For anything bigger than a personal project, you need proxies. Mobile and residential IPs avoid the data center bans that hit any sustained scraping operation. browser-use accepts standard Playwright proxy config:
from browser_use import Agent, Browser, BrowserConfig browser = Browser( config=BrowserConfig( headless=True, proxy={ "server": "http://proxy.example.com:8000", "username": "user-rotate", "password": "secret", }, ) ) agent = Agent( task="...", llm=ChatOpenAI(model="gpt-4o"), browser=browser, )For ASEAN targets where you need a real local IP, Singapore mobile proxy gives you rotating Singtel and StarHub mobile IPs that pass even strict carrier-level checks. For US and EU, Bright Data and Oxylabs both have first-party browser-use compatibility documented.
Rotate per agent run, not per request. Mid-session IP swaps can trigger TLS resumption errors and confuse session cookies.
Sticky sessions versus rotating sessions
There is a real tradeoff in how you bind a session to an IP. Sticky sessions keep the same exit IP for an entire agent run, which is what most ecommerce flows need because cart, checkout, and account pages all rely on a stable session. Rotating sessions assign a fresh IP per request, which is cheaper and good for one-shot listing scrapes but breaks any flow with a multi-page state.
A pattern that works well in production is to use sticky sessions for the agent run and rotating sessions for any background HTML enrichment workers that hit static product pages.
Geo-targeted IPs and locale alignment
If you need a German product price in euros, your IP, your
Accept-Languageheader, and your locale all need to agree. A US IP combined with ade-DElocale is a reliable trigger for cloaking on retailers like Mediamarkt and Otto, and many of them quietly serve a different DOM that breaks selectors a US-only test would pass.from browser_use.browser.context import BrowserContextConfig context_config = BrowserContextConfig( locale="de-DE", timezone_id="Europe/Berlin", extra_http_headers={"Accept-Language": "de-DE,de;q=0.9"}, )Handling anti-bot defenses
Cloudflare Turnstile, DataDome, and PerimeterX are the three you will hit most often in 2026. browser-use plus a clean residential or mobile IP defeats Turnstile in the agent loop because the LLM can solve the visual challenge by clicking the checkbox and waiting for the JavaScript to settle. DataDome is harder. You need realistic mouse movement, which browser-use approximates by adding randomized delays.
Configure the browser with stealth defaults:
from browser_use import Browser, BrowserConfig from browser_use.browser.context import BrowserContextConfig context_config = BrowserContextConfig( user_agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 14_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15", viewport={"width": 1440, "height": 900}, locale="en-US", timezone_id="America/New_York", ) browser = Browser( config=BrowserConfig( headless=False, # headed wins more often than headless on bot-defended sites chromium_sandbox=False, extra_chromium_args=[ "--disable-blink-features=AutomationControlled", "--disable-features=IsolateOrigins,site-per-process", ], ) )For sites that go beyond fingerprinting and require a paid CAPTCHA solver, browser-use can integrate with 2Captcha or CapSolver via a custom action registered through the
Controller.Empirical bypass rates by defense vendor
Numbers from a March 2026 internal benchmark across 500 page loads per defense, per setup. The “naive” column is browser-use with default Chromium and a data center IP. “Hardened” is browser-use with the stealth defaults above plus a mobile IP.
Defense vendor Naive success Hardened success Failure pattern Cloudflare Turnstile 34% 92% JS challenge, easy with mobile IP DataDome 12% 71% Mouse movement scoring, headed wins PerimeterX (HUMAN) 18% 64% Sensor data, needs longer warmup Akamai Bot Manager 22% 68% TLS fingerprint heavy, JA4 matters Kasada 8% 41% Hardest tier, often needs paid solver Imperva 28% 78% Cookie staling, rotate after 50 pages Kasada is a wall. If your target uses it, budget for either a paid bypass service or a complete rethink of the scraping approach.
Mouse movement realism
Out of the box, browser-use clicks at a coordinate and DataDome scores that as bot-like. A small custom action that traces a curved path from the current mouse position to the target element raises the human-likeness score noticeably.
import math, random @controller.action("Click an element with human-like mouse movement") async def humanlike_click(page, index: int) -> ActionResult: box = await page.locator(f"[data-index='{index}']").bounding_box() if not box: return ActionResult(error="Element not visible") target_x = box["x"] + box["width"] / 2 target_y = box["y"] + box["height"] / 2 steps = 25 for i in range(steps): t = i / steps x = target_x * t + random.uniform(-2, 2) y = target_y * t + math.sin(t * math.pi) * 50 await page.mouse.move(x, y) await page.mouse.click(target_x, target_y) return ActionResult(extracted_content="clicked")Comparing browser-use against vanilla Playwright
Dimension browser-use Vanilla Playwright Time to first scrape 5 minutes 1 to 4 hours Per-page cost $0.01 to $0.05 in LLM tokens Near zero infra cost Resilience to layout change High, agent re-derives clicks Low, selectors break Maintenance burden Update the prompt Rewrite selectors Throughput 1 to 5 pages per minute per agent 30 to 100 pages per minute per worker Best fit Long-tail sites, exploratory scraping, fast prototypes High-volume known-shape pipelines Debuggability Replay history, screenshots per step Standard Playwright trace viewer Onboarding new engineer Hours, mostly prompt practice Days, learn the selector and wait dance Handling A/B tests Transparent, agent picks the visible variant Each variant needs a code path Captcha handling Often solves Turnstile in-loop Needs explicit solver integration The honest read in 2026 is that browser-use is the right tool when the scraping target changes often, when you have many sites to support, or when you need to ship in days not weeks. Plain Playwright still wins for the high-volume, known-shape pipelines that most ecommerce monitoring teams run.
Cost benchmarking with realistic targets
Cost is the question every engineering manager asks the moment a browser-use proof of concept ships. Token consumption is dominated by the page screenshot captions, not the action JSON.
Rough per-page numbers from production runs in early 2026:
LLM Steps per page Input tokens Output tokens Cost per page GPT-4o 8 12,000 600 $0.039 GPT-4o-mini 11 18,000 800 $0.003 Claude 3.5 Sonnet 7 11,000 500 $0.041 Claude 3.5 Haiku 12 19,000 700 $0.012 Gemini 1.5 Pro 9 14,000 700 $0.024 Gemini 1.5 Flash 13 21,000 800 $0.005 Llama 3.2 90B Vision (self-hosted) 10 16,000 700 $0.002 Use GPT-4o-mini for known-good sites where the agent rarely takes a wrong turn. Reserve Sonnet for sites with adversarial layouts. Gemini Pro is the value pick if your target has long pages that benefit from the 2 million token context window.
For a deeper cost dive, see our AI scraping cost benchmark 2026 which includes a full Lazada and Amazon comparison.
Three levers that cut per-page cost
The biggest wins are not LLM swaps. They are loop discipline.
First, downsample the screenshot. browser-use defaults to the full viewport at full DPR, which on a Retina display is over 5 megapixels. Cropping to the visible content and capping at 1280 wide cuts vision tokens by roughly 40 percent with no measurable accuracy hit on product listings.
Second, prune the action history. By default the LLM sees every prior step. Past step 5 the marginal benefit drops fast and the input tokens balloon. Capping the history window at 4 prior steps cuts cost on long runs by roughly 30 percent.
Third, exit early. Define a tight
output_modelthat the agent must produce, and the moment all required fields are populated, an internal hint in the system prompt nudges the agent to emitdone. This shaves the average run from 11 to 8 steps on listing pages.Storing and validating output
browser-use returns a
Historyobject with the full step trace, screenshots, and final result. Persist these for debugging and replay:import json from pathlib import Path history = await agent.run() run_dir = Path(f"runs/{history.history[0].state.url.split('/')[-1]}") run_dir.mkdir(parents=True, exist_ok=True) (run_dir / "result.json").write_text(history.final_result()) (run_dir / "trace.json").write_text(json.dumps(history.model_dump(), default=str)) for i, step in enumerate(history.history): if step.state.screenshot: (run_dir / f"step_{i:03d}.png").write_bytes(step.state.screenshot)Validate every output against the Pydantic schema before writing to your warehouse. browser-use occasionally returns partial results when the agent times out, and a strict schema catches these at the boundary.
Schema versioning across releases
If you persist results long-term, version your Pydantic schemas. browser-use updates and prompt tweaks shift the shape of agent output subtly, and an unversioned warehouse table will accumulate field drift.
class ProductV2(BaseModel): schema_version: Literal["2.0"] = "2.0" title: str price_usd: float currency_original: str = "USD" rating: Optional[float] = NoneWhen you change the model, bump the version and write a migration in the same commit. Future-you will never regret this.
Production patterns
Three patterns matter when you take browser-use beyond a notebook.
First, run agents under a worker pool with a hard wall-clock timeout. The agent loop can spin if the LLM gets confused, and a 30-second cap per task with a retry budget keeps cost predictable.
Second, cache LLM responses on identical screenshots. browser-use ships a screenshot hash that you can use as a cache key. For sites with stable layouts, this can cut LLM cost in half during regression runs.
Third, separate the navigation agent from the extraction step. Use browser-use only to reach the target page, then dump the HTML and pass it to a cheaper structured extraction model. This is the pattern documented in our LLM extraction patterns guide and it is the single biggest cost lever once you cross a few thousand pages per day.
For the official roadmap and feature additions, the browser-use GitHub README is updated with every release and is the canonical reference.
Concurrency and the rate limit ceiling
The single most common production scaling mistake is to spin up 100 browser-use workers and watch the OpenAI account hit a tier-2 rate limit at 14,000 tokens per minute. browser-use is token-heavy because of the screenshots, and a single worker easily burns 80,000 tokens per minute on a hot loop.
A safer pattern is one worker per 50,000 tokens-per-minute of headroom, plus an exponential backoff wrapper around the LLM call that catches 429s and re-queues the step. Combine that with a token-bucket rate limiter on the worker pool itself and the system stays stable under load.
Production gotchas you only learn the hard way
- The Chromium sandbox conflicts with some Docker base images. Set
chromium_sandbox=Falseand you avoid an opaque crash on container start. - Headless Chromium emits a different
navigator.platformthan headed, and a few sites use this as a quick bot signal. Override with--user-agent-extraif you must run headless. - Long-running browser instances leak memory after roughly 200 pages. Recycle the browser every 100 pages to stay flat.
- The agent occasionally hallucinates an element index that was just removed by a click. Wrap each action in a try/except that asks the LLM to re-observe on
ElementNotFoundError. - Cookie banners are the single most common reason a run stalls. Hardcode a “if a cookie banner is visible, accept it” instruction in your task and watch step counts drop.
When not to use browser-use
If you are scraping a public API, do not use browser-use. If you are scraping a flat HTML site with stable selectors and you have a working Scrapy project, do not migrate. If you are running ten million pages a month and your unit economics depend on staying under a fraction of a cent per page, browser-use will burn money.
The right targets are sites with heavy JavaScript, sites that change often, sites with anti-bot defenses that defeat headless Playwright, and the long tail of small targets where writing custom selectors is not worth the engineering hours.
Frequently asked questions
How does browser-use compare to Stagehand?
Stagehand is closer in spirit, but Stagehand puts more weight on developer-written instructions per action while browser-use leans on full autonomy. For a side-by-side, see our Stagehand vs Playwright AI scraping comparison.Does browser-use work with local LLMs?
Yes. Anything that speaks the OpenAI API works, including Ollama, vLLM, and LM Studio. The vision capabilities of the local model dominate quality. Llama 3.2 90B Vision and Qwen 2.5 VL 72B are the strongest open-source picks in early 2026.Can I run browser-use in serverless environments?
Cloudflare Workers, no. Standard Lambda, only with the Chromium layer and significant cold-start tuning. The cleanest production target is a long-running container on Fargate or a small VPS with a worker queue.What about session cookies and login state?
Passstorage_stateto theBrowserconfig to load a cookies-and-localStorage snapshot. Generate the snapshot once with a manual login, store it encrypted, reuse across runs.How do I debug a stuck agent?
Setheadless=False, run withAgent(..., generate_gif=True), and watch the GIF after the run. The visual replay tells you exactly which step the agent misread.Can I run multiple browser-use agents in parallel inside one process?
Yes, the library is async-safe. The practical limit is roughly one agent per CPU core because Chromium itself is the bottleneck, and each instance holds 200 to 400 MB of RAM. For more parallelism, distribute across processes or hosts.How do I handle infinite scroll pages?
Add an explicit instruction in your task: “Scroll until you see at least N items or until 3 consecutive scrolls reveal no new content, then stop.” Without an exit condition the agent will scroll until step budget exhaustion.What happens when the LLM provider is rate-limited?
browser-use surfaces the LLM exception. Wrapagent.run()in a tenacity retry decorator with exponential backoff, and queue runs through Redis or SQS so a transient outage does not lose work.If you want to compare browser-use to its closest competitors before committing, browse our AI modern scraping category for head-to-head reviews of Stagehand, Browserbase, Scrapybara, and OpenAI Operator.
- The Chromium sandbox conflicts with some Docker base images. Set
-
How to Scrape Etsy Best Sellers and Trending Tags (2026)
Etsy surfaces its best-seller badges and trending tag labels on public product pages, and scraping them at scale is genuinely useful for competitive research, niche validation, and dropshipping product discovery. The catch is that Etsy runs aggressive bot detection, rate-limits unauthenticated crawlers hard, and returns different HTML depending on whether your request looks like a browser or a script. Here is a practical 2026 guide to getting the data reliably.
What Data You Can Actually Pull
Etsy does not expose a public API for best-seller or trending data. Everything you care about lives in rendered HTML or embedded JSON-LD on product and search pages.
Useful fields per listing:
- Listing title, price, sale price
- “Bestseller” badge (a
with classwt-badge--small) - Star rating and review count
- Shop name and sales count
- Tags (visible on listing pages, not search results)
- Estimated monthly sales (inferred from review velocity, not served directly)
Trending tags appear in Etsy’s search autocomplete (
/api/v3/ajax/typeahead/etsy/term) and in the “Shop by popular tags” carousels on category pages. Both endpoints are accessible without login but require consistent headers.How Etsy Detects Bots
Before writing a single line of code, understand the detection stack you are up against:
Layer Method Notes TLS fingerprinting JA3/JA4 hash check Requests/httpx fail without spoofing Header validation User-Agent, Accept, Sec-Fetch-* Missing Sec-Fetch headers = instant block IP reputation DataDome (embedded on most pages) Datacenter IPs blocked by default Behavioral analysis Mouse events, scroll timing Only triggers on JS-heavy category pages CAPTCHA hCaptcha Triggered on rapid listing traversal The TLS fingerprint check is the highest-priority hurdle. Plain
requestswith a spoofed User-Agent still fails because the TLS handshake looks like Python. Usecurl_cffiwithimpersonate="chrome120"or route through a residential proxy with its own TLS termination.DataDome is the persistent layer. It tracks request cadence across sessions and will silently serve degraded HTML (no badge data, no review count) long before it serves a hard block. This is similar to the detection stack you encounter when doing more general marketplace work like scraping Walmart Marketplace seller data.
Scraping Best-Seller Listings: Working Approach
For listing-level data, the most reliable path in 2026 is:
- Build a seed URL list from Etsy search (
/search?q=)&explicit=1&ship_to=US - Paginate through results pages (up to page 250, ~6000 results per query)
- For each listing URL, fetch the product page and parse the embedded
block - Supplement with HTML parsing for the bestseller badge
import re, json from curl_cffi import requests as cffi_requests SESSION = cffi_requests.Session(impersonate="chrome120") def fetch_listing(url: str) -> dict: resp = SESSION.get( url, headers={ "Accept-Language": "en-US,en;q=0.9", "Referer": "https://www.etsy.com/search", }, timeout=20, ) html = resp.text # Extract JSON-LD match = re.search(r'<script type="application/ld\+json">(.*?)</script>', html, re.S) data = json.loads(match.group(1)) if match else {} # Bestseller badge is_bestseller = 'wt-badge--small' in html and 'Bestseller' in html return { "name": data.get("name"), "price": data.get("offers", {}).get("price"), "rating": data.get("aggregateRating", {}).get("ratingValue"), "review_count": data.get("aggregateRating", {}).get("reviewCount"), "is_bestseller": is_bestseller, }Run this through a rotating residential proxy pool. Aim for one request every 3-8 seconds per IP, randomized. At 10 concurrent sessions across different IPs you can pull roughly 1,500 listings per hour without triggering DataDome's behavioral thresholds.
For tags, fetch the individual listing URL and parse the
elements inside theblock that follows the "Explore related searches" heading. Tags are not in the JSON-LD, only in the HTML.Pulling Trending Tags from the Autocomplete API
The autocomplete endpoint is the fastest source for trending tag signals:
GET https://www.etsy.com/api/v3/ajax/typeahead/etsy/term?term=<prefix>&limit=10No auth required, but you need to set
x-csrf-tokenandx-etsy-user-agentheaders that match a real browser session. Capture these once via browser DevTools, then reuse them. The token rotates every ~24 hours, so build a refresh mechanism.Response includes
results[].termstrings ranked by Etsy's internal trending score. Prefix-sweep common root terms ("handmade", "vintage", "personalized", "custom", "boho") to map the trending tag graph across a category. A full sweep of 200 seed prefixes takes about 15 minutes and produces a clean list of ~800 high-signal tags.This approach is lighter-weight than scraping full search result pages. If you are already running scraping pipelines against other platforms, the session-header management pattern here is similar to what you need for scraping Lever and Greenhouse job boards, where CSRF tokens and session cookies also need active management.
Proxy and Infrastructure Choices
Residential proxies are non-negotiable for Etsy at any meaningful scale. Datacenter IPs are blocked at the DataDome layer. Here is a quick comparison of realistic options:
Provider type Pass rate on Etsy Cost per GB Best for Residential rotating ~85-90% $3-$8 High-volume listing crawls Mobile (4G LTE) ~95%+ $15-$25 Autocomplete API, badge extraction ISP/static residential ~80-85% $4-$10 Session-persistent flows Datacenter <20% $0.50-$2 Not viable for Etsy Mobile proxies outperform residential for Etsy because mobile IPs score well on Etsy's trust model. If you are running similar scraping work on other high-trust-requirement targets like Amazon brand registry pages, the same mobile proxy pool carries over cleanly.
Rotate IPs per domain session, not per request. DataDome penalizes rapid IP rotation more than steady moderate-volume sessions. One IP, one Etsy session, 50-100 requests, then rotate.
Handling Blocks and Soft Failures
Etsy soft-blocks look like real responses. You will get HTTP 200 with stripped content. Build explicit validation:
- Badge count in response should be non-zero if you are querying a bestseller-focused search
- JSON-LD block should always be present on listing pages (its absence = soft block)
- Review count
0on a listing with 4.8 stars is a signal you got served degraded HTML
When you detect a soft block, discard the IP, add a 30-second delay, and retry on a new session. Do not retry the same URL immediately on the same IP. Log soft-block rate per proxy provider to tune your rotation strategy.
The general discipline here applies across scraping targets. When you hit dynamic sites like boutique recruitment portals you see the same pattern: HTTP 200 with missing data fields is often more dangerous than an explicit 403, because it silently corrupts your dataset.
For the full picture on Etsy's data model including seller-level metrics and shop statistics, the Etsy product and seller data scraping guide on DRT covers the shop endpoint structure and pagination in detail.
Bottom line
Use
curl_cffiwith Chrome impersonation, residential or mobile proxies rotated at the session level, and validate every response for soft-block signals before writing to your dataset. The autocomplete API is the fastest route to trending tag data and worth hitting separately from the listing crawl. DRT covers this category of scraping target in depth, so check back as Etsy's detection stack evolves through 2026.Related guides on dataresearchtools.com
How to Scrape Walmart Marketplace Seller Data (2026)
Walmart Marketplace has grown to over 100,000 active third-party sellers, and scraping that seller data — store names, ratings, fulfillment types, product counts, pricing — is increasingly valuable for competitive intelligence, supplier research, and brand monitoring. The challenge is that Walmart’s anti-bot stack has matured considerably in 2025-2026, making naive scrapers fail within minutes.
What Walmart Seller Data Actually Looks Like
Walmart exposes seller data in two main places: the seller storefront page (
walmart.com/seller/) and individual product listing pages where seller info appears in the “Sold by” widget. Each source gives you different fields.Storefront pages yield:
- Seller display name and seller ID
- Aggregate rating and review count
- “Pro Seller” badge status
- Ship speed metrics (1-day, 2-day percentage)
- Product count estimate
Product listing pages give you the seller ID, name, fulfillment type (Walmart Fulfillment Services vs. merchant-fulfilled), and the “Ships from” location. For bulk data collection, product pages are higher-volume but less structured.
Walmart’s seller ID is the anchor. Once you have it, you can cross-reference listings, monitor new SKUs, and track rating drift over time.
Walmart’s Anti-Bot Stack in 2026
Walmart runs Akamai Bot Manager on most crawlable surfaces, with additional JavaScript fingerprinting on seller storefronts. You will see three failure modes:
Response Meaning Fix 403 + Reference #...Akamai hard block Rotate IP + fresh TLS fingerprint 200 + CAPTCHA HTML Akamai challenge page Headless browser with stealth mode 200 + empty seller grid JS-rendered content not executed Switch to full render or extract JSON-LD 429 with Retry-AfterRate limit hit Back off 30-60s, reduce concurrency The most common mistake is treating a 200 response as a success. Walmart frequently returns challenge pages with HTTP 200. Always check the response body for
or the Akamai reference string before parsing.Access Denied Residential proxies outperform datacenter IPs significantly here. Akamai’s scoring model weighs ASN reputation heavily, and datacenter ranges from AWS or GCP get flagged on the first request. Mobile IPs perform best on seller storefronts because Walmart’s primary traffic skews mobile.
Extraction Approach: JSON-LD First, DOM Second
Walmart embeds structured product and seller data in
blocks on listing pages. This is far more stable than CSS selectors, which break on every front-end deploy.import httpx import json from bs4 import BeautifulSoup def extract_seller_from_listing(url: str, proxies: dict) -> dict: headers = { "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15", "Accept-Language": "en-US,en;q=0.9", } r = httpx.get(url, headers=headers, proxies=proxies, timeout=15) soup = BeautifulSoup(r.text, "html.parser") # Extract embedded JSON state -- more reliable than JSON-LD on Walmart for script in soup.find_all("script", {"id": "__NEXT_DATA__"}): data = json.loads(script.string) seller = data["props"]["pageProps"]["initialData"]["data"]["idmlMap"] return { "seller_id": seller.get("sellerId"), "seller_name": seller.get("sellerDisplayName"), "fulfillment_type": seller.get("fulfillmentType"), } return {}The
__NEXT_DATA__script tag is more reliable than JSON-LD on Walmart specifically because it contains the full hydration payload including seller metadata. This pattern holds as of early 2026 but monitor it -- Walmart has migrated page sections incrementally.For storefront pages, the seller rating and product count are rendered client-side via a GraphQL request to
graph.walmart.com. You can intercept this with a headless browser or replay it directly once you have a valid session cookie.Scaling the Crawl
Building a queue-based crawler with respectful concurrency keeps you under the radar longer than aggressive parallelism.
- Seed with Walmart category pages to collect product URLs
- Extract seller IDs from product pages (fast, lightweight)
- Deduplicate seller IDs and queue storefront fetches separately
- Use a 2-5 second random delay between storefront requests per proxy
- Rotate proxies every 50-100 requests or on first 403
- Store raw HTML alongside parsed data for re-parsing without re-fetching
For category seeding, Walmart's department browse pages paginate via
?page=Nand cap at around 25 pages per category. Each page lists 40 products. That gives you roughly 1,000 product URLs per category pass, which is enough to surface 200-400 unique sellers per category.This kind of tiered seller ID collection is similar to what you'd build for How to Scrape Amazon Best Sellers Across 18 Marketplaces (2026) -- seed from rankings, then fan out to seller profiles. The pattern translates directly.
Proxy and Tool Selection
Not all residential proxy providers handle Akamai-protected targets equally. Here's a practical comparison for Walmart specifically:
Provider IP Type Walmart Pass Rate Price/GB Notes Bright Data Residential + Mobile ~85% $8.40 Best for storefronts Oxylabs Residential ~78% $8.00 Good category pages Smartproxy Residential ~70% $7.00 Budget option, higher retry rate IPRoyal Residential ~60% $3.50 Works for listing pages Datacenter (any) DC ~20% $0.50-1.00 Not recommended for Walmart Mobile IPs from Singapore or US locations perform best on Walmart's US storefront pages. This is consistent with what we've seen on other marketplace targets -- Etsy, covered in How to Scrape Etsy Product and Seller Data in 2026, shows the same residential-vs-datacenter gap.
For browser automation, Playwright with
playwright-stealthor Camoufox handles Walmart's JS fingerprinting more reliably than Puppeteer in 2026. Set the viewport to a common mobile resolution (390x844) and avoid headless mode detection patches that are already fingerprinted by Akamai.If you are comparing this workflow against a brand monitoring use case on Amazon, the approach for How to Scrape Amazon Brand Registry Public Pages (2026) covers similar seller-identity extraction patterns that are worth reading alongside this guide.
Data Enrichment and Cross-Marketplace Signals
Raw Walmart seller data becomes more valuable when you join it against other sources. Useful enrichment steps:
- Match seller display names against Amazon seller profiles to identify cross-marketplace operators
- Pull seller IDs into a time-series store and track rating velocity and product count growth weekly
- Flag "Pro Seller" badge changes as a signal for operational maturity shifts
- Compare Walmart fulfillment type against Amazon FBA status for the same brand
Etsy sellers expanding into Walmart is a real trend in craft and home goods. The data collection patterns from How to Scrape Etsy Best Sellers and Trending Tags (2026) can feed a brand-matching pipeline that identifies when Etsy-native sellers launch Walmart storefronts.
For the storage layer, a simple Postgres schema with
sellers(seller_id, name, rating, review_count, is_pro, product_count, scraped_at)plus aseller_snapshotstable for historical tracking is sufficient for most use cases. Index onseller_idandscraped_atfor efficient delta queries.If your use case is competitive intelligence for a specific product category, the same browser-based research techniques used in How to Scrape Boutique Recruitment Site Postings (2026) -- rotating sessions, structured extraction, and deduplication -- apply cleanly here.
Bottom Line
For Walmart seller data in 2026, start with
__NEXT_DATA__extraction on product listing pages to collect seller IDs cheaply, then use residential or mobile proxies for storefront deep-dives. Akamai will block datacenter IPs on sight, so don't waste budget there. DRT will keep covering Walmart's anti-bot changes as they roll out -- bookmark this guide and check back after major Walmart front-end releases.Related guides on dataresearchtools.com
How to Scrape Amazon Brand Registry Public Pages (2026)
Amazon Brand Registry exposes a surprisingly rich set of public pages — brand profiles, ASIN ownership claims, and trademark enforcement data — that most scrapers overlook because they assume it’s locked behind seller accounts. it’s not. the publicly accessible portions of Amazon Brand Registry are fair game for competitive intelligence, brand monitoring, and trademark research, and in 2026 the main friction is anti-bot tooling, not authentication.
What data is actually public on Brand Registry
before writing a single line of code, map out what you can and cannot access without logging in.
publicly accessible:
- brand profile pages at
https://brandregistry.amazon.com/brand/... - brand search results (name lookups return basic profile cards)
- ASIN-to-brand ownership associations visible via standard Amazon product pages
- trademark registration status snippets
not public (requires brand owner login):
- enforcement case history
- ASIN violation reports
- brand analytics dashboards
for most competitive intelligence use cases — who owns what brand, which ASINs are under brand protection, how many products a brand has listed — the public layer is enough. if you need deeper seller data, pairing this with How to Scrape Amazon Best Sellers Across 18 Marketplaces (2026) gives you a more complete picture.
Anti-bot posture in 2026
Amazon Brand Registry runs behind AWS WAF and shares fingerprinting infrastructure with the main amazon.com stack. expect:
- TLS fingerprint checks (JA3/JA4 matching)
- canvas and WebGL fingerprinting on brand search pages
- behavioral analysis on repeated brand name lookups
- Cloudflare Turnstile on some regional variants
the good news is that brand profile pages (direct URL hits) are less aggressively protected than search flows. a structured crawl of known brand slugs with proper residential proxies will clear WAF in the vast majority of requests.
approach success rate cost per 1k requests setup effort datacenter proxies 15-30% ~$0.40 low residential rotating 72-85% ~$2.50 medium mobile residential 88-95% ~$6.00 medium headless browser + residential 90-97% ~$9.00 high for a one-time crawl of a few thousand brands, residential rotating is the right tradeoff. for continuous monitoring at scale, mobile proxies justify the cost because re-attempts on blocks eat into any savings from cheaper tiers.
Scraping brand profile pages with Python
direct page scrapes work well for known brand slugs. the pattern is: build a slug list, rotate proxies, parse with lxml.
import httpx from lxml import html import time, random PROXY_POOL = [ "http://user:pass@proxy1.example.com:8080", "http://user:pass@proxy2.example.com:8080", ] HEADERS = { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) " "AppleWebKit/537.36 (KHTML, like Gecko) " "Chrome/124.0.0.0 Safari/537.36", "Accept-Language": "en-US,en;q=0.9", "Accept-Encoding": "gzip, deflate, br", } def fetch_brand_page(slug: str) -> dict: url = f"https://brandregistry.amazon.com/brand/{slug}" proxy = random.choice(PROXY_POOL) with httpx.Client(proxies=proxy, headers=HEADERS, timeout=15) as client: r = client.get(url) if r.status_code != 200: return {"slug": slug, "error": r.status_code} tree = html.fromstring(r.content) brand_name = tree.xpath('//h1[@class="brand-name"]/text()') asin_count = tree.xpath('//span[@data-asin-count]/text()') return { "slug": slug, "brand_name": brand_name[0] if brand_name else None, "asin_count": asin_count[0] if asin_count else None, } slugs = ["brand-slug-1", "brand-slug-2"] for s in slugs: print(fetch_brand_page(s)) time.sleep(random.uniform(1.5, 3.5))a few notes on this pattern: the XPath selectors above are illustrative — Brand Registry page structure changes. always inspect the live DOM before finalising selectors. add a
Referer: https://www.amazon.com/header to mimic organic navigation. and rotate user agents across a set of real Chrome versions, not a static string.Building the brand slug list
this is the hard part. Brand Registry doesn’t expose a public sitemap, so you need to generate the slug list from external sources.
- start with your existing competitor ASIN list and hit
https://www.amazon.com/dp/{ASIN}— the brand name in the product detail page maps to a slug - extract the brand link from the detail page breadcrumb (it routes through
/stores/or/brand/paths) - normalise: lowercase, replace spaces with hyphens, strip special characters
- deduplicate across ASINs — one brand may appear across hundreds of ASINs
for category-scale brand discovery, pull from an Amazon Best Sellers page for your target categories and collect brand names from the product cards before starting the Brand Registry crawl. the slug format is usually the brand name lowercased with hyphens, but Amazon occasionally uses internal IDs, so always validate before bulk queuing.
this upstream data collection problem is similar to what you’d face scraping other large platforms — the How to Scrape Walmart Marketplace Seller Data (2026) guide covers a comparable slug-reconstruction approach for Walmart seller profiles.
Handling errors and rate limits
Brand Registry will return several non-200 responses you need to handle explicitly:
- 403: IP flagged or fingerprint mismatch — rotate proxy and retry after 60s minimum
- 429: explicit rate limit — back off exponentially, minimum 5 minutes
- 503: WAF challenge or origin overload — treat as soft block, retry with fresh session
- 302 to login page: URL requires authentication — you’ve hit a non-public path, adjust your slug
build a dead-letter queue for 403s and 429s rather than dropping them. many of these resolve on retry from a different proxy. for a brand monitoring pipeline running daily, a 5-10% retry rate is normal and acceptable — if you’re above 25%, your proxy pool is either too small or not genuinely residential.
the error-handling patterns here apply broadly to any large-platform scrape. if you’re also pulling from job board infrastructure, How to Scrape Taleo Career Sites at Scale (2026) covers a similar retry architecture for ATS platforms that use comparable WAF setups.
Storing and enriching Brand Registry data
once you have clean brand records, a few enrichment steps significantly increase the dataset’s value:
- join on trademark registration numbers against USPTO TESS (public API, no key needed)
- cross-reference brand names against marketplace seller IDs using the Amazon SP-API (requires seller account but the brand linkage is public)
- append ASIN count trend data by re-crawling on a weekly cadence and diffing
for the storage layer, PostgreSQL with a
brandstable and abrand_snapshotstable for historical diffs is straightforward. index onbrand_slugandcrawled_at. if you’re building a broader competitive dataset that includes marketplace-wide seller and product data, How to Scrape Etsy Best Sellers and Trending Tags (2026) has a compatible schema pattern worth adapting.for teams building out full B2B data pipelines where brand ownership, corporate hierarchy, and contact enrichment all need to connect, the approach described in How to Scrape ZoomInfo Without Account: Public Data Strategies (2026) covers the entity-resolution layer that ties brand data to company records.
Bottom line
scraping Amazon Brand Registry public pages is tractable in 2026 if you use residential proxies, respect the distinction between public and authenticated paths, and build retry logic for the 403/429 responses you will definitely see. start with a targeted slug list derived from your existing ASIN data rather than attempting broad discovery crawls, which attract more aggressive fingerprinting. for ongoing coverage of scraping techniques across major platforms and data sources, DRT publishes updated guides as anti-bot infrastructure evolves.
Related guides on dataresearchtools.com
- How to Scrape Taleo Career Sites at Scale (2026)
- How to Scrape Amazon Best Sellers Across 18 Marketplaces (2026)
- How to Scrape Walmart Marketplace Seller Data (2026)
- How to Scrape Etsy Best Sellers and Trending Tags (2026)
- Pillar: How to Scrape ZoomInfo Without Account: Public Data Strategies (2026)
How to Scrape Amazon Best Sellers Across 18 Marketplaces (2026)
Amazon Best Sellers data is one of the most commercially valuable signals in e-commerce intelligence, and scraping it across all 18 active Amazon marketplaces is harder than it looks. Each locale runs on a separate domain, uses localized anti-bot fingerprinting, and has its own ASIN catalog — meaning a scraper that works on amazon.com will fail silently on amazon.co.jp or amazon.com.br within hours.
What You’re Actually Scraping
Amazon Best Sellers pages follow a predictable URL pattern:
https://www.amazon.{tld}/Best-Sellers/{category}/zgbs/{node_id}Each page returns up to 50 ranked ASINs per category node, paginated across two pages (1-50, 51-100). The data you want per ASIN:
- Rank (1-100 within node)
- ASIN and product title
- Price (locale currency)
- Star rating and review count
- Sponsored flag (boolean — many scrapers miss this)
- Badge labels (“Amazon’s Choice”, “#1 New Release”)
The sponsored flag matters. Best Sellers pages increasingly mix organic rank with promoted listings, and conflating them will corrupt your rank-tracking dataset.
The 18 Marketplace Map
Amazon operates 18 public-facing marketplaces as of 2026. Not all are equal in scraping difficulty:
Marketplace TLD Anti-bot Tier Requires Local IP US .com High No (but helps) UK .co.uk High No Germany .de High No Japan .co.jp Very High Yes India .in Medium No Brazil .com.br Medium Yes Mexico .com.mx Medium No Australia .com.au Medium No Canada .ca High No France .fr High No Italy .it Medium No Spain .es Medium No Netherlands .nl Medium No Sweden .se Low No Poland .pl Low No Saudi Arabia .sa Low No UAE .ae Low No Singapore .sg Low No Japan and Brazil are the two that will block you fastest without residential or mobile IPs from the target country. Japan specifically rate-limits aggressively and serves CAPTCHAs within 3-5 requests if you’re on a datacenter IP.
Parsing Strategy: HTML vs. SP-API vs. Third-Party
You have three realistic options:
- Direct HTML scraping — highest fidelity, most fragile, requires proxy rotation and browser fingerprinting
- Amazon SP-API (Selling Partner API) — structured data, but requires an active seller account and doesn’t expose Best Sellers rank cleanly across all nodes
- Third-party aggregators (Rainforest API, Keepa, DataForSEO) — easiest to operationalize, costs $0.002-$0.02 per ASIN depending on freshness
For competitive intelligence at scale, direct HTML scraping with a rotating proxy layer gives you the freshest data and the widest node coverage. SP-API is better for sellers who need their own rank tracking tied to inventory operations.
If you’re already running proxy-dependent scrapers for other targets — like scraping Walmart Marketplace seller data — you can reuse that infrastructure directly. The same rotating IP pool, session management logic, and retry handlers transfer cleanly.
The Anti-Bot Stack You’ll Actually Face
Amazon runs a layered defense in 2026:
- TLS fingerprinting via BoringSSL — curl and requests fail on most locales without a matching TLS profile
- Browser fingerprint checks (canvas, WebGL, font enumeration) on JavaScript-rendered pages
- Behavioral analysis — consistent timing patterns trigger blocks faster than random delays
- Geographic IP scoring — datacenter ASNs get a higher suspicion score than residential
The practical fix: use a headless browser (Playwright with stealth patches) or a dedicated scraping browser like Browserless or Apify Actors, combined with residential or mobile proxies. For Japan and Brazil specifically, you need in-country mobile IPs. The same logic applies when scraping other commerce platforms with geo-restricted pricing — mobile proxies used for insurance quote comparison demonstrate this pattern clearly: local mobile IP plus rotating session equals consistent access.
A minimal Playwright config for Amazon scraping:
from playwright.async_api import async_playwright async def scrape_best_sellers(url: str, proxy: dict) -> str: async with async_playwright() as p: browser = await p.chromium.launch( proxy=proxy, args=["--disable-blink-features=AutomationControlled"] ) ctx = await browser.new_context( user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", locale="en-US", timezone_id="America/New_York", ) page = await ctx.new_page() await page.goto(url, wait_until="domcontentloaded") content = await page.content() await browser.close() return contentSet
localeandtimezone_idto match the target marketplace country, not your proxy IP’s country. Mismatches are a detectable signal.Structuring a Multi-Marketplace Pipeline
Running 18 markets in parallel is the right architecture, but naive parallelism gets you blocked. The structure that works:
- One session pool per marketplace — don’t reuse US session cookies on .co.uk
- Stagger requests per node — 2-5 second jitter between category pages within a single market
- Checkpoint by ASIN hash — if a page returns fewer than 40 ASINs, treat it as a soft block and retry with a fresh session, not the same one
- Deduplicate sponsored ASINs — store a
is_sponsoredboolean at ingest, filter downstream
For the data model, store raw HTML in object storage (S3/R2) and parse to structured rows separately. Amazon’s HTML structure changes without notice; having the raw payload means you can re-parse without re-scraping.
This pipeline architecture is similar to what you’d build for ATS platform scraping at scale — the same session isolation and checkpoint logic that makes iCIMS career site scraping and Taleo scraping at scale reliable also applies to marketplace data pipelines. The underlying problem — maintaining session integrity across distributed workers — is the same class of challenge.
For brand-level research, Best Sellers data pairs well with Amazon Brand Registry public page data, which gives you trademark registration dates and brand owner identities to enrich your ASIN-level records.
Handling Failures at Scale
Common failure modes and how to handle them:
- 503 / captcha page returned as 200 — parse response body for
containing “Robot Check” before processing - Redirect to signin page — session expired; rotate to fresh session, do not retry same credentials
- Missing rank badges — normal on low-traffic nodes; don’t treat as parse failure
- Price not rendered — JavaScript-dependent; ensure page fully loads before extracting, or use
wait_for_selectoron the price element
Rate your proxy health by marketplace separately. A proxy pool that performs well on amazon.com can be effectively blocked on amazon.co.jp. Monitor block rates per
(proxy_asn, marketplace)tuple and drop underperforming ASNs from that market’s pool automatically.Bottom Line
Scraping Amazon Best Sellers across 18 marketplaces is tractable in 2026 if you treat each locale as a separate target with its own proxy pool, session state, and block-rate monitoring. The two non-negotiables: residential or mobile IPs for Japan and Brazil, and a browser fingerprint that doesn’t expose automation. DRT covers the full stack of e-commerce and job board scraping infrastructure — if this article was useful, the rest of the scrape-target library will be too.
Related guides on dataresearchtools.com
Proxy Patterns for App Store Position Tracking (2026)
App store position tracking without proxies is broken by design. The App Store and Google Play serve different rankings based on country, device type, and even carrier — and if your scraper runs from a single datacenter IP, you’re getting one slice of a highly localized picture. Getting this right in 2026 means matching your proxy infrastructure to the way app store crawlers get blocked, rate-limited, and fingerprinted.
Why App Store Ranking Data Is Harder to Collect Than It Looks
Apple and Google both serve ranking data dynamically. A top-10 result for “expense tracker” in the US App Store differs from the same query in Singapore or Germany — and those differences update hourly during peak periods. The naive approach (curl from an AWS instance) gets you either a CAPTCHA wall or stale cached data within minutes.
The core problem is that app store endpoints use a combination of IP reputation scoring, request-rate fingerprinting, and geo-validation. Datacenter IPs are flagged almost immediately. Even well-known residential proxy pools with large subnets get rate-limited once they show consistent scraping patterns.
This is a structural problem, not a solvable-with-headers one. The fix is at the proxy layer, not the request layer.
Proxy Type Selection: Mobile First, Residential Second
For app store rank tracking specifically, mobile proxies outperform residential on every dimension that matters:
Proxy Type Trust Score Geo Accuracy Cost/GB Block Rate (App Stores) Datacenter Low Medium $0.50-1 Very high Residential Medium High $3-8 Medium Mobile (4G/5G) Very high Very high $8-20 Low ISP (static res.) Medium-high High $4-10 Medium Mobile IPs are assigned by carriers and rotate through CGNAT pools — the same infrastructure a real iPhone uses to browse the App Store. That’s exactly the signal app store anti-bot systems look for. The same logic applies to proxy selection for ticket bots, where trust-tier matching between proxy and platform determines whether you get real data or a block.
For rank tracking at scale across 10+ countries, you need country-matched mobile IPs. A Singapore mobile IP hitting the SG App Store will behave like a local user. A US residential IP doing the same thing may work but will show higher block rates over time, particularly for keyword search ranking endpoints.
Rotation Strategy: Request-Level vs. Session-Level
How you rotate matters as much as which proxy type you use. App store ranking checks fall into two patterns:
Request-level rotation (new IP per request) works for:
- Top charts by category
- Featured app lists
- Search result pages (non-personalized)
Session-level rotation (same IP for a sequence of requests) works for:
- Keyword ranking checks that require simulating a search + scroll + click flow
- A/B test visibility sampling
- Store listing page reads with embedded review counts
For session-level work, you want sticky sessions of 2-5 minutes per IP. Most mobile proxy providers support session tokens or sticky endpoints — use them. If you’re running parallel country checks, assign one sticky session per country per keyword batch.
This is the same session discipline that matters in proxy patterns for brand protection monitoring, where per-platform session consistency prevents false negatives from mid-session IP switches.
Building a Rank Tracking Scraper: Minimal Working Config
A basic Google Play rank tracker in Python using a rotating mobile proxy:
import httpx import time PROXY = "http://user-country-us-session-kw001:pass@mobile.proxypool.io:8080" def check_play_rank(keyword: str, app_id: str) -> int | None: url = "https://play.google.com/store/search" params = {"q": keyword, "c": "apps", "hl": "en", "gl": "US"} headers = { "User-Agent": "Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36", "Accept-Language": "en-US,en;q=0.9", } try: r = httpx.get(url, params=params, headers=headers, proxies={"https://": PROXY}, timeout=15) r.raise_for_status() # parse position of app_id from result HTML return parse_rank(r.text, app_id) except httpx.HTTPStatusError as e: if e.response.status_code == 429: time.sleep(30) return NoneKey decisions in this config: Android UA paired with a mobile proxy (consistent fingerprint), session token in the proxy auth string for sticky behavior per keyword, and explicit 429 handling before retry. Running this with a datacenter proxy and a desktop Chrome UA is a common mismatch that inflates your block rate for no gain.
Multi-Country Tracking: Geo Assignment and Coverage
Running rank checks across 10+ countries introduces a prioritization problem. Not all markets need the same check frequency. A useful breakdown:
- Tier 1 markets (US, UK, DE, JP, AU) — check every 4-6 hours, mobile proxies required
- Tier 2 markets (SG, FR, BR, CA, KR) — check every 12 hours, residential proxies acceptable
- Tier 3 markets (remaining) — daily checks, ISP proxies usually sufficient
For Tier 1, budget for mobile proxies from carriers that match the market. US AT&T or T-Mobile IPs for the US App Store outperform generic residential on trust scoring. For Tier 2 and below, the cost savings from using residential are meaningful and the block rate difference is tolerable at 12+ hour intervals.
This tiered approach is similar to what proxy patterns for ad verification uses — high-trust proxies for high-value markets, cost-optimized tiers everywhere else.
When you scale past 20 countries, proxy health becomes a real operational concern. Stale IPs, misconfigured sticky sessions, and provider outages will silently corrupt your ranking data. The Build a Proxy Health Monitor guide covers how to build real-time status checks that catch these failures before they become data quality problems.
Common Failure Modes and Fixes
- Silent 200s with bad data: App stores sometimes return a 200 with a CAPTCHA page or empty results. Always validate that the response contains expected app count or known app IDs.
- Geo mismatch: Your proxy reports US location, but the App Store serves UK results. Verify geo assignment by hitting an IP-check endpoint before each session batch.
- Rate limit drift: Block rates increase gradually over days, not immediately. Monitor your 429 rate on a rolling 24-hour window, not just current session.
- UA inconsistency: Mobile proxies with desktop UAs get higher scrutiny. Match Android/iOS UA to mobile proxy type.
The proxy selection guide for sneaker bots has a useful breakdown of fingerprint consistency requirements that applies directly here — the same platform-signal matching logic that works for checkout flows works for app store API calls.
Bottom line
For app store position tracking in 2026, use mobile proxies for Tier 1 markets, session-level rotation for keyword flows, and a tiered geo strategy to keep costs in check without sacrificing data quality. Validate response content — not just status codes — at every step. DRT covers proxy infrastructure patterns like these in depth; if you’re building a tracking pipeline from scratch, the health monitoring and proxy selection guides are the right starting points before you write a line of scraping code.
Related guides on dataresearchtools.com
- Proxy Patterns for Ad Verification at Scale (2026)
- Proxy Patterns for Brand Protection Monitoring (2026)
- Proxy Selection for Sneaker Bots in 2026: Mobile vs ISP vs Residential
- Proxy Selection for Ticket Bots: Why Residential Wins (2026)
- Pillar: Build a Proxy Health Monitor: Real-Time Status Tracking
Proxy Patterns for Brand Protection Monitoring (2026)
Brand protection monitoring is one of the few scraping use cases where getting caught isn’t just inconvenient — it’s catastrophically bad for the data. Counterfeit listings disappear, grey-market sellers rotate domains, and unauthorized resellers swap pricing the moment they detect a crawler. Proxy patterns for brand protection monitoring have to be built around stealth, geographic precision, and high rotation frequency, or the data you collect is already stale by the time it lands in your pipeline.
Why Standard Residential Proxies Fall Short
Most brand protection teams start with a residential proxy pool and call it done. That works for basic price monitoring, but it breaks down fast when you need to:
- Detect unauthorized resellers across 15+ marketplaces simultaneously
- Verify geo-restricted counterfeit listings that only surface in specific countries
- Monitor social commerce platforms (TikTok Shop, Instagram Shopping) that fingerprint proxy ASNs aggressively
- Catch trademark violations on ad networks that rotate creatives by IP geolocation
Residential proxies from large pools (Bright Data, Oxylabs, Smartproxy) share exit IPs across thousands of customers. A single IP used for scraping Amazon one hour and brand-checking Shopify the next carries cross-contamination risk. Platforms that flag scraper IPs share blocklists — your “clean” residential IP may already be poisoned before you use it.
The better approach is proxy segmentation by platform tier.
Proxy Type Selection by Platform Tier
Not every marketplace deserves the same proxy budget. Tier your infrastructure to match detection sophistication:
Platform Type Recommended Proxy Rotation Frequency Typical Cost Amazon, eBay, Walmart Mobile (4G/5G) Per request $8-15/GB Shopify storefronts ISP residential Per session (5-10 min) $2-4/GB Social commerce (TikTok Shop) Mobile with sticky sessions Per product page $10-20/GB Brand registry portals Datacenter (authenticated) Per login session $0.10-0.50/GB Telegram/Discord grey markets SOCKS5 mobile Per conversation thread $12-18/GB Mobile proxies outperform residential for high-value targets because they present real carrier ASNs (Singtel, Verizon, EE) rather than ISP ranges that platforms have learned to profile. For the same reason they dominate in proxy selection for sneaker bots — the underlying fingerprint logic is identical: platforms want to see a real device on a real carrier network.
Geographic Targeting and the Country-IP Mismatch Problem
Counterfeit goods listings are often geo-fenced. A fake luxury handbag listing on a Southeast Asian marketplace may never appear to a US IP. Your monitoring stack has to request pages from within the target country, not from a proxy provider’s nearest PoP.
The critical mistake is using a provider’s “country targeting” feature without verifying actual exit geography. Many residential pools label IPs by billing country, not by where the device physically connects. Run a validation sweep before any monitoring campaign:
import httpx import asyncio async def verify_exit_geo(proxy_url: str, expected_country: str) -> dict: async with httpx.AsyncClient(proxies={"all://": proxy_url}, timeout=10) as client: r = await client.get("https://ipapi.co/json/") data = r.json() return { "proxy": proxy_url, "actual_country": data.get("country_code"), "asn": data.get("org"), "match": data.get("country_code") == expected_country } # Run against your pool before campaign launch results = asyncio.run(asyncio.gather(*[ verify_exit_geo(p, "SG") for p in proxy_pool[:50] ])) mismatches = [r for r in results if not r["match"]] print(f"{len(mismatches)} geo mismatches out of 50 sampled")In practice, 10-25% of “country-targeted” residential IPs fail this check with budget providers. For brand monitoring campaigns tied to specific markets (EU luxury goods enforcement, SG parallel imports), this mismatch rate produces false negatives — you conclude a listing doesn’t exist because your IP was routed through a different country.
Session and Fingerprint Management
Brand protection crawls have a different session lifecycle than standard price scrapers. You’re not just fetching a product page — you’re often navigating seller profiles, clicking through to contact pages, and capturing screenshots for legal evidence.
Key session rules:
- Bind one IP to one seller investigation workflow from start to finish. Never rotate mid-session on a seller profile page.
- Use browser-level fingerprinting (Playwright with real Chrome, not httpx) for any platform that serves React or Next.js storefronts.
- Set realistic viewport, locale, and timezone headers that match the exit IP’s country.
- Add 2-8 second jitter between page transitions — brand protection crawls are slower than price scrapers because the evidence chain matters.
- Archive full HTTP response headers alongside screenshots for legal defensibility.
This is the same session discipline required in ad verification at scale, where a session that switches IPs mid-audit produces evidence that opposing counsel can challenge in court.
Marketplace-Specific Patterns
Amazon Brand Registry Monitoring
Amazon’s Brand Registry portal itself uses authenticated sessions, so datacenter proxies are fine there. The risk surface is the public marketplace, where you’re scraping ASIN pages to detect unauthorized third-party sellers. Use residential or ISP proxies per ASIN batch, and rotate after every 15-20 requests per IP.
Watch for Amazon’s “dogs of war” pattern: they serve honeypot ASINs to scrapers with slightly wrong pricing data. If your monitoring pipeline shows wildly inconsistent prices that don’t match manual checks, you’re likely getting served poisoned responses.
App Store and Social Platform Monitoring
App store brand monitoring (fake apps impersonating your brand) uses a different proxy pattern to what’s needed for position tracking — you’re not tracking rank, you’re doing bulk search sweeps for trademark variations. Mobile proxies with country rotation work best here because Apple and Google serve different search results by device locale, not just IP geolocation.
Affiliate and Reseller Channel Audits
Unauthorized affiliate channels are the hardest to catch because they’re often behind branded subdomains or redirect chains. The scraping pattern has to follow the full redirect chain before rendering. A proxy that blocks CONNECT tunneling will silently drop the affiliate referral parameter, giving you a false “clean” result. This overlaps with the challenge covered in affiliate network validation — the proxy stack has to preserve redirect fidelity end to end.
Building a Rotation Architecture That Holds Up
A solid brand protection proxy architecture follows the same layered design as any serious scraping system. The proxy server architecture patterns guide covers the component breakdown in depth, but for brand protection the critical additions are:
- Evidence archiving layer: every request that captures a counterfeit listing must log the full response, exit IP, timestamp (UTC), and geo verification result. Store this in append-only object storage, not a mutable database.
- Dedup by seller fingerprint, not URL: the same counterfeit seller will rotate product URLs. Your dedup key should be seller ID + marketplace, not listing URL.
- Separate pools for evidence capture vs. discovery: use cheap residential for broad discovery sweeps, reserve mobile IPs for the evidence capture requests you’ll present to brand registry or legal counsel.
Failing to separate these pools is expensive. Mobile proxy bandwidth at $12-18/GB burns fast when you’re doing discovery sweeps across thousands of search queries. Keep mobile strictly for the 5-10% of findings that need defensible screenshots.
Bottom Line
For brand protection monitoring in 2026, use mobile proxies for evidence capture on tier-1 marketplaces, ISP residential for session-heavy storefronts, and datacenter only for authenticated brand registry portals. Always geo-verify your exit IPs before campaign launch — mislabeled country pools are the single biggest source of false negatives. DRT covers proxy infrastructure patterns for these exact production use cases, and the tradeoffs here hold across every marketplace vertical where legal defensibility of the captured data actually matters.
Related guides on dataresearchtools.com
Proxy Patterns for Continuous SEO Rank Tracking 2026: Cost vs Coverage
Continuous SEO rank tracking is deceptively expensive at scale. Pull 500 keywords across 10 locales daily and you are firing 5,000 requests every 24 hours — enough to trigger Google’s bot detection within minutes unless your proxy layer is designed for it. The proxy patterns for SEO rank tracking in 2026 are not the same ones you would use for e-commerce or social scraping, and the cost-vs-coverage tradeoff is sharper than most teams realize when they first spec out a tracker.
Why SEO Rank Tracking Has Unique Proxy Requirements
Google SERPs are the most aggressively defended scrape target on the web. Cloudflare, reCAPTCHA v3, and Google’s own fingerprinting stack all run in parallel. The failure mode is not a 403 — it is a degraded SERP that looks real but returns a CAPTCHA page or a country-mismatch result, silently poisoning your rank data.
The requirements that follow from this:
- Residential or mobile IPs only. Datacenter ranges are blocked or heavily throttled on Google Search within hours of high-volume use.
- Geo-matched IPs. A Singapore IP returning results for a UK keyword query will pull a geo-biased SERP. You need IPs in the same city or region as your target locale.
- Low request rate per IP. Google’s session model tolerates roughly 3-5 SERP requests per IP per hour before score degradation. Burst above that and you burn the IP.
- Consistent User-Agent + cookie jar pairing. Rotating UA without rotating cookies (or vice versa) creates a fingerprint mismatch that triggers detection faster than either alone.
Proxy Type Comparison: Residential vs Mobile vs ISP
Not all residential proxies behave the same way for rank tracking. Here is how the main categories compare in 2026 practice:
Type Pass Rate (Google) Cost per GB Best Use Case Residential rotating ~85-92% $3-8 Broad keyword sets, multi-locale Mobile (4G/5G) ~96-99% $12-25 High-value keywords, local packs ISP (static residential) ~88-94% $2-5 Consistent session tracking Datacenter ~30-55% $0.20-0.80 Not recommended for Google SERPs Mobile proxies have the highest pass rates because the IP ASN maps to a carrier, not a hosting provider, but the cost is 3-5x residential. The practical split most teams land on is mobile for the top 10-20% of keywords by revenue importance, and residential rotating for the long tail. If you are also running ad verification workflows, the same mobile pool can pull double duty — this overlap is discussed in Proxy Patterns for Ad Verification at Scale (2026).
Request Scheduling: The Architecture That Determines Cost
The biggest cost lever is not which proxy provider you pick — it is how you schedule requests. Naive rank trackers fire all keywords in parallel bursts at the same time each day. This maximizes IP burn rate and forces you to buy more bandwidth to compensate.
A better pattern:
- Spread requests across a 6-hour window. Pick a window that matches off-peak search activity in your target locale (typically 2am-8am local time). Fewer concurrent queries from the same IP pool means lower per-IP load.
- Group keywords by locale first, then by query intent. Brand keywords, local pack queries, and informational queries hit different SERP layouts. Grouping them lets you reuse the same proxy session for similar fingerprint patterns.
- Implement exponential backoff on 429s, not just retries. A flat retry loop burns IPs. Back off 30s, 2min, 8min before rotating to a fresh IP.
- Cache static SERP elements. Knowledge panels, featured snippets, and “People also ask” boxes change slowly. Pull them once daily at full fidelity, not on every keyword cycle.
A minimal Python scheduler config that applies jitter to avoid predictable timing:
import random, time def throttled_request(session, url, base_delay=12): jitter = random.uniform(0.5, 1.8) time.sleep(base_delay * jitter) return session.get(url, timeout=15)The
base_delayof 12 seconds keeps you under 5 requests per IP per hour at a single-thread level. Run 4 threads per proxy session and you hit roughly 20 requests per hour per IP — still within safe range for most residential providers.Locale Coverage Without Breaking the Budget
Multi-locale tracking is where budgets blow up. The temptation is to buy geo-targeted residential pools in every country you track. In practice, most teams only need city-level accuracy for local pack keywords — country-level IPs are sufficient for standard organic rankings.
A tiered coverage model keeps costs manageable:
- Tier 1 (city-level mobile): Primary revenue markets, local pack tracking, Google Maps rank checks
- Tier 2 (country-level residential): Secondary markets, informational keyword monitoring
- Tier 3 (shared rotating residential): Long-tail, low-priority, or experimental keyword sets
For affiliate sites doing competitive rank monitoring across many verticals, this same tiering logic applies to proxy selection decisions more broadly, as covered in Proxy Patterns for Affiliate Network Validation in 2026.
One underused tactic: for locales where you have low keyword volume (under 50 keywords), use a proxy provider’s on-demand geo-targeting rather than a dedicated pool. Providers like Oxylabs, Bright Data, and Smartproxy all support country+city targeting on their rotating residential endpoints with no minimum commitment.
Handling Detection and Result Validation
A proxy that returns a 200 is not the same as a proxy that returned a valid SERP. Google serves different page structures to suspected bots, and if your parser is not validating SERP structure before storing rank data, you are silently ingesting garbage.
Validation checks to run before writing rank data:
- Confirm the
#searchdiv or equivalent organic results container is present - Check that the number of organic results is within expected range (7-10 for standard queries)
- Verify the result URLs are real domains, not redirect traps
- Flag any response where the page title contains “unusual traffic” or CAPTCHA patterns
The same challenge of detecting degraded or fraudulent responses shows up in survey and earn-app proxy setups, where providers serve fake completion pages to suspected automation — Proxy Selection for Survey Sites and Earn Apps (2026) covers that validation pattern in detail.
For video and YouTube SERP tracking, the fingerprinting stack is slightly more lenient than Google Search but locale-matching matters even more because YouTube’s ranking algorithm is heavily localized. If you are tracking video properties alongside web rankings, YouTube SEO and Video Rank Tracking with Proxies (2026) lays out the specific IP requirements for YouTube SERP pulls.
The sneaker-drop proxy community solved rotating IP exhaustion under high detection pressure years before the SEO tracking world caught up — Proxy Selection for Limited Drop Sneaker Releases (2026) has relevant patterns for IP recycling and session warm-up that translate directly to rank tracker architecture.
Bottom Line
For most teams running 500-2,000 keywords daily, the right setup is residential rotating for the long tail plus a small mobile pool for local and high-value terms, with request jitter and SERP validation baked in from day one. Skipping validation is the most common reason rank data becomes unreliable under scale. DRT covers proxy infrastructure and scraping patterns across SEO, ad tech, and data collection — if this architecture is relevant to your stack, the other proxy use-case guides in this series are worth a read.
Related guides on dataresearchtools.com
How to Scrape Taleo Career Sites at Scale (2026)
Oracle Taleo powers job listings for thousands of enterprise employers — Fortune 500s, healthcare systems, government contractors — and scraping it at scale is genuinely harder than scraping most ATS platforms. The challenge is not just pagination; Taleo’s hosted endpoints vary by tenant subdomain, its JavaScript-heavy requisition pages resist simple HTTP fetches, and its rate limiting is aggressive enough to block naive scrapers within minutes.
How Taleo’s Architecture Works (and Why It Matters)
Taleo deployments fall into two patterns. The older “hosted” model puts job listings at a subdomain like
company.taleo.net/careersection/, while newer Oracle Recruiting Cloud (ORC) tenants serve listings underfa-xxxx.oraclecloud.com. Both use server-side rendered pages for the job list but load full requisition details via internal API calls.The key discovery: every Taleo instance exposes a semi-public REST endpoint at
/careersection/rest/jobboard/searchjobs(older hosted) or a GraphQL-style endpoint in ORC. Hitting this directly returns JSON, bypassing HTML parsing entirely and cutting scrape complexity by half.import httpx TENANT = "companyname" BASE = f"https://{TENANT}.taleo.net/careersection/rest/jobboard/searchjobs" params = { "multiln": "false", "lang": "en", "start": 0, "limit": 25, "portal": "1", } headers = { "Accept": "application/json", "Referer": f"https://{TENANT}.taleo.net/careersection/joblist.ftl", } resp = httpx.get(BASE, params=params, headers=headers, timeout=15) data = resp.json() jobs = data.get("requisitionList", [])Increment
startby 25 per page untilrequisitionListis empty. For ORC tenants, the endpoint changes to av2/jobspath — inspect XHR calls in DevTools to find it.Tenant Discovery at Scale
Scraping one company is trivial. Scraping thousands requires a tenant enumeration strategy. There is no official registry, so you build it from:
- LinkedIn job postings that include
taleo.netin the apply URL - Google dork:
site:taleo.net "careersection" "apply now" - Common Crawl extracts filtered by
taleo.nethostnames - Job board APIs (Indeed, ZipRecruiter) that leak the ATS apply URL
Once you have a list of subdomains, check liveness with a HEAD request to
/careersection/joblist.ftl. Expect 10–30% to return 404 (abandoned tenants) or redirect to the parent company’s careers page after an acquisition.If you are scraping Ashby or iCIMS tenants alongside Taleo for a talent pipeline, the same discovery pattern applies — see How to Scrape Ashby Career Sites for Talent Pipelines (2026) for a comparable approach, and How to Scrape iCIMS Career Sites (2026) for iCIMS-specific quirks.
Rate Limiting and Anti-Bot Behavior
Taleo hosted instances run Oracle’s WAF in front of a JBoss application server. The rate limits are tenant-configurable but typical defaults are:
Behavior Threshold Response Rapid sequential requests >10 req/s per IP 429 or silent 503 Missing Referer/Accept headers Any rate 403 Session cookie absence First request Redirect to login ORC tenants (FA-series) >5 req/s per IP Akamai bot challenge The session cookie issue is the most common failure mode. Taleo hosted requires a valid
JSESSIONIDplus aTaleoSIDcookie acquired from the initial page load. The REST endpoint will return a 302 to the login page if these are absent.Fix this by doing a single GET to
/careersection/joblist.ftlbefore hitting the REST endpoint, capturing cookies from the response, and forwarding them on all subsequent requests. Withhttpx, use aClientwith cookie jar enabled:with httpx.Client(follow_redirects=True) as client: client.get(f"https://{TENANT}.taleo.net/careersection/joblist.ftl") # cookies now populated resp = client.get(BASE, params=params, headers=headers)For ORC tenants on Akamai, residential proxies are unavoidable. Datacenter IPs get challenged immediately. The proxy rotation pattern is the same one covered in How Proxies Help Scrape Reviews at Scale: Yelp, Google, Trustpilot (2026) — one IP per session, rotate on 429, minimum 2-second delay between requisition fetches.
Parsing Requisition Detail Pages
The job list API returns metadata (title, location, req ID, posting date) but not the full description. To get the JD body, you need to hit the requisition detail page:
/careersection/10000/jobdetail.ftl?job={reqId}&lang=enThis is an HTML page. The description sits inside a
container. Parse with BeautifulSoup:from bs4 import BeautifulSoup detail_resp = client.get( f"https://{TENANT}.taleo.net/careersection/10000/jobdetail.ftl", params={"job": req_id, "lang": "en"}, ) soup = BeautifulSoup(detail_resp.text, "lxml") desc_div = soup.find("div", id="requisitionDescriptionInterface") description = desc_div.get_text(separator="\n").strip() if desc_div else ""Note: the
10000in the URL is the career section ID, not a real number. Different tenants use different IDs (10000, 10200, 5001, etc.). Check the job list page source for the correct value before scraping.Key fields to extract from detail pages:
- Job title, requisition ID, posting date
- Location (often structured as city, state, country separately)
- Employment type (full-time / contract / internship)
- Department and business unit
- Full JD text (HTML preserved for downstream parsing)
Infrastructure for Multi-Tenant Runs
Running this against hundreds of tenants in parallel requires a queue, not a loop. A simple architecture:
- Queue: Redis or SQS with tenant subdomains as items
- Workers: 4–8 async Python workers per machine, each managing its own httpx
Clientwith cookie jar - Proxy pool: Rotate IPs at the worker level, not per-request. Sticky sessions per tenant reduces cookie re-acquisition overhead.
- Storage: Write raw JSON and HTML to S3 or local disk first, parse separately. Parsing bugs should not require re-fetching.
- Dedup: Hash on
(tenant, reqId)to skip already-seen requisitions on incremental runs.
For comparison, the same async worker pattern applies well when scraping product data at scale — the worker isolation model described here is similar to what you would use for How to Scrape Amazon Best Sellers Across 18 Marketplaces (2026). For brand and company intelligence use cases that combine job data with public registry data, see How to Scrape Amazon Brand Registry Public Pages (2026) for a comparable enrichment workflow.
For incremental runs, check
postingDateagainst your last-seen timestamp per tenant rather than re-fetching the full listing. Most enterprise tenants post under 50 new roles per week, so a daily incremental pull with a 7-day lookback window covers 99% of new postings.Bottom Line
Taleo is scrapeable at scale once you handle the session cookie requirement and split your scrape into a fast list API call plus a slower detail HTML fetch. Target the
/rest/jobboard/searchjobsendpoint first; fall back to HTML parsing only if the tenant blocks it. Use residential proxies for ORC (FA-series) tenants and rate-limit to one requisition fetch every 2–3 seconds per IP. DRT covers patterns like this across the ATS and e-commerce scraping landscape for engineers who need production-grade pipelines, not toy examples.Related guides on dataresearchtools.com
- How to Scrape Ashby Career Sites for Talent Pipelines (2026)
- How to Scrape iCIMS Career Sites (2026)
- How to Scrape Amazon Best Sellers Across 18 Marketplaces (2026)
- How to Scrape Amazon Brand Registry Public Pages (2026)
- Pillar: How Proxies Help Scrape Reviews at Scale: Yelp, Google, Trustpilot (2026)