Structured Data Extraction From Any Website (Custom Schema)
omnial/web-extract
Given a starting URL and a JSON Schema you supply, crawls the site and returns one JSON object shaped exactly like your schema, filled in from the page content -- plus crawl stats (pages found/succeeded/failed/skipped) and cache status. An unreachable or invalid URL returns an error code and message instead.
Price
$0.0346 per call
You pay the price shown. If a call turns out to cost more than its quote, you pay the actual price, capped at twice the quote. No monthly minimum. Top-ups start at $5.00.
Data source
Data from the web page you request.
Use it
Your AI assistant does the work: it finds this tool, shows you the price first, runs it, and you are charged when the run finishes. There is nothing to set up for this tool in particular.
Connect once and your AI can find and run this tool, and any other it needs.
For developers: the calls your assistant makes
// 1. search: find the tool
omnial_search({ query: "what you need" })
// 2. inspect: price and input schema
omnial_inspect({ tool: "omnial/web-extract" })
// 3. learn: read the usage guide at runtime
omnial_learn({ tool: "omnial/web-extract" })
// 4. run: price the exact call first, then run it
omnial_execute({ tool: "omnial/web-extract", input: { /* see input_schema */ }, dry_run: true })
omnial_execute({ tool: "omnial/web-extract", input: { /* ... */ } })
// 5. settle: the call is charged when it finishes, nothing to doNot connected yet? Point your MCP client at https://mcp.eden-engine.com/mcp, then copy a config for your client.
Pricing
Every charge this tool can incur.
| Charge | Price |
|---|---|
Per call | $0.0346 |
- Updated
- Oct 27, 2026
Input and output schemas
Input schema
{
"type": "object",
"required": [
"url",
"schema"
],
"properties": {
"url": {
"type": "string",
"format": "uri",
"description": "Starting website URL to crawl and extract from."
},
"schema": {
"type": "object",
"description": "JSON Schema describing the object to return. Generate it from a Zod or Pydantic model, or hand-write it — the upstream service fills exactly this shape.",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
},
"maxAgeMs": {
"type": "integer",
"default": 86400000,
"maximum": 2592000000,
"minimum": 0,
"description": "Reuse a cached result younger than this many milliseconds. Default 86400000 (1 day), max 2592000000 (30 days). Set 0 to always fetch fresh."
},
"maxDepth": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 0,
"description": "Maximum link depth from the starting URL (0 = only the starting page). Unlimited when omitted."
},
"maxPages": {
"type": "integer",
"default": 5,
"maximum": 50,
"minimum": 1,
"description": "Maximum number of pages to analyze. Default 5, hard cap 50."
},
"factCheck": {
"type": "boolean",
"description": "When true, every returned value must be grounded in text stated on the page and unsupported fields come back null/empty. When false (default), reasonable inferences are allowed while verifiable specifics stay faithful to the source."
},
"timeoutMS": {
"type": "integer",
"maximum": 300000,
"minimum": 1000,
"description": "Upstream timeout in milliseconds (max 300000). The upstream service aborts the call with a 408 when exceeded. Keep it below the endpoint's requestTimeoutMs so the provider answers before the platform's own budget expires."
},
"waitForMs": {
"type": "integer",
"maximum": 30000,
"minimum": 0,
"description": "Extra browser wait in milliseconds after page load before the content is captured (0-30000). Useful for JavaScript-heavy pages."
},
"stopAfterMs": {
"type": "integer",
"default": 80000,
"maximum": 110000,
"minimum": 10000,
"description": "Soft time budget for the crawl phase in milliseconds (10000-110000, default 80000)."
},
"instructions": {
"type": "string",
"maxLength": 2000,
"description": "Extraction guidance: which facts to prioritize, how to interpret ambiguous fields."
},
"includeFrames": {
"type": "boolean",
"default": false,
"description": "Include iframe contents in the Markdown handed to the extractor. Default false."
},
"followSubdomains": {
"type": "boolean",
"default": false,
"description": "Follow links on subdomains of the starting URL's domain. Default false."
},
"settleAnimations": {
"type": "boolean",
"default": false,
"description": "Wait briefly for animations to settle before each page is read. Default false."
}
},
"additionalProperties": false
}Output schema
{
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "Present instead of status/data/metadata when the request errors -- observed as 'HTTP_400' for an unreachable/invalid domain."
},
"data": {
"type": "object",
"description": "The extracted record. Its keys and value types are whatever the caller's own `schema` input requested for that call -- there is no fixed shape here, by design (e.g. a schema requesting {companyName, tagline, industry} returns exactly those keys, all strings). Only ever observed as a plain object, never null or an array at the top level.",
"additionalProperties": true
},
"status": {
"type": "string",
"description": "Present on a successful call. Typically 'ok'."
},
"message": {
"type": "string",
"description": "Human-readable error message accompanying `code`."
},
"metadata": {
"type": "object",
"properties": {
"numUrls": {
"type": "number",
"description": "Total URLs the crawl considered."
},
"numFailed": {
"type": "number",
"description": "Pages that failed to fetch."
},
"numBlocked": {
"type": "number",
"description": "Pages blocked from fetching (e.g. robots rules)."
},
"numSkipped": {
"type": "number",
"description": "Pages found but not fetched (e.g. over the page/depth limit)."
},
"numSucceeded": {
"type": "number",
"description": "Pages successfully fetched and read."
},
"maxCrawlDepth": {
"type": "number",
"description": "Deepest link level actually reached during this crawl."
}
},
"description": "Crawl statistics for the pages the extraction visited.",
"additionalProperties": true
},
"cache_metadata": {
"type": "object",
"properties": {
"age_ms": {
"type": "number",
"description": "Age of the cached result in milliseconds, 0 on a fresh fetch (miss)."
},
"status": {
"type": "string",
"description": "Observed value: \"miss\" (freshly fetched). \"hit\" is documented but unconfirmed here."
}
},
"description": "Whether this result was served from cache or freshly fetched.",
"additionalProperties": true
}
},
"description": "The extraction result on a successful crawl, or an error code/message when the request itself fails (e.g. an unreachable domain).",
"additionalProperties": true
}