← Back to blog

Top 10 Common AI Agent Scraping Mistakes to Avoid

August 10, 2026
Top 10 Common AI Agent Scraping Mistakes to Avoid

The most common AI agent scraping mistakes fall into three buckets: infrastructure failures that block the model before it ever runs, LLM-specific extraction errors that corrupt data silently, and operational gaps that turn intermittent bugs into runaway costs. Here is the triage list every engineer should pin to their backlog.

  1. No typed failure classification — classify every fetch result as TRANSIENT, RATE_LIMITED, BLOCKED, BAD_SCHEMA, or SUCCESS before passing anything to the model.
  2. Browser-first by default — start with HTTP fetch and escalate to headless browser only on NEEDS_JS; running Chromium on every request multiplies cost and block rate.
  3. Fragile XPath selectors — replace hard-coded positional XPaths with attribute-robust selectors anchored to stable container IDs or data-* attributes.
  4. Sending full DOM to the LLM — slim the HTML first, then convert to hierarchical JSON or flat XPath-to-text before extraction to reduce hallucination risk.
  5. No stop conditions or retry budget — define a maximum retry count and a circuit-breaker threshold per domain; unbounded retries are how one flaky target drains a credit balance.
  6. Naive parallelism — coordinate concurrency with per-domain rate limits; shared-state bugs and simultaneous 429s are predictable consequences of uncoordinated parallel runs.
  7. Ignoring robots.txt and terms of service — treat consent as a design constraint, not an afterthought. Prefer official APIs and sitemaps where they exist.
  8. No small-sample validation before scale — probe 5–10 pages, confirm field coverage, then gate the full run on a schema-pass threshold.
  9. Unbounded LLM calls per page — set a spending cap and instrument cost-per-valid-extraction; without it, a schema change on the target site silently multiplies token spend.
  10. No data freshness or deduplication strategy — track cursor state and use a probabilistic membership check to avoid re-fetching pages that have not changed.

Pro Tip: Treat the fetch layer as the authoritative source of truth. If a fetch fails, return a typed failure code and let the agent reason about it — never pass a partial or error HTML payload to the model and hope it figures it out.

Key Takeaways

Reliable agentic extraction requires typed failure classification at the fetch layer, small-sample validation before scale, and spending caps that prevent schema drift from becoming a budget crisis.

PointDetails
Classify failures at the fetch layerReturn SUCCESS, BLOCKED, TRANSIENT, or BAD_SCHEMA before passing any result to the model.
Validate at small sample firstProbe 5–10 pages and require a 95% schema-pass rate before scheduling a full-scale run.
Use structured input formatsHierarchical JSON or flat XPath-to-text reduces LLM hallucination compared with raw or aggressively slimmed HTML.
Cap spending with circuit-breakersInstrument cost-per-valid-extraction and halt jobs automatically when it exceeds baseline by 30%.
Gyrence provides typed, failure-first extractionEvery Gyrence API call returns a discriminated-union response with explicit failure codes, spending caps, and bundled LLM extraction.

Table of Contents

What are the most common AI agent scraping mistakes in production?

The industry term for what most teams call "scraping" in an agent context is agentic extraction: an LLM-driven loop that fetches, parses, and structures web data autonomously. The failure modes are distinct from those of a traditional scraper because the model introduces a second layer of error on top of the infrastructure layer. Community-curated failure catalogs show the recurring categories: incorrect tool use, broken selectors, dependency errors, and cascaded tool-call failures. The practical implication is that you need an explicit failure taxonomy before you write a single prompt.

The single most effective framing is this: most agent scraping failures are infrastructure and validation problems, not prompt problems. Fix the fetch layer and the schema contract first. The model logic is usually the last thing that needs tuning.

Design patterns that make agent scrapers reliable at scale

Naive agent scrapers treat a scraping task as a one-shot script: fetch the URL, extract the data, done. That works for a demo. At production scale, against real targets, it breaks in predictable ways. The patterns below are what separate a reliable extraction pipeline from a fragile one.

1. Incremental runs over one-shot scripts

A "scraping-as-skill" architecture runs the agent in short, bounded increments rather than one long session. Each increment fetches a page or a batch, validates the result, persists the cursor state, and exits cleanly. The next run picks up from the cursor. This means a transient block or a timeout affects one increment, not the entire job.

Many agent failures occur in the fetch layer before the model can reason about anything. Incremental runs make those failures cheap and reproducible instead of catastrophic and opaque.

2. Stop conditions and bounded retries

Every run needs an exit contract. Define:

  • A maximum retry count per URL (e.g., 3 attempts with exponential backoff).
  • A per-domain circuit-breaker: if block rate exceeds a threshold (e.g., 40% over the last 20 requests), pause and escalate.
  • A job-level stop condition: if the success rate drops below a quality gate, halt and alert rather than continuing to burn credits on bad data.

Classification-based escalation matters here. A TRANSIENT failure warrants a retry with jitter. A BLOCKED failure warrants infrastructure escalation. A BAD_SCHEMA failure warrants a prompt or selector fix. Treating all three the same way is one of the most expensive mistakes in data scraping.

3. Pagination and cursor handling

Offset-based pagination (?page=2, ?offset=40) is brittle against live data: inserts or deletes shift the window and produce duplicates or gaps. Cursor-based pagination (an opaque token or a last_seen_id) is stable because the server anchors the position to a record, not an index.

For unknown-length lists, always store the cursor in durable state (a database row, not an in-memory variable) so a crash does not restart the job from page one. For deduplication at scale, Bloom filters are a memory-efficient way to check URL membership without storing every seen URL in full.

4. Parallel execution without shared-state bugs

The most common parallel execution mistake is launching N concurrent workers against the same domain with no coordination. Each worker independently tracks its own retry state, so a domain-wide 429 triggers N simultaneous backoff timers that all fire at the same moment, producing a thundering-herd retry storm.

The fix is a shared rate-limit token bucket per domain, accessible to all workers. Workers draw a token before each request; if the bucket is empty, they wait. This keeps aggregate request rate within the domain's tolerance regardless of worker count.

A concise incremental-run loop looks like this:

cursor = load_cursor(job_id)
while not stop_condition_met(job):
    result = fetch_with_classification(next_url(cursor))
    if result.type == "SUCCESS":
        validated = validate_schema(result.payload)
        if validated:
            persist(validated)
            cursor = advance(cursor)
    elif result.type == "TRANSIENT":
        retry_with_backoff(result)
    elif result.type == "BLOCKED":
        escalate_to_managed_infra(result)
        break
    elif result.type == "BAD_SCHEMA":
        log_and_alert(result)
        break
save_cursor(job_id, cursor)

The mental model: think of each run as a transaction. It either commits a valid batch and advances the cursor, or it rolls back cleanly with a typed reason.

Pro Tip: Separate fetch-layer logs from model logs. When you debug a failure, you need to know whether the problem was a blocked request or a bad extraction — mixing the two signals in one log stream makes triage take ten times longer.

How do LLM-specific extraction errors corrupt your dataset?

LLM-based extraction introduces failure modes that a traditional CSS-selector scraper never produces. The data looks plausible. The schema validates. The pipeline reports success. And the dataset is wrong.

The six structural failure modes

Hallucination/fabrication: The model generates a value that does not exist in the source HTML. A product page with no listed release date gets "2024-01-01" because the model inferred a plausible default. This is the hardest failure to catch because the output is well-formed.

Implicit inference: The model fills a field by reasoning from context rather than reading a literal value. A sale_price field gets populated with a calculated discount instead of the actual marked-down price shown on the page.

Field-mapping errors: Two fields with similar names get swapped. price and original_price are a classic pair. So are author and editor, or publish_date and last_updated.

Schema conformance errors: The model returns a string where the schema expects a number, or an array where it expects a single object. These are catchable with a JSON Schema or Pydantic validator, but only if you run one.

The six structural failure modes — overview diagram

Partial completeness: The model extracts 8 of 10 required fields and silently omits the other two rather than returning null. Downstream joins on those fields produce silent data loss.

Context leakage: Content from an adjacent page or a previous extraction call bleeds into the current output when conversation history is not properly scoped per extraction call.

Handing an agent a browser to "debug the web" leads to silent, expensive partial successes. The recommended pattern is a typed extraction contract where the tool returns either validated fields or an explicit failure code — not a best-effort payload that looks correct until you query it. (Stop Letting AI Agents Debug the Web)

Detection signals in your dataset

Fabricated dates cluster around round numbers or common defaults (2024-01-01, January 1). Swapped price fields produce sale_price > price rows. Partial completeness shows up as a field with an anomalously high null rate relative to the source site's actual coverage. Context leakage produces fields that match a different URL's content — detectable by cross-referencing extracted values against the source URL.

Mitigation patterns

LLM extraction is highly sensitive to input representation: hierarchical JSON or flat XPath-to-text formats reduce hallucination compared with unstructured or aggressively slimmed HTML. Structured formats constrain the model to elements that actually exist in the cleaned DOM, which is the root cause of most fabrication errors.

Beyond input format, the core mitigations are:

  • Use structured prompts that specify null-preserving rules explicitly: "If a field is not present in the source, return null. Do not infer or estimate."
  • Enforce typed JSON outputs with a schema validator on every extraction call, not just spot checks.
  • Run a verification pass on high-value fields: re-extract with a second prompt that asks the model to confirm the value exists verbatim in the provided text.
  • Scope conversation history to a single extraction call; never carry prior page context into the next call.

Pro Tip: Your web-formatting problem is often bigger than your scraping problem. Before tuning the prompt, check whether the input representation is giving the model a fighting chance.

Why does your agent get blocked before the model even runs?

Infrastructure failures are the dominant operational failure mode in agentic extraction. Tests show agent runs using standard headless Chromium are blocked far more often than managed infrastructure: observed pass rates for unassisted agents on Cloudflare-protected targets were significantly lower than for managed stacks with proper fingerprinting, which achieved pass rates above 90%. That gap is not a prompt problem.

What modern anti-bot systems actually check

Simple user-agent rotation stopped working years ago. Modern anti-bot systems evaluate:

  • TLS/JA3 fingerprint: The cipher suite order and TLS extension list in the handshake. A Python requests library or a default Chromium build produces a fingerprint that differs from a real browser's. The server can block the connection before serving a single byte of HTML.
  • Navigator heuristics: navigator.webdriver, navigator.plugins.length, navigator.languages — headless browsers expose consistent tells unless explicitly patched.
  • Behavioral entropy: Mouse movement patterns, scroll velocity, and timing between interactions. Bots move in straight lines at constant speed.
  • Header entropy: The order and presence of HTTP headers. A real browser sends Accept-Language, Accept-Encoding, and Sec-Fetch-* headers in a consistent order; a naive scraper often omits or reorders them.

Modern anti-bot systems evaluate TLS fingerprint mismatches and other low-level signals; scrapers that do not mirror real browser TLS handshakes are blocked before server-side processing begins.

Common infrastructure misconfigurations

  • Shared datacenter proxies: Multiple agents sharing the same IP pool get that pool flagged and banned together. One bad actor in the pool poisons the address for everyone.
  • Session mishandling: Not persisting cookies across requests to the same domain, or reusing a session across domains, produces inconsistent state that anti-bot systems flag.
  • Credential exposure: API keys and proxy credentials stored in environment variables that get logged or committed to version control. Rotate credentials on a schedule and store them in a secrets manager (AWS Secrets Manager, HashiCorp Vault).
  • Improper backoff on 429/403: Retrying immediately on a 429 is the fastest way to get a longer ban. Use exponential backoff with jitter; respect Retry-After headers when present.

Operational checks to run now

SignalHealthy thresholdAction when breached
Block rate (per domain)Below 10%Rotate proxy pool, review fingerprint config
p95 fetch latencyBelow 8 secondsCheck proxy geography, switch to closer egress
429 rateBelow 5%Reduce concurrency, add per-domain token bucket
Structural extraction error rateBelow 5%Audit selector config, re-validate schema

Pro Tip: Treat managed infrastructure (residential IPs plus fingerprint patching) as a separate engineering responsibility from agent logic. The agent should not know or care how a page was fetched — it should receive a clean, classified result. Mixing fetch concerns into agent reasoning is how you get both layers wrong.

How do you choose an extraction strategy that does not break on every deploy?

The root cause of most selector brittleness is coupling the extraction logic to the site's current DOM structure rather than to the data's semantic meaning. A hard-coded XPath like /html/body/div[3]/div[1]/span[2] breaks the moment the site adds a banner or reorganizes its layout. That is not a hypothetical — it happens on every non-trivial site within weeks.

Deterministic vs. LLM extraction: a neutral comparison

DimensionDeterministic (CSS/XPath)LLM-based extraction
Reliability on stable layoutsHighModerate
Resilience to layout changesLow without maintenanceHigher with good input format
Hallucination riskNonePresent without mitigation
Token costNonePer-call inference cost
Schema enforcementExplicit, compile-timeRequires runtime validator
Best forStructured, stable pagesHeterogeneous or semi-structured content

The practical answer is a hybrid: use deterministic anchors for fields that have stable, identifiable markers (product SKU in a data-sku attribute, price in a [itemprop="price"] element), and fall back to LLM extraction only for fields that require semantic interpretation.

Input formats that reduce hallucination

Structured input formats — hierarchical JSON or flat XPath-to-text — let LLMs avoid hallucinating nonexistent elements by constraining outputs to elements that exist in the cleaned DOM. The trade-offs:

  • Full HTML: Maximum context, maximum token cost, highest noise. Rarely the right choice for production extraction.
  • Slimmed HTML: Reduced cost, but aggressive stripping removes positional context the model needs to disambiguate similar elements.
  • Hierarchical JSON (DOM hierarchy): Preserves parent-child relationships. Better for nested data structures like product variants or address blocks.
  • Flat JSON (XPath → text): Each entry maps a path to its text value. Low token cost, easy to validate, and the model cannot hallucinate an element that is not in the map.

For implementation, strip style, script, noscript, and decorative class attributes before passing the DOM to the model. Preserve positional XPaths and data-* attributes — they are the anchors that prevent field swaps. A developer guide on fetching web pages to LLM-ready formats covers the full conversion pipeline with concrete examples.

Pro Tip: Use typed collector configs — JSON Schema, Zod, or Pydantic — to define the extraction contract before you write the prompt. Schema drift is the silent killer of long-running extraction jobs; a schema validator catches it at the boundary, not three weeks later in a downstream query.

How do you validate extractions before they corrupt production data?

The most expensive mistake in agentic extraction is running at scale before validating at small sample. A schema error that affects 12% of pages costs 12x more to fix after a million-page run than after a hundred-page probe. The validation methodology below is designed to catch failures at the cheapest possible point.

The small-sample validation pipeline

  1. Probe phase: Select 5–10 representative pages covering the target site's layout variants (product page, category page, edge cases like out-of-stock or discontinued items).
  2. Field confirmation: Manually verify that every required field is present and correctly extracted on the probe set. Check for the LLM failure modes from the previous section: null fields, swapped values, fabricated defaults.
  3. Schema enforcement run: Execute the full extraction pipeline on the probe set with a strict JSON Schema or Pydantic validator. Any SCHEMA_VALIDATION_FAILED result is a hard stop.
  4. Quality gate: Define a minimum pass rate (e.g., 95% of probe pages must pass schema validation) before scheduling the scale run.
  5. Scale execution: Only after the probe set passes the quality gate, schedule the full run with monitoring enabled.

A constrained, typed collector configuration plus small-sample validation and rule-based quality checks improves pass rates and type-match compared with unconstrained LLM-generated scrapers. The trade-off is some one-shot flexibility for repeatability — which is exactly the right trade for a scheduled production pipeline.

Explicit failure codes

Every extraction result should carry one of these typed outcomes:

  • SUCCESS — all required fields present and schema-valid.
  • PARTIAL — required fields present but optional fields missing; acceptable if documented.
  • SCHEMA_VALIDATION_FAILED — output does not conform to the schema; do not persist.
  • BLOCKED — fetch layer returned a block signal; escalate infrastructure.
  • TRANSIENT — network or timeout error; retry with backoff.
  • BAD_INPUT — the fetched page does not match the expected template; flag for human review.

Typed extraction contracts that return validated fields or an explicit failure code prevent the most expensive failure mode: a plausible-looking partial success that passes silently into production data.

Key operational metrics

MetricTargetAlert threshold
Extraction success rateAbove 95%Below 90%
p95 fetch latencyBelow 8 secondsAbove 12 seconds
Block rateBelow 10%Above 20%
Cost per valid extractionBaseline + 10%Baseline + 30%

Archival and replayability checklist

  • Store sanitized HTML for every failed extraction (not just the error code).
  • Log request headers and redirect history alongside the HTML.
  • Capture the failing selector or the exact prompt input that produced the bad output.
  • Tag archived failures with the failure code so you can query by type.

Pro Tip: Implement schema checks as CI-style gates in your pipeline. A rule-based quality check — "no more than 5% null values in price field across the batch" — catches schema drift automatically without requiring manual review of every run.

How do unbounded LLM calls turn a scraping job into a budget crisis?

Token costs are not linear with page count when the extraction architecture is naive. Three patterns produce runaway spend.

The three cost traps

Full-DOM extraction at scale. Sending a complete, unprocessed HTML page to an LLM for every extraction call is the fastest way to exhaust a token budget. A typical e-commerce product page is 50–150KB of HTML. After conversion to tokens, that is 12,000–40,000 tokens per page. At production scale, the math is punishing. Slim the input first: strip boilerplate, convert to flat JSON or hierarchical JSON, and pass only the relevant DOM subtree.

Batch sizing errors. Batches that are too large blow the model's context window and produce truncated outputs — which look like partial completeness failures but are actually token-limit mismatches. Batches that are too small multiply per-call overhead (API round-trip latency, connection setup, per-call minimum billing increments). The right batch size depends on the model's context window and the average input size per page; instrument both before setting a fixed batch size. The LLM context window and web data guide covers truncation risks and strategies for preserving critical DOM context within token limits.

The three cost traps — overview diagram

No spending cap or circuit-breaker. A schema change on the target site can cause every extraction to fail schema validation, triggering retries, which trigger more LLM calls, which burn credits at full rate while producing zero valid output. Without a spending cap, this runs until the billing cycle ends.

Cost mitigation patterns

  • Pre-extract deterministic anchors (price, SKU, URL) with CSS selectors before sending anything to the LLM. Only send fields that require semantic interpretation.
  • Cache extraction results by URL and content hash. If the page content has not changed since the last fetch, return the cached result without an LLM call.
  • Set a per-job spending cap and a per-domain circuit-breaker. When cost-per-valid-extraction rises above a threshold, pause the job and alert.
  • Use a cheaper model for schema-conformance verification passes and reserve the more capable model for initial extraction.

Pro Tip: Instrument cost-per-valid-extraction as your primary financial metric, not cost-per-page. A page that produces a SCHEMA_VALIDATION_FAILED result costs the same as a successful one but delivers zero value. When p95 cost-per-valid-extraction rises, that is the signal to audit your input pipeline, not your prompt.

Engineer's remediation playbook: 7, 30, and 90-day fixes

This checklist is prioritized by impact and implementation speed. Add these directly to your backlog.

Fix within 7 days

  1. Add fetch-layer logging. Log every request with URL, HTTP status, response time, and a classified failure code. Separate this log stream from model/agent logs.
  2. Implement typed failure responses. Every fetch result returns one of: SUCCESS, TRANSIENT, RATE_LIMITED, BLOCKED, BAD_SCHEMA, NEEDS_JS. No more passing raw error HTML to the model.
  3. Add exponential backoff with jitter on retries. Replace any time.sleep(1) retry logic with base_delay * (2 ** attempt) + random.uniform(0, 1).
  4. Set a per-job spending cap. Even a rough cap (e.g., stop after N LLM calls) prevents runaway cost while you build proper instrumentation.
  5. Audit robots.txt compliance. Check that your agent respects Disallow directives and sends a proper User-Agent string. Treating robots.txt, rate limits, and publisher terms as a consent layer reduces legal and reputational risk.

Fix within 30 days

  1. Run small-sample validation on every new target. Probe 5–10 pages, confirm field coverage, and gate scale runs on a 95% schema-pass threshold.
  2. Define a retry budget per domain. Maximum 3 retries per URL; circuit-breaker at 40% block rate over the last 20 requests.
  3. Switch to flat JSON or hierarchical JSON inputs for LLM extraction. Measure hallucination rate before and after; expect a meaningful reduction.
  4. Add a Pydantic or JSON Schema validator on every extraction output. Log SCHEMA_VALIDATION_FAILED results separately for triage.
  5. Implement cursor-based pagination for any target with paginated lists. Persist cursor state in durable storage.

Fix within 90 days

  1. Audit and upgrade infrastructure. Evaluate whether your current proxy setup and TLS fingerprint configuration can pass modern anti-bot checks. The AI agent web browsing checklist covers the operational steps in detail.
  2. Build a monitoring dashboard. Track success rate, p95 latency, block rate, and cost-per-valid-extraction per domain. Set automated alerts at the thresholds from the validation section.
  3. Catalog flaky sources. Maintain a registry of domains with known anti-bot configurations, schema instability, or JS-rendering requirements. Route them to the appropriate fetch mode automatically.
  4. Implement WebDoppler-style change detection. Subscribe to webhook alerts when a monitored page's content changes, so your extraction schema can be updated before the next scheduled run.

Pro Tip: Triage your backlog by cost-per-valid-extraction and block rate, not by the number of failing URLs. A domain with a 60% block rate and high per-page LLM cost is a higher priority than ten domains with occasional TRANSIENT errors.

Scraping is infrastructure, not a feature

The conventional wisdom treats web scraping as a quick integration task: write a selector, call an API, done. That framing is why most agent scrapers fail within weeks of their first production deploy.

Web data is a storm. Sites change layouts without notice. Anti-bot systems update their fingerprint checks. LLMs hallucinate plausible-looking values that corrupt downstream models. The teams that build reliable extraction pipelines treat scraping as permanent infrastructure with the same engineering discipline they apply to a database or a message queue: typed interfaces, failure classification, monitoring, and a validation gate before any data touches production.

The testing-first, typed-failure approach is not overhead. It is the only architecture that makes agentic extraction predictable at scale. Every hour spent on fetch-layer logging and schema enforcement saves days of debugging corrupted datasets. The engineers who learn this early build systems that run for months without manual intervention. The ones who skip it spend those months firefighting.

Web scraping is not a one-off feature you ship and forget. It is a responsibility you maintain.

What a failure-first web data API should give you

The failure modes covered in this article — blocked fetches, schema drift, hallucinated fields, runaway token costs — are exactly what a well-designed managed web data API should handle before your agent logic ever runs.

Gyrence

Gyrence is built around that contract. Every API call returns a typed, discriminated-union response that includes the failure cases, so your agent reasons about results instead of guessing. The five primitives (Search, Traverse, Fetch, Extract, Map) map directly to the patterns in this article: HTTP-first fetch with browser escalation, LLM-powered schema-guided JSON extraction with no separate inference charge, site-wide crawls with cursor state, and URL graph mapping via sitemaps. Spending caps and per-workspace billing controls mean your scraping bill does not surprise you when a target site changes.

Before committing to any managed web data API, evaluate it on these criteria:

  • Does every response carry a typed failure code, or does it return a best-effort payload?
  • Does it support small-sample validation before a full crawl run?
  • Does it handle TLS fingerprinting and proxy rotation as a managed concern, separate from your agent logic?
  • Does it expose spending caps and per-call cost visibility?
  • Does it provide webhook monitoring for content changes on tracked pages?

Gyrence answers yes to all five. Start with the Gyrence docs to see the full API surface, or open the console to run your first extraction against a live target.

Sources

Fetch layer and infrastructure:

LLM extraction research:

Anti-bot and fingerprinting:

Deduplication and crawl efficiency:

Agent failure taxonomy:

FAQ

What are the most common errors AI agents make when scraping?

The most frequent AI agent scraping errors are fetch-layer blocks (the agent never receives valid HTML), LLM hallucination of field values not present in the source, schema conformance failures, and fragile selectors that break on layout changes. A typed failure taxonomy that classifies each error type is the first step toward fixing them systematically.

Do AI agents make mistakes even when the page loads successfully?

Yes. A successful fetch does not guarantee correct extraction. LLMs can fabricate plausible-looking values, swap similar fields like price and sale_price, or silently omit required fields rather than returning null. Running a schema validator on every extraction output catches these errors before they reach production data.

What is the best way to avoid runaway costs in AI agent scraping?

Instrument cost-per-valid-extraction (not cost-per-page) as your primary financial metric, set a per-job spending cap, and use a circuit-breaker that halts the job when cost rises above a defined threshold. Pre-extracting deterministic fields with CSS selectors before sending anything to the LLM also reduces per-page token spend significantly.

How do you handle JavaScript-rendered content without getting blocked?

Use HTTP fetch as the default and escalate to a headless browser only when the response is classified as NEEDS_JS. Running a full headless Chromium instance on every request exposes a TLS and navigator fingerprint that modern anti-bot systems detect; managed infrastructure with proper fingerprint patching reaches pass rates in the 90% range versus roughly 26–39% for unassisted standard Chromium on protected targets.

Web scraping legality depends on the target site's terms of service, the type of data collected, and applicable law. The practical engineering guidance is to honor robots.txt Disallow directives, respect Crawl-delay settings, prefer official APIs and sitemaps where they exist, and treat consent as a design constraint rather than an afterthought. Consult a qualified attorney for advice specific to your use case and jurisdiction.