Skip to main content
Glama
CrawlForge MCP Server

CrawlForge MCP Server

extract_embedded_state

Read-onlyIdempotent

Use this when a page's data lives in its embedded JavaScript state rather than its rendered HTML - Next.js (NEXT_DATA, and React Server Component payloads with references between rows resolved plus a data_rows index of the rows…

Instructions

Use this when a page's data lives in its embedded JavaScript state rather than its rendered HTML - Next.js (NEXT_DATA, and React Server Component payloads with references between rows resolved plus a data_rows index of the rows carrying data), Nuxt (Nuxt 3's NUXT_DATA decoded), SvelteKit, Apollo, Redux (INITIAL_STATE, PRELOADED_STATE), ytInitialData and ytInitialPlayerResponse, Inertia, Shopify, JSON data-* attributes and blocks. One fetch, exact values, no LLM in the extraction path, so nothing can be fabricated. Payloads are routinely over a megabyte - pass path to return one subtree, keys_only:true to see the first two levels of keys before choosing one, or find:"" to get every path where a field of that name lives, each ready to pass back as path. A result over max_inline_chars comes back as a preview (whole lines of the JSON), data_keys and a result_handle; read the rest with read_result json_path, e.g. "data.next_data.props". Set escalate:true when the site is known to block: the plain fetch still runs first, and only if it is walled does the stealth browser re-read the page, run the same parser and also read the globals off window (window_state: NEXT_DATA, NUXT, ytInitialData and others, read after JavaScript ran) - projected at 7, charged 2 when the plain fetch worked. Not for the rendered text of a page (scrape) or for sites built without a framework payload. Asking again for the same page with different formats, paths or selectors reuses this session's copy for 10 minutes at 1 credit; pass maxAge: 0 to force a fresh fetch. Cost: 2 credits. Example: extract_embedded_state({url: "https://www.ticketmaster.com/discover/concerts", path: "next_data.props.pageProps"})

Input Schema

NameRequiredDescriptionDefault
rawNoAlso keep the undecoded __NUXT_DATA__ devalue array under json_scripts, beside the decoded nuxt_data. Default: false
urlYesThe URL to read embedded state from
findNoReturn `matches` instead of `data`: every property with this key name (case-insensitive) anywhere in the selected data (after `path`), in document order, each as {path, preview} with the first 200 characters of its value - at most 50, with `matches_total` and `matches_truncated`. Each match path already starts with `path`, so it can be passed straight back as `path`. Discover where a field lives without downloading the payload. Cannot be combined with keys_only
pathNoReturn only this subtree instead of the whole payload. Dotted keys and array indexes, e.g. "next_data.props.pageProps" or "next_f[0].f" — not JSONPath (no wildcards, filters or recursion). State payloads are routinely over a megabyte; scope them.
maxAgeNoReuse this session's copy of the page if it was fetched within this many ms (default 600000 = 10 min); 0 always fetches fresh.
escalateNoWhen the plain fetch comes back blocked (403/429/challenge page, or an empty shell with no state), re-read the page once in the stealth browser and run the same parser on the rendered document; the browser also reads the framework globals off window (window_state). Under escalate_engine "auto" a Chrome TLS handshake with the honest CrawlForge User-Agent (impit) is tried first, and the browser runs only when that does not get the page. A 404 or 5xx never escalates. Projected at 2+5; the actual charge stays at 2 when the plain fetch succeeded. Default: false
wait_forNoEscalated render only: extra wait after page load, in ms — for state assigned after DOMContentLoaded. Ignored without escalation
keys_onlyNoReturn `keys` instead of `data`: the first two levels of keys of the selected data (after `path`), each value replaced by its type ("object", "array(<n>)", "string", "number", "boolean", "null"); an array shows its length and its first item. Cheap discovery before choosing a path. Default: false
user_agentNoOverride the outbound User-Agent. CrawlForge identifies itself honestly by default; use this only for targets you have your own agreement with.
respect_robotsNoRespect the target site's robots.txt (default: true). Setting this to false is honoured, returns a warning in the response, and is recorded against your API key — it is your decision, not a silent default.
escalate_engineNoStealth engine for the escalated retry: "auto" (default — Camoufox when it is installed, Chromium otherwise, reported in warnings), "playwright" (Chromium) or "camoufox"auto
max_inline_charsNoLargest result to return inline, in characters of its JSON. Over it, the call returns a preview plus a result_handle for read_result instead of the whole result (default 40,000; env CRAWLFORGE_MAX_INLINE_CHARS)

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changedv6.24.0
    • addedInput schema / properties / maxAge
      Added value: +{
      +  "description": "Reuse this session's copy of the page if it was fetched within this many ms (default 600000 = 10 min); 0 always fetches fresh.",
      +  "maximum": 9007199254740991,
      +  "minimum": 0,
      +  "type": "integer"
      +}
  2. Changed2 schema fields changedv6.18.1
    • addedInput schema / properties / find
      Added value: +{
      +  "description": "Return `matches` instead of `data`: every property with this key name (case-insensitive) anywhere in the selected data (after `path`), in document order, each as {path, preview} with the first 200 characters of its value - at most 50, with `matches_total` and `matches_truncated`. Each match path already starts with `path`, so it can be passed straight back as `path`. Discover where a field lives without downloading the payload. Cannot be combined with keys_only",
      +  "maxLength": 100,
      +  "minLength": 1,
      +  "type": "string"
      +}
    • addedInput schema / properties / raw
      Added value: +{
      +  "default": false,
      +  "description": "Also keep the undecoded __NUXT_DATA__ devalue array under json_scripts, beside the decoded nuxt_data. Default: false",
      +  "type": "boolean"
      +}
  3. Changed4 schema fields changedv6.14.0
    • addedInput schema / properties / escalate
      Added value: +{
      +  "default": false,
      +  "description": "When the plain fetch comes back blocked (403/429/challenge page, or an empty shell with no state), re-read the page once in the stealth browser and run the same parser on the rendered document; the browser also reads the framework globals off window (window_state). Under escalate_engine \"auto\" a Chrome TLS handshake with the honest CrawlForge User-Agent (impit) is tried first, and the browser runs only when that does not get the page. A 404 or 5xx never escalates. Projected at 2+5; the actual charge stays at 2 when the plain fetch succeeded. Default: false",
      +  "type": "boolean"
      +}
    • addedInput schema / properties / escalate_engine
      Added value: +{
      +  "default": "auto",
      +  "description": "Stealth engine for the escalated retry: \"auto\" (default — Camoufox when it is installed, Chromium otherwise, reported in warnings), \"playwright\" (Chromium) or \"camoufox\"",
      +  "enum": [
      +    "auto",
      +    "playwright",
      +    "camoufox"
      +  ],
      +  "type": "string"
      +}
    • addedInput schema / properties / keys_only
      Added value: +{
      +  "default": false,
      +  "description": "Return `keys` instead of `data`: the first two levels of keys of the selected data (after `path`), each value replaced by its type (\"object\", \"array(<n>)\", \"string\", \"number\", \"boolean\", \"null\"); an array shows its length and its first item. Cheap discovery before choosing a path. Default: false",
      +  "type": "boolean"
      +}
    • addedInput schema / properties / wait_for
      Added value: +{
      +  "description": "Escalated render only: extra wait after page load, in ms — for state assigned after DOMContentLoaded. Ignored without escalation",
      +  "maximum": 30000,
      +  "minimum": 0,
      +  "type": "number"
      +}
  4. Changed2 schema fields changedv6.0.0
    • removedInput schema / additionalProperties
      Removed value: -false
    • addedInput schema / properties / max_inline_chars
      Added value: +{
      +  "description": "Largest result to return inline, in characters of its JSON. Over it, the call returns a preview plus a result_handle for read_result instead of the whole result (default 40,000; env CRAWLFORGE_MAX_INLINE_CHARS)",
      +  "maximum": 10000000,
      +  "minimum": 1000,
      +  "type": "integer"
      +}
  5. Addedv5.4.0

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare read-only, idempotent, open-world behavior, but the description goes further: exact values with no LLM in the extraction path, large-payload handling via previews and result handles, cache reuse for 10 minutes, and escalation behavior with projected versus actual cost. These are meaningful operational traits beyond the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core use case and alternatives, and every part is relevant to calling the tool correctly. It is dense and somewhat long, with some repetition of schema-level details, but the length is justified by the tool's complexity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 12-parameter extraction tool with no output schema, the description covers framework scope, extraction guarantees, large-result handling, caching, escalation behavior, and cost. An agent has enough context to invoke it correctly without opening sibling tools.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents all 12 parameters thoroughly. The description still adds useful cross-parameter workflow guidance: use keys_only for discovery, find to locate matching paths, path to scope large payloads, and read_result for oversized results.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action and resource: extracting a page's embedded JavaScript framework state. It explicitly distinguishes this from rendered-text scraping and from sites without a framework payload, so an agent can select it confidently.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives a clear triggering condition (data lives in embedded JS state), lists concrete frameworks and payload names, and explicitly excludes the sibling use cases: rendered text should use scrape, and framework-less sites are out of scope. It also explains when to use path, keys_only, find, and escalate.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.