Better Fetch

· Paul Crossland

Session Evidence for Agentic Fetch Incidents

Cloudflare's new agent and bot signals show why browser-grade fetch logs need journey-level context, not just request outcomes.

A single HTTP response is no longer enough evidence for many production fetch incidents. The same URL can look fine when tested directly, fail when opened through a browser session, render different content after a consent step, or be classified differently once an automated actor starts moving through a site. That is not just a WAF problem. It is becoming an agent-infrastructure problem.

On July 13, Cloudflare announced Precursor, a continuous behavioral validation engine that turns session-level interaction into bot-management signals. The same day, Cloudflare's developer changelog noted that Precursor introduces session-based bot detection for Challenges, that Agents SDK MCP clients can respond to elicitation requests, and that Markdown for Agents now preserves security and cache headers in converted responses. On July 14, Cloudflare also published a WAF managed ruleset release, a reminder that application-layer policy keeps changing underneath ordinary fetch traffic.

The useful synthesis for web-data operators is not "Cloudflare detects bots, so scrapers need another trick." That is the wrong frame and the wrong safety model. The operational lesson is that agentic browsing, browser-grade fetching, and content extraction now depend on evidence across a journey: which client acted, what state it carried, what policy surface evaluated it, what headers survived conversion, and which step changed the result.

If your fetch system logs only url, status, proxy_region, and html_length, it will not be able to explain failures in this environment. A crawler may be allowed on the first page view, challenged after a sequence of interactions, served different agent-oriented Markdown than browser HTML, or routed through a WAF rule that did not exist last week. The fix is not evasion. The fix is to make session evidence explicit enough that operators can distinguish policy, state, rendering, extraction, and transport failures.

What changed this week

Precursor is important because it emphasizes continuous, session-level behavior rather than a one-time request verdict. That matters for browser automation and agent browsing because the unit of work is rarely one request. A realistic task might load a page, wait for hydration, follow an internal link, trigger a search, accept a consent dialog, inspect an API response, and extract a table. Any one of those steps can change the policy context.

The MCP elicitation update points in the same direction from the agent side. An MCP-connected tool can now ask an agent client for structured input such as form or URL elicitation. That makes agent workflows more interactive and stateful. It also means that reliable logs need to show where information came from: user-provided input, tool-provided context, page-observed state, or an agent decision.

Markdown for Agents preserving security and cache headers is a different but related signal. Agent-facing content representations are no longer just convenience transforms. If converted Markdown carries origin content signals, security headers, and cache semantics, then an agent fetcher that ignores those headers can make the wrong freshness, compliance, or storage decision even when the body text looks correct.

The WAF release is the background drumbeat: managed rules evolve. A production fetch pipeline should expect policy outcomes to drift over time, especially around automated traffic, APIs, forms, and high-risk routes. Without versioned evidence, teams over-attribute every change to proxies, browser fingerprints, or parser regressions.

The failure mode: request logs pretending to be session logs

Most crawler observability starts at the request boundary. That is useful for cheap HTTP fetches, but it is too narrow for browser-grade and agentic work. Consider four incidents that look similar in a dashboard:

SymptomLikely missing evidenceBetter interpretation
First page returns 200, second step gets challengedSession timeline, interaction count, challenge eventPolicy changed after behavior, not after URL
HTML extraction succeeds, Markdown extraction is staleCache headers on converted responseRepresentation freshness differs
Agent submits the wrong form valueElicitation source and approval traceTool input provenance failed
Regional crawl starts seeing more blocksWAF/ruleset timestamp, bot score class, routePolicy drift, not necessarily network failure

The common problem is flattening a journey into independent fetches. Once the system does that, retries become misleading. Retrying the challenged step with a new browser may hide that the original session crossed a policy boundary. Retrying a Markdown conversion may hide that the converted representation carried a cache directive the pipeline ignored. Retrying an agent task may hide that the wrong input was elicited or accepted.

A session-evidence checklist

For Better Fetch-style infrastructure, add a session record beside individual request records. It does not need to store sensitive content or violate site policy. It should record enough operational metadata to explain what happened without teaching the system to defeat access controls.

Log these fields for browser and agent fetches:

  • session_id, task_id, and attempt_id, with a parent-child relationship between task, page steps, and network requests.
  • Client runtime: browser family, browser version, automation library version, headless/headed mode, device profile, viewport, locale, timezone, and whether extensions or special permissions were enabled.
  • State inputs: cookie jar identifier, storage partition, consent state, authenticated/not-authenticated classification, region, and declared purpose or crawl policy label.
  • Step timeline: navigation start, DOM ready, hydration signal, user/agent action, API discovery event, challenge/redirect/interstitial event, extraction start, extraction end.
  • Policy evidence: status code, final URL, redirect count, challenge page classification, robots or publisher policy decision, WAF/challenge category if visible to the site owner, and whether the run stopped for policy rather than technical failure.
  • Representation evidence: HTML, JSON, screenshot, PDF, or Markdown; converter version; cache headers; security headers; content hash; extracted-record count; schema validation result.
  • Agent evidence: tool name, MCP server identity, elicitation type, approval state, input provenance, and whether the agent saw browser DOM, converted Markdown, API JSON, or a screenshot.
  • Safety outcome: allowed, skipped by policy, requires human review, target unavailable, parser failed, or infrastructure failed.

The point is not to collect everything forever. The point is to preserve the minimum evidence needed to replay and classify failures. Retention can be short, hashes can replace bodies, and sensitive values should be redacted. But the relationship between actions, state, and outcomes should survive.

Tests worth adding now

Use the current Cloudflare changes as a prompt to test your own fetch contract, even if you do not sit behind Cloudflare and even if most targets are not using agent-specific content yet.

First, run a multi-step canary instead of a single URL canary. Pick representative pages that require navigation, filtering, pagination, or consent. Assert not just final status, but the sequence of events: redirects, challenges, API calls discovered, rendered record count, and extraction schema.

Second, compare representations. For a small set of pages, capture browser-rendered HTML, direct HTTP HTML, discovered API JSON, and any agent-oriented Markdown representation you intentionally use. Store content hashes and key headers. Alert when the body is stable but headers change in ways that affect caching, security, or policy.

Third, separate policy stops from technical failures. A respectful crawler should be able to say "we stopped because access policy changed" without turning that into a proxy-rotation incident. That means operators need failure codes such as policy_challenge, publisher_disallowed, requires_login, consent_unresolved, agent_input_required, renderer_timeout, and extractor_schema_mismatch.

Fourth, test elicitation paths. If an agent can request form input, URL input, or other structured data through MCP, treat that as a data provenance event. Record what was requested, which tool requested it, whether a human or upstream system approved it, and which downstream fetches depended on it. That is useful for debugging and for preventing silent credential or personal-data leakage.

Decision rule for operators

When a browser or agent fetch fails, ask one question before changing retries: did the failure attach to a request, a session, a representation, or an agent decision?

If it attaches to a request, inspect transport, status, redirects, and headers. If it attaches to a session, inspect cookies, storage, interaction sequence, consent, and challenge state. If it attaches to a representation, inspect conversion, caching, security headers, and extractor assumptions. If it attaches to an agent decision, inspect tool context, elicitation, approval, and observation quality.

That decision rule keeps teams from using a single lever for every failure. More retries will not fix stale converted content. A browser upgrade will not fix missing input provenance. A proxy change will not fix a publisher policy stop. A parser patch will not fix a session-level challenge.

The durable lesson from this week's updates is that the web-data surface is becoming more stateful, not less. Agent tools, bot-management systems, WAF releases, and content representations are all adding more context around a fetch. Production systems that make that context observable will debug faster, respect policy more consistently, and produce data quality reports that explain why a result changed instead of merely reporting that it did.