CrawlForge MCP
Basic ToolMulti-Format2 credits

scrape

Ask one page load for markdown, HTML, raw HTML, plain text, links and metadata at once. Every requested format is derived from the same fetch and returned together under formats, so asking for six costs exactly what asking for one costs. Add a highlights or question format with a query to get only the matching sentences, table rows and code blocks — verbatim page text with an offset into the markdown, no model in the path — for 1 credit more. Pass escalate: true and a page that comes back as a bot wall instead of the page is re-fetched once through the stealth browser inside the same call, for 5 credits more.

Use Cases

One Call Instead of Four

Get markdown, links, and metadata from a page in a single request instead of chaining fetch_url, extract_links, and extract_metadata.

LLM-Ready Markdown

Request markdown with onlyMainContent enabled to feed clean, boilerplate-free page text straight into a RAG pipeline or prompt.

Archival Snapshots

Ask for rawHtml and markdown together to keep the exact source alongside a clean reading copy, from a single fetch.

One Fetch, Many Formats

Six formats cost the same 2 credits as one, so a pipeline that needs markdown, links and metadata should ask for all three in a single call rather than three.

Quote the Page, Don't Summarise It

Ask for highlights with a query, or question with a question, to get only the sentences, table rows and code blocks that match — verbatim page text with an offset into the markdown of the same call, so an agent quotes the source instead of paraphrasing it. Unlike summarising fetch tools, no model is in the path.

Endpoint

POST/api/v1/tools/scrape
Auth Required
1 req/s on Free plan
2 credits

Parameters

Every requested format is served from a single page fetch, so asking for six formats costs the same 2 credits as asking for one. A query-scoped highlights or question format adds 1 credit, charged once per request whether you include one or both. With escalate: true the projection is the ceiling at 7 credits, 8 alongside a query-scoped format; the escalation stage's 5 credits are charged only when the plain fetch was walled and the stage actually ran.
NameTypeRequiredDefaultDescription
url
stringRequired-
The URL to scrape (must include protocol: http:// or https://)
Example: https://example.com
formats
arrayOptional["markdown"]
Output formats to return. One or more of `markdown`, `html`, `rawHtml`, `text`, `links`, `metadata`, plus two query-scoped object formats: `{ "type": "highlights", "query": "…", "max_highlights": 10, "mode": "extractive" }` returns the sentences and code blocks that best match `query` (`max_highlights` 1–50, default 10) — `kind` is `sentence` or `code_block` on the hosted REST API; `table_row` units come from the MCP server, whose markdown keeps tables as pipe rows, whereas the REST API flattens tables to text — and `{ "type": "question", "question": "…", "mode": "extractive" }` returns an `answer` assembled from the best-matching passages. Both return verbatim page text; each unit carries an `offset` and `length` into the `markdown` format of the same call (same `onlyMainContent` setting), so also ask for `markdown` to quote with a locator. `mode: "model"` is rejected here with 400 — it needs an LLM and is available on the MCP server only. `screenshot` and `json-schema` pass validation but are then rejected with 400 — they need a browser or an LLM, which the hosted REST API does not provide.
Example: ["markdown", { "type": "highlights", "query": "Starter plan price" }, { "type": "question", "question": "How much does the Starter plan cost?" }]
onlyMainContent
booleanOptionaltrue
Strip navigation, headers, and footers so only the main article content is returned.
Example: true
escalate
booleanOptionalfalse
Opt in to one automatic retry through the stealth browser when the plain fetch comes back as a bot wall instead of the page — a Cloudflare, Amazon, DataDome, PerimeterX, Akamai or Vercel challenge page, an empty shell, or a short error-titled placeholder. The plain fetch always runs first; only when it is walled does the same call render the page with the stealth browser and derive every requested format from what it rendered, so a blocked page costs one call instead of two. Escalation reuses the same stealth path as [stealth_mode](/docs/api-reference/tools/stealth-mode) and the same robots.txt gate, and adds no new handling of a bot defence. A wall the stealth render is refused at too still comes back as a blocked page, carrying `escalated: true` and charged nothing: escalation saves the second round trip, it does not promise the page. It is most reliable where the plain fetch failed only because the page needs JavaScript to render. The response then carries `escalated`, and `stealth` when that is `true`. Adds 5 credits, charged only when the escalation stage actually runs. On the MCP server only, a host that walled a request is remembered for 24 hours, so the next `escalate: true` call to that host skips the doomed plain fetch and says so in a warning.
Example: true
escalate_engine
stringOptionalplaywright
Browser engine for the escalation stage: "playwright" (default) or "camoufox" (Firefox-based, stronger anti-detection; available only where installed on the backend). Ignored unless `escalate` is `true` and the plain fetch was walled.
Example: camoufox
respect_robots
booleanOptionaltrue
Respect the target site's robots.txt. Left at `true`, a path disallowed for `CrawlForge` is refused with 403 before anything is fetched and no credits are charged. Set it to `false` only for a target you have your own agreement with — the response then carries a `warnings` entry and the override is recorded against your API key.
Example: true
max_inline_chars
numberOptional40000
Largest result to return inline, in characters of its JSON (1,000-10,000,000). Over it the response carries `preview` (the first `max_inline_chars` characters of the markdown), `result_handle`, `total_chars`, `truncated: true` and `expires_at`, and [read_result](/docs/api-reference/tools/read-result) reads the rest for 1 credit per call. Stored results are kept for 1 hour.
Example: 40000
redact_pii
boolean | objectOptionalfalse
Remove personal data from the text this call returns, before the result is stored or sent back. `true` is shorthand for `{ mode: "fast" }` — all four regex classes, tagged. Whenever you ask for redaction the response carries `redaction: { entities, count, mode }` inside `data`, even when nothing matched (`count: 0`), so "found nothing" is never mistaken for "the parameter was ignored"; a class with no hits is left out rather than reported as `0`. Redaction runs **before** the result is stored, so an oversized result read back later with [read_result](/docs/api-reference/tools/read-result) is already redacted. Two deliberate limits: addresses (`url`, `link`, `href`, `canonical_url`) are never redacted, and counters derived from the text (`content_length`, `word_count`, `character_count`) describe it as extracted, before redaction.
Example: true

Request Examples

cURL

terminalBash
curl -X POST https://crawlforge.dev/api/v1/tools/scrape \
  -H "X-API-Key: cf_test_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "formats": [
      "markdown", "links", "metadata",
      { "type": "highlights", "query": "professional plan price per month" }
    ],
    "onlyMainContent": true,
    "escalate": true
  }'

TypeScript

scrape.tsTypescript
// npm install crawlforge-sdk
import { CrawlForge, ToolError } from 'crawlforge-sdk';

const client = new CrawlForge({ apiKey: process.env.CRAWLFORGE_API_KEY });

try {
  const result = await client.scrape({
    url: 'https://example.com',
    formats: [
      'markdown', 'links', 'metadata',
      // 1 extra credit: the matching sentences, table rows and code blocks, verbatim, with offsets
      { type: 'highlights', query: 'professional plan price per month' },
    ],
    onlyMainContent: true,
    // Only when the plain fetch meets a bot wall: one stealth render in this same call (5 extra credits)
    escalate: true,
  });

  // result.data is untyped in crawlforge-sdk 0.1 — its shape is the Response Example below.
  const { formats } = result.data as {
    formats: { markdown: string; links: string[]; metadata: { title: string }; highlights: { text: string }[] };
  };
  console.log('Markdown:', formats.markdown);
  console.log('Links found:', formats.links.length);
  console.log('Title:', formats.metadata.title);
  // Each highlight is verbatim page text; offset/length index formats.markdown.
  console.log('Best match:', formats.highlights[0]?.text);

  // A success with warnings is a PARTIAL result — some formats came back, others didn't.
  if (result.warnings.length > 0) {
    console.warn('Partial result:', result.warnings);
  }

  console.log('Credits used:', result.creditsUsed);
  console.log('Credits remaining:', result.creditsRemaining);
} catch (err) {
  // A bot wall the stealth render could not pass either: not charged, blocked.vendor names it.
  if (err instanceof ToolError && err.blocked) {
    console.error('Blocked by', err.blocked.vendor, '— escalated:', err.escalated);
  } else {
    throw err;
  }
}

Python

scrape.pyPython
# pip install crawlforge
from crawlforge import CrawlForge, ToolError

client = CrawlForge()  # reads CRAWLFORGE_API_KEY

try:
    result = client.scrape(
        url='https://example.com',
        formats=[
            'markdown', 'links', 'metadata',
            # 1 extra credit: the matching sentences, table rows and code blocks, verbatim, with offsets
            {'type': 'highlights', 'query': 'professional plan price per month'},
        ],
        onlyMainContent=True,
        # Only when the plain fetch meets a bot wall: one stealth render in this same call (5 extra credits)
        escalate=True,
    )
except ToolError as e:
    # A bot wall the stealth render could not pass either: not charged, blocked names the vendor.
    print(f"Blocked: {e.blocked} (escalated: {e.escalated})")
    raise

# result.data is a plain dict — its shape is the Response Example below.
formats = result.data['formats']
print(f"Markdown: {formats['markdown']}")
print(f"Links found: {len(formats['links'])}")
print(f"Title: {formats['metadata']['title']}")
# Each highlight is verbatim page text; offset/length index formats['markdown'].
print(f"Best match: {formats['highlights'][0]['text']}")

# A success with warnings is a PARTIAL result — some formats came back, others didn't.
if result.warnings:
    print(f"Partial result: {result.warnings}")

print(f"Credits used: {result.credits_used}")
print(f"Credits remaining: {result.credits_remaining}")

Response Example

200 OK4218ms
{
"success": true,
"data": {
"url": "https://example.com",
"formats": {
"markdown": "# Example\n\nMain content scraped from https://example.com. The Starter plan costs $12 per month and includes three seats. Annual billing lowers the Starter plan to $10 per month.",
"highlights": [
{
"text": "The Starter plan costs $12 per month and includes three seats.",
"kind": "sentence",
"offset": 58,
"length": 62,
"score": 6.612
},
{
"text": "Annual billing lowers the Starter plan to $10 per month.",
"kind": "sentence",
"offset": 121,
"length": 56,
"score": 5.809
}
],
"answer": {
"text": "The Starter plan costs $12 per month and includes three seats.",
"grounded": true,
"evidence": [
{
"text": "The Starter plan costs $12 per month and includes three seats.",
"kind": "sentence",
"offset": 58,
"length": 62,
"score": 6.612
}
]
}
},
"escalated": true,
"stealth": {
"engine": "playwright",
"vendor_detected": "cloudflare"
},
"scraped_at": "2026-08-26T14:30:00.000Z"
},
"credits_used": 8,
"credits_remaining": 992,
"processing_time": 4218
}
Field Descriptions
data.urlThe URL that was fetched.
data.formatsOne key per requested format — the extracted content lives in here, not at the top level of data.
data.formats.markdownMain content converted to markdown (present when `markdown` is requested).
data.formats.highlightsThe top-ranked sentences and code blocks matching `query`, verbatim (present when a `highlights` format is requested). Each unit carries `text`, `kind` (`sentence` or `code_block` on the hosted REST API; `table_row` units come from the MCP server, whose markdown keeps tables as pipe rows, whereas the REST API flattens tables to text), `offset`, `length` and `score` — a raw BM25 relevance value, meaningful for ordering only, not a 0–1 confidence.
data.formats.highlights.offsetCharacter index into the `markdown` format of the same call (same `onlyMainContent` setting): `markdown.slice(offset, offset + length) === text`.
data.formats.answerThe answer to `question` (present when a `question` format is requested): `text` is the best-matching evidence joined, and `evidence` lists up to 5 supporting units.
data.formats.answer.groundedAlways `true` on the REST API — the text is verbatim page content, nothing is synthesised.
data.escalatedWhether the escalation stage ran (present only when the request passed `escalate: true`). `false` means the plain fetch returned the page and only the base cost was charged.
data.stealthHow the page was rendered (present only when `escalated` is `true`): `engine` is the browser that ran, and `vendor_detected` names the bot-defence vendor the plain fetch hit — `cloudflare`, `amazon`, `datadome`, `perimeterx`, `akamai` or `vercel` — or `null` when the wall was an empty shell or an error placeholder rather than a named challenge.
data.scraped_atISO 8601 timestamp of the fetch.
credits_usedCredits deducted for this request — 2 per scrape, regardless of how many formats you asked for, plus 1 when a `highlights` or `question` format is included, plus 5 when the escalation stage ran. Here: 2 + 1 + 5.
credits_remainingYour remaining credit balance.

Error Handling

Invalid Input (400 Bad Request)

The URL format is invalid, formats contains a value outside the supported list, or a highlights or question format asks for mode: "model", which needs an LLM and is available on the MCP server only. At least one format is required when the field is supplied.

URL Blocked (403 Forbidden)

The target resolved to a private, internal, or link-local address and was rejected by SSRF protection. Only publicly reachable URLs can be scraped.

Insufficient Credits (402 Payment Required)

Your account doesn't have enough credits. Purchase more credits or upgrade your plan.

Rate Limit Exceeded (429 Too Many Requests)

You've exceeded your plan's rate limit. Wait a moment or upgrade your plan for higher limits.

Escalation Backend Not Configured (503 TOOL_NOT_AVAILABLE)

escalate: true runs its stealth stage on the CrawlForge execution backend. When that backend is not configured the stage returns 503 and no credits are charged for it.

Blocked by robots.txt (403 Forbidden)

The target site's robots.txt disallows this path for CrawlForge. Set respect_robots: false to override if you have your own agreement with the target — the override is recorded against your API key. The override does not reach a host on CrawlForge's permanent opt-out list, which is refused whatever respect_robots is set to.

Pro Tip: Requesting markdown, links and metadata together costs the same 2 credits as requesting one — every format is derived from a single page load. Ask for everything you might need in one call; a highlights or question format adds 1 credit once, not per format.

Credit Cost

2 credits
2 credits per request
Each successful scrape request costs 2 credits no matter how many formats you request, because every format is served from one fetch. A highlights or question format adds 1 credit, charged once per request whether you include one or both. A call with escalate: true projects up to 7 credits, 8 alongside a query-scoped format, and pays the 5-credit escalation add-on only when the plain fetch came back as a bot wall and the stealth stage ran — never more than the projection.

Free Plan: 1,000 one-time credits = 500 requests

Hobby Plan: 5,000 credits/month = 2,500 requests ($19/mo)

Professional Plan: 50,000 credits/month = 25,000 requests ($99/mo)

Business Plan: 250,000 credits/month = 125,000 requests ($399/mo)

Related Tools

fetch_url
Raw HTTP fetch when you want the untouched response body (1 credit)
extract_content
Readability-based main-content extraction for a single page (2 credits)
batch_scrape
Run the same extraction across many URLs as an async job (5 credits)
scrape_with_actions
Click, scroll, or fill forms before scraping a JS-heavy page (5 credits)
Ready to try scrape? Sign up for free and get 1,000 credits to start building.

Footer

CrawlForge MCP

Enterprise web scraping for AI Agents. 30 specialized MCP tools designed for modern developers building intelligent systems.

Product

  • Features
  • Playground
  • Pricing
  • Use Cases
  • Integrations
  • Alternatives
  • Changelog

Resources

  • Getting Started
  • API Reference
  • Templates
  • Guides
  • Blog
  • Glossary
  • FAQ
  • Sitemap

Developers

  • MCP Protocol
  • Claude Desktop
  • Cursor IDE
  • LangChain
  • LlamaIndex

Company

  • About
  • Contact
  • Privacy
  • Terms
  • Acceptable Use
  • Security
  • Cookies

Stay updated

Get the latest updates on new tools and features.

Built with Next.js and MCP protocol

© 2025-2026 CrawlForge. All rights reserved.