<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Simon</title>
    <description>The latest articles on DEV Community by Simon (@simon_crawlforge_dev).</description>
    <link>https://dev.to/simon_crawlforge_dev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3846482%2F9fdf4e37-2a8c-49ba-a3e2-dead13e04551.jpg</url>
      <title>DEV Community: Simon</title>
      <link>https://dev.to/simon_crawlforge_dev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/simon_crawlforge_dev"/>
    <language>en</language>
    <item>
      <title>We stopped trusting our test suite and pointed 28 tools at the real web</title>
      <dc:creator>Simon</dc:creator>
      <pubDate>Wed, 26 Aug 2026 19:24:33 +0000</pubDate>
      <link>https://dev.to/simon_crawlforge_dev/we-stopped-trusting-our-test-suite-and-pointed-28-tools-at-the-real-web-25eb</link>
      <guid>https://dev.to/simon_crawlforge_dev/we-stopped-trusting-our-test-suite-and-pointed-28-tools-at-the-real-web-25eb</guid>
      <description>&lt;p&gt;Every one of our &lt;code&gt;amazon-product&lt;/code&gt; tests passed. The tool returned &lt;code&gt;null&lt;/code&gt; for the price currency, &lt;code&gt;null&lt;/code&gt; for the rating, &lt;code&gt;null&lt;/code&gt; for every image, and the string &lt;code&gt;"Brand: Amazon"&lt;/code&gt; where the brand should have been.&lt;/p&gt;

&lt;p&gt;Nothing looked broken in CI, because the fixtures had been written to match the selectors instead of the site. The tests were checking that our code agreed with itself.&lt;/p&gt;

&lt;p&gt;So over two days we ran all 28 tools of &lt;strong&gt;&lt;a href="https://www.crawlforge.dev" rel="noopener noreferrer"&gt;CrawlForge&lt;/a&gt; MCP&lt;/strong&gt; against real sites — Wikipedia, Hacker News, Amazon, Shopify storefronts, npm, YouTube, GitHub, Reddit, an IRS PDF — and shipped six releases: v5.2.0 through v5.2.5, plus four releases of the shared &lt;code&gt;crawlforge-extractors&lt;/code&gt; package.&lt;/p&gt;

&lt;p&gt;This is the whole set, organised by what it does rather than by version number.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Why six passing tests meant nothing&lt;/li&gt;
&lt;li&gt;Product data from the source&lt;/li&gt;
&lt;li&gt;Reddit-wide search after PullPush went dark&lt;/li&gt;
&lt;li&gt;Change tracking that actually fires&lt;/li&gt;
&lt;li&gt;Content that was being deleted&lt;/li&gt;
&lt;li&gt;Local LLMs finally work&lt;/li&gt;
&lt;li&gt;Browser automation and the stealth wedge&lt;/li&gt;
&lt;li&gt;Language detection and PDF tables&lt;/li&gt;
&lt;li&gt;One copy of the extractors&lt;/li&gt;
&lt;li&gt;How to upgrade&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
&lt;strong&gt;TL;DR&lt;/strong&gt; — v5.2 is six releases shipped after a live sweep of all 28 tools. New: a &lt;code&gt;shopify-product&lt;/code&gt; template reading a store's own JSON, templates that can fetch any machine-readable endpoint, &lt;code&gt;responseTime&lt;/code&gt; on &lt;code&gt;fetch_url&lt;/code&gt;, remote Ollama via &lt;code&gt;OLLAMA_API_KEY&lt;/code&gt;. Fixed: an Amazon template returning nulls behind six green tests, price monitoring that never fired, &lt;code&gt;scrape&lt;/code&gt; deleting visible content, Ollama never registered as an LLM provider, seven Playwright defects, a renderer leak, Reddit-wide search, and PDF tables returning &lt;code&gt;[]&lt;/code&gt; for every document. 28 tools, no breaking changes, one price moved.&lt;br&gt;

&lt;/div&gt;


&lt;h2&gt;
  
  
  Why six passing tests meant nothing
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;amazon-product&lt;/code&gt; failure is the clearest case. Six unit tests covered that template and all six passed, because every selector they exercised — a &lt;code&gt;priceCurrency&lt;/code&gt; meta tag, &lt;code&gt;#acrPopover .a-size-base&lt;/code&gt;, &lt;code&gt;img.a-thumbnail-image&lt;/code&gt; — exists nowhere on Amazon today, and the fixture HTML had been written to contain them.&lt;/p&gt;

&lt;p&gt;The pattern repeated:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;scrape_with_actions&lt;/code&gt; had seven Playwright defects invisible to its suite, because its fake pages implemented whatever the executor called — including APIs Playwright does not have.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;youtube-video&lt;/code&gt; template read an attribute that appears nowhere on a watch page, while its fixture kept the test green.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;process_document&lt;/code&gt; read a field the PDF library declares and never writes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the new suites were written to &lt;strong&gt;fail against the pre-fix code first&lt;/strong&gt;: 15 of 24 for &lt;code&gt;amazon-product&lt;/code&gt;, 8 of 10 for the &lt;code&gt;crawl_deep&lt;/code&gt; cache scope, 7 for the &lt;code&gt;scrape_with_actions&lt;/code&gt; Playwright APIs. The suite is now 1,140 tests with MCP protocol compliance at 100% across all 28 tools — but the number that matters is that every fix below was found by a real page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Product data from the source
&lt;/h2&gt;

&lt;p&gt;Four &lt;code&gt;scrape_template&lt;/code&gt; templates changed, and three moved the same direction: &lt;strong&gt;stop parsing the rendered page, read the structured data the site already publishes.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Shopify's Dawn theme ships &lt;em&gt;every&lt;/em&gt; price badge in the markup unconditionally and hides the inapplicable ones with component CSS. A scraper reading the DOM sees "Sold out" on a product with a hundred units in stock. Ask an LLM for a compare-at price on a product that has none and it invents one — in our testing, &lt;code&gt;27.99&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Shopify serves the same data as JSON at &lt;code&gt;/products/&amp;lt;handle&amp;gt;.json&lt;/code&gt; on every storefront including custom domains, so the new template reads that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tool"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"scrape_template"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"template"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"shopify-product"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://shop.example.com/products/kelpie-bandana"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Exact price, compare-at price, &lt;code&gt;on_sale&lt;/code&gt;, currency, price range across variants, per-variant stock, options, images and tags — no HTML parsing, no LLM in the path.&lt;/p&gt;

&lt;p&gt;Making that possible needed a change one level down: &lt;code&gt;TemplateRegistry&lt;/code&gt; gained &lt;code&gt;resolveUrl(url)&lt;/code&gt; to redirect the tool's single fetch and &lt;code&gt;extractRaw(body, url)&lt;/code&gt; to parse a non-HTML response. The tool still owns the SSRF-guarded fetch.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm-package&lt;/code&gt; moved the same way — npmjs.com answers plain fetches with 403, so it now reads the registry document. Weekly downloads are &lt;strong&gt;omitted rather than returned as null&lt;/strong&gt;: they live on a separate endpoint, and the registry endpoint that carries them alongside package data is a &lt;em&gt;search&lt;/em&gt; endpoint — ask it for &lt;code&gt;left-pad&lt;/code&gt; and it answers &lt;code&gt;pad-left&lt;/code&gt;. Returning another package's download count is worse than returning none.&lt;/p&gt;

&lt;p&gt;And &lt;code&gt;amazon-product&lt;/code&gt; was rebuilt from live captures of three pages. Currency comes from the hidden add-to-cart field, not a meta tag. Rating parses to a number from &lt;code&gt;#acrPopover&lt;/code&gt;'s &lt;code&gt;title&lt;/code&gt;. Review count handles both &lt;code&gt;"(198,594)"&lt;/code&gt; and &lt;code&gt;"198,594 global ratings"&lt;/code&gt;. Images drop Amazon's size token — the tokened URL is a 1 KB thumbnail, the same URL without it is the 16 KB original.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reddit-wide search after PullPush went dark
&lt;/h2&gt;

&lt;p&gt;If your Reddit pipeline started returning 429s this month, the fix is not a longer sleep, a rotating user agent or a proxy. We tested all three. Every request now returns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Rate limit exceeded. This website does not provide free scraping resources for agents..."&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is policy, not throttling. And it matters more than one dead endpoint, because &lt;strong&gt;Arctic Shift — the other public Reddit archive — cannot keyword-search across all of Reddit by design.&lt;/strong&gt; Ask it for a query naming no subreddit and no author and it returns HTTP 400:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;'query' query parameter requires one of: author, subreddit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So scoped searches still worked, and unscoped ones — where you know the phrase but not the community — had no backend at all.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;reddit_search&lt;/code&gt; now serves that in two steps. &lt;strong&gt;Discovery:&lt;/strong&gt; a site-restricted web search returns post URLs in relevance order, and post IDs come out of the &lt;code&gt;/comments/&amp;lt;id&amp;gt;/&lt;/code&gt; segment. &lt;strong&gt;Hydration:&lt;/strong&gt; those IDs go to Arctic Shift in one batch lookup, returning the real post rows — score, comment count, subreddit, author, timestamp, full selftext.&lt;/p&gt;

&lt;p&gt;These are &lt;strong&gt;archive rows, not search snippets&lt;/strong&gt;. Discovery only supplies the addresses. Responses carry &lt;code&gt;source: "web_discovery"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Two limits, both reported rather than hidden: &lt;code&gt;after&lt;/code&gt;/&lt;code&gt;before&lt;/code&gt; cannot apply on the discovery route, and the response says the filter was ignored instead of returning results that look filtered; and an unscoped &lt;strong&gt;comment&lt;/strong&gt; search has no backend at all, so it asks for a scope rather than failing generically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Change tracking that actually fires
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;track_changes&lt;/code&gt; had seven defects across this release, and the first meant price monitoring — the headline use case — did not work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Price moves were scored by how much of the page they occupy.&lt;/strong&gt; Significance was purely volumetric, so &lt;code&gt;$19.99 → $29.99&lt;/code&gt; and &lt;code&gt;$19.99 → $99.99&lt;/code&gt; both scored "minor". With &lt;code&gt;notificationThreshold&lt;/code&gt; defaulting to "moderate", a monitor set up the obvious way never fired. Monetary amounts are now compared directly, and relative magnitude raises significance to at least "moderate", or "major" at 20%+. Only currency-tagged numbers count, so view counters do not fire.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;customSelectors&lt;/code&gt; never scoped anything.&lt;/strong&gt; It was read only inside section-level analysis, where it &lt;em&gt;added&lt;/em&gt; hashes — so scoping made it worse. On an Amazon product page, scoping to the price block raised modified elements 456 → 3204 and payload 5.35 MB → 6.18 MB, on a page whose price had not moved.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;structuralSimilarity&lt;/code&gt; lied in both directions&lt;/strong&gt; — reporting &lt;code&gt;0&lt;/code&gt; when it had not measured (a real score meaning "completely changed"), and never able to fall &lt;em&gt;below&lt;/em&gt; 0.5, because the hierarchy half of the average compared an object that was initialised empty and never written.&lt;/p&gt;

&lt;p&gt;Then 5.2.5 added three more, found while testing price tracking on Zillow and Newegg. Element-level analysis indexed a fixed tag allowlist — &lt;code&gt;h1&lt;/code&gt;-&lt;code&gt;h6&lt;/code&gt;, &lt;code&gt;p&lt;/code&gt;, &lt;code&gt;div&lt;/code&gt;, &lt;code&gt;span&lt;/code&gt;, &lt;code&gt;a&lt;/code&gt; — so a monitor scoped to &lt;code&gt;address&lt;/code&gt;, &lt;code&gt;td&lt;/code&gt;, &lt;code&gt;li&lt;/code&gt;, &lt;code&gt;tr&lt;/code&gt; or &lt;code&gt;dd&lt;/code&gt; built a baseline of &lt;strong&gt;zero elements&lt;/strong&gt; and could never report a change. A Zillow page scoped to &lt;code&gt;['address']&lt;/code&gt; built a baseline of 0 elements from 9 matching nodes. A scoped compare also silently ran unscoped, and "Text content changed" appeared on compares that found no changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Content that was being deleted
&lt;/h2&gt;

&lt;p&gt;Three &lt;code&gt;scrape&lt;/code&gt; defects shared a root: the cleanup passes that strip invisible content were removing content that was visible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Framework-streamed content was deleted.&lt;/strong&gt; The hidden-content strip removed &lt;code&gt;&amp;lt;div id="S:0" hidden&amp;gt;&lt;/code&gt; — where the Next.js App Router streams the rendered page. On a pricing page that wrapper &lt;em&gt;is&lt;/em&gt; the whole visible page, so markdown came back empty and every price with it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Script payload counted as page text.&lt;/strong&gt; The bulk-removal guard sized elements with &lt;code&gt;$('body').text()&lt;/code&gt;, which includes every inline &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;. On a Shopify storefront the denominator was 62,269 characters of which 4,295 was visible copy — so a wrapper holding the entire product section measured under the threshold and was deleted along with the price. The json path then had no price to extract, and the model invented one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;An LLM's schema echo was returned as data.&lt;/strong&gt; The json format read only &lt;code&gt;success&lt;/code&gt; from &lt;code&gt;extract_with_llm&lt;/code&gt; and discarded the rest, so a schema document returned instead of page data reached callers looking like a clean extraction — well-formed JSON, and with no required fields it passed validation too.&lt;/p&gt;

&lt;p&gt;And in 5.2.2, the &lt;code&gt;markdown&lt;/code&gt; format stopped returning raw HTML. &lt;code&gt;turndown-plugin-gfm&lt;/code&gt; converts a table only when its first row is entirely &lt;code&gt;&amp;lt;th&amp;gt;&lt;/code&gt;; every other table hits the plugin's &lt;code&gt;keep&lt;/code&gt; filter and is emitted verbatim. Real pages are full of layout tables — Hacker News is built out of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Local LLMs finally work
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Ollama was never registered as an LLM provider.&lt;/strong&gt; &lt;code&gt;LLMManager&lt;/code&gt; registered only OpenAI and Anthropic, both gated on an API key. So on a machine running Ollama with no cloud keys, &lt;code&gt;extract_structured&lt;/code&gt; skipped LLM extraction entirely and reported &lt;code&gt;css_fallback&lt;/code&gt; — producing values like &lt;code&gt;"$79.99$79.99"&lt;/code&gt; — and &lt;code&gt;deep_research&lt;/code&gt; silently disabled query expansion, semantic ranking and synthesis. &lt;code&gt;extract_with_llm&lt;/code&gt; has its own private client, which is why it worked and masked the gap.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Model routing now picks the best installed model&lt;/strong&gt; instead of always &lt;code&gt;llama3.2&lt;/code&gt;. Benchmarked against three live product pages with verified ground truth, &lt;code&gt;gemma3:4b&lt;/code&gt; scored 18/18 at 1040 ms while &lt;code&gt;llama3.2&lt;/code&gt; scored 16/18 — and the failures are systematic: over five runs &lt;code&gt;llama3.2&lt;/code&gt; invented a compare-at price all five times. Parameter count did not predict accuracy; the 4B model beat both a 12B and a 20B.&lt;/p&gt;

&lt;h2&gt;
  
  
  Browser automation and the stealth wedge
&lt;/h2&gt;

&lt;p&gt;Seven Playwright defects in &lt;code&gt;scrape_with_actions&lt;/code&gt;, all invisible to the suite:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;scroll toElement&lt;/code&gt; called &lt;code&gt;scrollIntoView()&lt;/code&gt;, which does not exist on a handle or locator, so the branch threw every time it ran.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;wait&lt;/code&gt; action advertised &lt;code&gt;enabled&lt;/code&gt;/&lt;code&gt;disabled&lt;/code&gt;/&lt;code&gt;stable&lt;/code&gt; but passed them to an API that rejects them.&lt;/li&gt;
&lt;li&gt;The per-action &lt;code&gt;Promise.race&lt;/code&gt; shared a deadline with the work it raced and won, replacing Playwright's real error with a bare "Action timeout" — and left a live timer per action.&lt;/li&gt;
&lt;li&gt;Every recovery strategy sat behind &lt;code&gt;retries &amp;gt; 0&lt;/code&gt; while the schema defaulted &lt;code&gt;retries&lt;/code&gt; to 0, so none could ever run.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Separately, &lt;code&gt;stealth_mode create_page&lt;/code&gt; never closed its page, leaking one Chromium renderer per call until the instance ran out of memory. A wedged browser was then reused forever behind truthiness-only checks, and cleanup hung on protocol calls to the dead browser. There is now &lt;code&gt;isConnected()&lt;/code&gt; corpse detection, cleanup racing closes against 5 s deadlines with a SIGKILL fallback, and an in-flight launch mutex.&lt;/p&gt;

&lt;h2&gt;
  
  
  Language detection and PDF tables
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Five languages were undetectable.&lt;/strong&gt; &lt;code&gt;analyze_content&lt;/code&gt; filters franc's output against a map of language names, and five keys were ISO 639-2/B codes — &lt;code&gt;chi&lt;/code&gt;, &lt;code&gt;gre&lt;/code&gt;, &lt;code&gt;ara&lt;/code&gt;, &lt;code&gt;nor&lt;/code&gt;, &lt;code&gt;msa&lt;/code&gt; — which franc, emitting ISO 639-3, never produces. A page written entirely in Chinese returned &lt;code&gt;null&lt;/code&gt;. So did Greek, Arabic, Norwegian and Malay.&lt;/p&gt;

&lt;p&gt;A second bug sat behind it: franc scores whichever script is most common, and a CJK page carries the usual run of English product names and code samples. Detection now short-circuits on a Han/kana/hangul share of at least 10% of letters — measured across live pages, Latin-script pages sit at 0% and genuine CJK pages at 24–51%.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PDF table extraction returned &lt;code&gt;[]&lt;/code&gt; for every document ever passed to it.&lt;/strong&gt; The route read &lt;code&gt;TableResult.mergedTables&lt;/code&gt;, a field the PDF library declares but never writes; the tables live on &lt;code&gt;result.pages[].tables&lt;/code&gt;. Against the arXiv "Attention Is All You Need" paper, the IRS W-9 and the IRS 1040, the field being read held 0 tables in every case while the per-page arrays held 7, 6 and 11.&lt;/p&gt;

&lt;h2&gt;
  
  
  One copy of the extractors
&lt;/h2&gt;

&lt;p&gt;The MCP server and our REST API each carried their own copy of the template extractors, in two languages, with nothing detecting divergence — and it diverged twice in two days. &lt;code&gt;amazon-product&lt;/code&gt; was repaired on the MCP side on 25 August while the REST copy kept returning a null rating until the 26th.&lt;/p&gt;

&lt;p&gt;There is now one implementation, published as &lt;a href="https://www.npmjs.com/package/crawlforge-extractors" rel="noopener noreferrer"&gt;crawlforge-extractors&lt;/a&gt;, which both surfaces install. Two more behaviours moved there because one surface had them and the other did not: &lt;code&gt;readBody&lt;/code&gt; (charset-aware decoding and a body-size cap — the REST API called &lt;code&gt;response.text()&lt;/code&gt;, so Shift_JIS and GBK pages came back as mojibake) and &lt;code&gt;structureSignature&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The alternative was a parity test that told us after the fact which copy was wrong. Deleting the second copy is cheaper than detecting drift in it.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to upgrade
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; crawlforge-mcp-server@latest
crawlforge &lt;span class="nt"&gt;--version&lt;/span&gt;   &lt;span class="c"&gt;# 5.2.5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your MCP client launches the server with &lt;code&gt;npx&lt;/code&gt;, it picks up the release on the next restart. No tool was renamed and no output shape changed. The only price change is &lt;code&gt;reddit_search&lt;/code&gt;, from 2 credits to 5 — it now spends the same upstream search call &lt;code&gt;search_web&lt;/code&gt; does — so check your budget maths if you call it in a loop.&lt;/p&gt;

&lt;p&gt;The package is &lt;a href="https://www.npmjs.com/package/crawlforge-mcp-server" rel="noopener noreferrer"&gt;crawlforge-mcp-server on npm&lt;/a&gt;, and the same fixes are already live on the hosted REST API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Want to try any of this without setting up a server?&lt;/strong&gt; The free plan's 1,000 one-time credits need no card, and the &lt;a href="https://www.crawlforge.dev/docs/api-reference/tools" rel="noopener noreferrer"&gt;API reference&lt;/a&gt; covers all 28 tools.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.crawlforge.dev/signup" class="crayons-btn crayons-btn--primary" rel="noopener noreferrer"&gt;Start free with 1,000 credits&lt;/a&gt;
&lt;/p&gt;

</description>
      <category>webscraping</category>
      <category>mcp</category>
      <category>ai</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Web Scraping API Credits That Don't Expire</title>
      <dc:creator>Simon</dc:creator>
      <pubDate>Wed, 26 Aug 2026 19:17:02 +0000</pubDate>
      <link>https://dev.to/simon_crawlforge_dev/web-scraping-api-credits-that-dont-expire-206k</link>
      <guid>https://dev.to/simon_crawlforge_dev/web-scraping-api-credits-that-dont-expire-206k</guid>
      <description>&lt;p&gt;Most web scraping APIs sell you credits, then quietly take back whatever you did not use. Burn 60% of your monthly allowance and the other 40% evaporates on the next billing date. If you are searching for web scraping API credits that don't expire, you have probably hit that wall already — so this post covers why expiry is the industry default, what it actually costs you, and how &lt;a href="https://www.crawlforge.dev" rel="noopener noreferrer"&gt;CrawlForge&lt;/a&gt; prices the alternative.&lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
&lt;strong&gt;TL;DR:&lt;/strong&gt; CrawlForge sells credits that don't expire: one-time packs from $3 per 1,000 up to $62.50 per 25,000, bought with no subscription, plus paid plans whose unused credits roll over month to month. Cancelling never wipes your balance, and the free 1,000 signup credits never refill — but never vanish either. Firecrawl's free 1,000 credits, by contrast, reset monthly and unused ones lapse.&lt;br&gt;

&lt;/div&gt;


&lt;h2&gt;
  
  
  Why Do Most Scraping API Credits Expire?
&lt;/h2&gt;

&lt;p&gt;Because most scraping APIs are sold as subscriptions, and subscription accounting wants a clean monthly reset. A fixed allowance that expires makes revenue predictable, keeps no credit liability on the books, and turns every unused credit into pure margin. The industry term for that margin is &lt;strong&gt;breakage&lt;/strong&gt;, and expiring credits are how vendors generate it.&lt;/p&gt;

&lt;p&gt;The model is fine when your usage is flat. Scraping usage rarely is: it comes in bursts — a one-off dataset build, a competitor research sprint, a migration — followed by quiet weeks. On an expiring plan the burst months force an upgrade or overage fees, and the quiet months donate the allowance back to the vendor. Either way, you are paying for your peak month twelve times a year.&lt;/p&gt;

&lt;h2&gt;
  
  
  The CrawlForge Model
&lt;/h2&gt;

&lt;p&gt;CrawlForge treats credits as something you bought, not something you rent. Four rules:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;One-time credit packs never expire.&lt;/strong&gt; Buy a pack in the dashboard — no subscription required — and the credits sit there until you spend them, whether that takes a week or a year.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Paid-plan credits roll over.&lt;/strong&gt; On Hobby, Professional, and Business, all unused monthly credits carry forward and never expire while the subscription is active.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cancelling never wipes your balance.&lt;/strong&gt; Unused credits survive cancellation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The free tier is one-time, not monthly.&lt;/strong&gt; Sign up and you get 1,000 credits with no credit card required; they never refill, and they never vanish either.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The packs:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pack&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;th&gt;Per 1,000 credits&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1,000 credits&lt;/td&gt;
&lt;td&gt;$3&lt;/td&gt;
&lt;td&gt;$3.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5,000 credits&lt;/td&gt;
&lt;td&gt;$14&lt;/td&gt;
&lt;td&gt;$2.80&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10,000 credits&lt;/td&gt;
&lt;td&gt;$27&lt;/td&gt;
&lt;td&gt;$2.70&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;25,000 credits&lt;/td&gt;
&lt;td&gt;$62.50&lt;/td&gt;
&lt;td&gt;$2.50&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For bursty workloads this is the whole pitch: buy exactly the burst, spend it on your own schedule, and pay nothing in the quiet weeks. Paid plans add optional auto-recharge — a top-up that fires only when the balance runs low — and the full plan grid is on the &lt;a href="https://www.crawlforge.dev/pricing" rel="noopener noreferrer"&gt;pricing page&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What 1,000 Credits Actually Buys
&lt;/h2&gt;

&lt;p&gt;CrawlForge meters all 28 tools per call, at 1–10 credits depending on the work involved. So a 1,000-credit pack — or the free signup grant — translates to:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Credits per call&lt;/th&gt;
&lt;th&gt;Calls per 1,000 credits&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;fetch_url&lt;/code&gt; (raw HTTP fetch)&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;scrape&lt;/code&gt; (markdown/HTML/text)&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;extract_structured&lt;/code&gt; (schema JSON)&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;333&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;search_web&lt;/code&gt; / &lt;code&gt;stealth_mode&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;deep_research&lt;/code&gt; (multi-source)&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You mix and match against one balance, over MCP (Claude Code, Claude Desktop, Cursor), REST, or the &lt;a href="https://www.crawlforge.dev/playground" rel="noopener noreferrer"&gt;browser playground&lt;/a&gt;. And because none of it expires, "1,000 credits" means 1,000 page fetches whenever you get around to them — not 1,000 fetches this month or nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Firecrawl Handles the Same Question
&lt;/h2&gt;

&lt;p&gt;Firecrawl — the best-known name in this space, YC-backed with an established community — is a solid product, and its pricing is the standard subscription shape. The free tier grants 1,000 credits per month, and unused credits do not roll over — Firecrawl's own pricing FAQ states that credits do not roll over on any self-serve plan, with rollover reserved for its Scale and Enterprise tiers. Paid plans (billed annually) run Hobby $16/mo for 5,000 credits, Standard $83/mo for 100,000, and Growth $333/mo for 500,000; there is no equivalent of CrawlForge's standalone one-time packs, and the same FAQ says outright that it does not offer a pay-per-use plan.&lt;/p&gt;

&lt;p&gt;One caveat before you compare raw numbers: a Firecrawl credit buys one page, while CrawlForge bills 1–10 credits per tool call depending on the tool, so credit counts are not directly comparable between the two. What is directly comparable is the free-tier expiry policy: Firecrawl's free 1,000 credits reset monthly and unused ones lapse; CrawlForge's free 1,000 is a one-time grant that never expires. The feature-by-feature breakdown is in the &lt;a href="https://www.crawlforge.dev/blog/crawlforge-vs-firecrawl-mcp-web-scraper-comparison" rel="noopener noreferrer"&gt;CrawlForge vs Firecrawl comparison&lt;/a&gt;, with the wider field covered in &lt;a href="https://www.crawlforge.dev/blog/crawlforge-vs-firecrawl-tavily-exa-web-data-api" rel="noopener noreferrer"&gt;CrawlForge vs Firecrawl, Tavily, and Exa&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  When a Subscription Is the Better Deal
&lt;/h2&gt;

&lt;p&gt;Honesty cuts both ways: at steady high volume, a subscription beats packs — including ours. CrawlForge Professional is $99/mo for 50,000 credits, about $1.98 per 1,000 — cheaper than even the largest one-time pack at $2.50. Business is $399/mo for 250,000, about $1.60 per 1,000, and plans also raise the rate limit: 2, 4, and 10 requests per second on Hobby, Professional, and Business versus 1 on free.&lt;/p&gt;

&lt;p&gt;The rule of thumb: predictable volume in the tens of thousands of credits per month, subscribe; bursty or exploratory work, buy packs. And because CrawlForge plan credits roll over, subscribing does not reintroduce the use-it-or-lose-it problem the packs exist to solve — a slow month just banks credits for the next burst.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;/p&gt;
  Do CrawlForge credits expire?
  &lt;br&gt;
No. One-time credit packs ($3 for 1,000 up to $62.50 for 25,000) never expire, and on paid plans all unused monthly credits roll over and never expire while the subscription is active. The free 1,000 signup credits are also permanent — they never refill, but they never disappear either. There is no use-it-or-lose-it mechanic anywhere in the pricing.&lt;br&gt;


&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  What happens to my credits if I cancel my subscription?
  &lt;br&gt;
Nothing — cancelling a CrawlForge subscription never wipes unused credits, so whatever balance you have built up stays spendable, including plan credits rolled over from previous months. The one exception is choosing a full refund of an untouched billing period: the money goes back, and the credits that payment provided go with it. If you need more later, you can buy one-time credit packs without resubscribing.&lt;br&gt;


&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Can you use a web scraping API without a subscription?
  &lt;br&gt;
Yes. CrawlForge sells one-time credit packs — $3 for 1,000 up to $62.50 for 25,000 — in the dashboard with no subscription attached, and they never expire. Every account also starts with 1,000 free one-time credits, no credit card required. All 28 tools work on either footing, over REST, MCP, or the browser playground.&lt;br&gt;


&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Do the free 1,000 credits expire or refill?
  &lt;br&gt;
Neither. CrawlForge's free tier is a one-time grant of 1,000 credits at signup: it never refills monthly, and it never expires, with no credit card required and a rate limit of 1 request per second. Firecrawl's free tier works the other way around — 1,000 fresh credits each month, but unused ones do not roll over (noting a Firecrawl credit buys one page while CrawlForge tools cost 1–10 credits per call).&lt;br&gt;


&lt;p&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Start Without a Clock
&lt;/h2&gt;

&lt;p&gt;The cheapest way to test any of this is the grant every account starts with: 1,000 one-time credits, no card, no expiry — enough for 1,000 raw fetches, 500 scrapes, or 100 deep-research runs. If they are still sitting there in six months, that is the feature working as designed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.crawlforge.dev/signup" class="crayons-btn crayons-btn--primary" rel="noopener noreferrer"&gt;Start Free — 1,000 Credits Included&lt;/a&gt;
&lt;/p&gt;

</description>
      <category>webscraping</category>
      <category>api</category>
      <category>pricing</category>
      <category>mcp</category>
    </item>
    <item>
      <title>Reddit 403'd our stealth browser, so we stopped scraping reddit.com entirely</title>
      <dc:creator>Simon</dc:creator>
      <pubDate>Mon, 24 Aug 2026 23:29:33 +0000</pubDate>
      <link>https://dev.to/simon_crawlforge_dev/reddit-403d-our-stealth-browser-so-we-stopped-scraping-redditcom-entirely-4k7i</link>
      <guid>https://dev.to/simon_crawlforge_dev/reddit-403d-our-stealth-browser-so-we-stopped-scraping-redditcom-entirely-4k7i</guid>
      <description>&lt;p&gt;Ask any scraper developer what the hardest mainstream site is in 2026 and Reddit is a safe answer. We would know — reddit.com blocks every direct access path &lt;a href="https://www.crawlforge.dev" rel="noopener noreferrer"&gt;CrawlForge&lt;/a&gt; has, from a plain fetch to a full stealth browser.&lt;/p&gt;

&lt;p&gt;So &lt;strong&gt;CrawlForge MCP v5.1.0&lt;/strong&gt; stops fighting the wall and goes around it: the new &lt;code&gt;reddit_search&lt;/code&gt; tool — our 28th — searches Reddit posts and comments and reads entire threads through community-run archives, with &lt;strong&gt;no Reddit API key, no OAuth app, and no credentials of any kind&lt;/strong&gt;.&lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
&lt;strong&gt;TL;DR:&lt;/strong&gt; v5.1.0 adds &lt;code&gt;reddit_search&lt;/code&gt;: search Reddit posts and comments, or read a full nested comment thread, without ever touching reddit.com. It queries two community archives — Arctic Shift (near-real-time) and PullPush (Pushshift-compatible full-text search) — so there is nothing to sign up for on Reddit's side. Three modes, 2 credits per call. Upgrade: &lt;code&gt;npm install -g crawlforge-mcp-server@latest&lt;/code&gt;.&lt;br&gt;

&lt;/div&gt;


&lt;h2&gt;
  
  
  Table of contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What shipped&lt;/li&gt;
&lt;li&gt;Why reddit.com cannot be scraped&lt;/li&gt;
&lt;li&gt;One tool, three modes&lt;/li&gt;
&lt;li&gt;The archives: Arctic Shift and PullPush&lt;/li&gt;
&lt;li&gt;How routing works&lt;/li&gt;
&lt;li&gt;Honest caveats&lt;/li&gt;
&lt;li&gt;Using it from MCP and REST&lt;/li&gt;
&lt;li&gt;What about the Reddit thread template&lt;/li&gt;
&lt;li&gt;Credit cost&lt;/li&gt;
&lt;li&gt;How to upgrade&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What shipped
&lt;/h2&gt;

&lt;p&gt;v5.1.0 is a focused minor release with one headline:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;reddit_search&lt;/code&gt;&lt;/strong&gt; — search Reddit posts (title + selftext) and comments, or read a post plus its nested comment tree, via the Arctic Shift and PullPush community archives. Three modes, scoped filters, normalized output. &lt;strong&gt;2 credits per call.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Tool count goes from 27 to &lt;strong&gt;28&lt;/strong&gt;, and the MCP server card, tool instructions, and getting-started prompt all know about the newcomer.&lt;/li&gt;
&lt;li&gt;31 new unit tests (1,018 total in the suite) and 100% MCP protocol compliance across all 28 tools, live-verified over MCP stdio returning real r/ClaudeAI posts.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why reddit.com cannot be scraped
&lt;/h2&gt;

&lt;p&gt;We did not reach for archives out of preference — we measured the wall first. Before building the tool we ran every direct path against reddit.com, live:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;fetch_url&lt;/code&gt; with a full browser User-Agent: &lt;strong&gt;403&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;scrape&lt;/code&gt; against old.reddit.com: &lt;strong&gt;403&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;scrape_template&lt;/code&gt; with the reddit-thread template: &lt;strong&gt;403&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;stealth_mode&lt;/code&gt; at its most advanced level: &lt;strong&gt;403&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The block is layered — datacenter IP reputation first, TLS fingerprinting at the handshake, then a JavaScript challenge — which is why even a stealth browser on a server fails.&lt;/p&gt;

&lt;p&gt;And the sanctioned door narrowed too: Reddit closed self-service API signup in November 2025 under its Responsible Builder Policy, so new applications for official API credentials go through an approval request rather than a signup form. Most Reddit MCP servers wrap that official API, which now makes "get credentials" the hardest step of their setup.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;reddit_search&lt;/code&gt; sidesteps all of it. It never sends a single request to reddit.com.&lt;/p&gt;

&lt;h2&gt;
  
  
  One tool, three modes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;posts&lt;/code&gt;&lt;/strong&gt; (default) — keyword search across post titles and selftext, optionally scoped to a subreddit or author. Supports &lt;code&gt;"quoted phrases"&lt;/code&gt;, &lt;code&gt;OR&lt;/code&gt;, and &lt;code&gt;-exclusion&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;comments&lt;/code&gt;&lt;/strong&gt; — full-text search across comment bodies, something the official Reddit API cannot do at all.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;thread&lt;/code&gt;&lt;/strong&gt; — hand it a post ID and get the post plus its nested comment tree, with reddit-style collapse markers for branches too deep to expand.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Filters cover &lt;code&gt;subreddit&lt;/code&gt;, &lt;code&gt;author&lt;/code&gt;, &lt;code&gt;after&lt;/code&gt;/&lt;code&gt;before&lt;/code&gt; dates (ISO 8601, epoch seconds, or offsets like &lt;code&gt;"7d"&lt;/code&gt;), &lt;code&gt;limit&lt;/code&gt; (up to 100), and &lt;code&gt;sort&lt;/code&gt;. Results come back normalized: full reddit.com permalinks, ISO dates, scores, comment counts, and text capped at 2,000 characters with truncation flags so a 100-result payload stays friendly to an LLM context window.&lt;/p&gt;

&lt;p&gt;A typical call from an MCP client looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tool"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"reddit_search"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"arguments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"best mcp servers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"subreddit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ClaudeAI"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"mode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"posts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"limit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Take any post &lt;code&gt;id&lt;/code&gt; from the results, pass it back as &lt;code&gt;link_id&lt;/code&gt; with &lt;code&gt;mode: "thread"&lt;/code&gt;, and you have the whole discussion — ready for &lt;code&gt;summarize_content&lt;/code&gt; or &lt;code&gt;analyze_content&lt;/code&gt; to turn into sentiment, topics, and a briefing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The archives: Arctic Shift and PullPush
&lt;/h2&gt;

&lt;p&gt;If you remember &lt;strong&gt;Pushshift&lt;/strong&gt; — the beloved Reddit research archive that lost its API access in 2023 — these two projects are its successors, and they are what &lt;code&gt;reddit_search&lt;/code&gt; queries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Arctic Shift&lt;/strong&gt; ingests Reddit in near-real-time. During live testing it returned a post created the same day, and it serves proper nested comment trees. Its one documented constraint: keyword search must be scoped to a subreddit or author.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PullPush&lt;/strong&gt; is Pushshift-compatible and does what Arctic Shift will not — full-text search across &lt;em&gt;all&lt;/em&gt; of Reddit. The trade-offs: documented gaps in its post-2023 archive and aggressive rate limits.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are free, both are community-run, and neither needs credentials. Every response includes provenance notes naming the archive that answered, so downstream consumers always know where the data came from.&lt;/p&gt;

&lt;h2&gt;
  
  
  How routing works
&lt;/h2&gt;

&lt;p&gt;You never pick a backend unless you want to. In the default &lt;code&gt;auto&lt;/code&gt; mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;scoped search (subreddit/author)  --+--&amp;gt; Arctic Shift (fresher)
thread read                       --+      |
                                           +--&amp;gt; error? --&amp;gt; PullPush
                                                           (fallback_used: true)

unscoped full-text search  ----------&amp;gt; PullPush
                                       (only archive that supports it)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The plumbing absorbs the archives' quirks: every request carries an identifying User-Agent (live testing showed Arctic Shift throttles anonymous clients into a shared bucket), transient throttle responses get one bounded retry, and PullPush's rate-limit messages pass through verbatim so you see the real reason instead of a generic error. A &lt;code&gt;REDDIT_SEARCH_TIMEOUT_MS&lt;/code&gt; environment variable overrides the 30-second per-request cap if your pipeline needs a different budget.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest caveats
&lt;/h2&gt;

&lt;p&gt;Archive data has edges, and we would rather document them than let you find them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Very fresh content reads low.&lt;/strong&gt; The archives capture posts the moment they appear, so scores and comment counts of content less than ~36 hours old often read 0 or 1. The content is there; the vote tallies have not caught up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PullPush has post-2023 gaps.&lt;/strong&gt; An empty unscoped search does not prove the content does not exist. Scope to a subreddit or author when you can — it routes you to the more complete archive.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deleted content may persist in archives.&lt;/strong&gt; That is inherent to how archives work, and it cuts both ways: it is also why researchers use them.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Using it from MCP and REST
&lt;/h2&gt;

&lt;p&gt;In an MCP client — Claude Desktop, Claude Code, Cursor — just ask: &lt;em&gt;"Search r/webdev for discussions about scraping infrastructure from the last month and summarize the top complaints."&lt;/em&gt; The agent picks &lt;code&gt;reddit_search&lt;/code&gt;, scopes it, and chains the summary itself.&lt;/p&gt;

&lt;p&gt;From the &lt;a href="https://www.crawlforge.dev/docs/api-reference/tools/reddit-search" rel="noopener noreferrer"&gt;REST API&lt;/a&gt;, it is one authenticated POST:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://crawlforge.dev/api/v1/tools/reddit_search&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;X-API-Key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CRAWLFORGE_API_KEY&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;best mechanical keyboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;subreddit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MechanicalKeyboards&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; posts via &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also try it with zero setup in the &lt;a href="https://www.crawlforge.dev/playground" rel="noopener noreferrer"&gt;playground&lt;/a&gt; — &lt;code&gt;reddit_search&lt;/code&gt; is live there alongside the other 27 tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about the Reddit thread template
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;scrape_template&lt;/code&gt; still ships its &lt;code&gt;reddit-thread&lt;/code&gt; template, but it points at reddit.com — the very wall this release routes around — so it no longer works reliably. The &lt;a href="https://www.crawlforge.dev/docs/api-reference/tools/scrape-template" rel="noopener noreferrer"&gt;scrape_template docs&lt;/a&gt; now say exactly that and point Reddit work at &lt;code&gt;reddit_search&lt;/code&gt; instead. The other nine templates (Amazon, GitHub, YouTube, Hacker News, and friends) are unaffected.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Also since v5.0.4
  &lt;br&gt;
If you skipped the patch between releases, v5.0.5 fixed two numbers &lt;code&gt;serp_rank&lt;/code&gt; had been asserting wrongly: the DataForSEO request timeout (now 120 seconds by default, tunable via &lt;code&gt;DATAFORSEO_TIMEOUT_MS&lt;/code&gt;, because live Google scrapes at depth 100 routinely take 30-60+ seconds) and the documented upstream cost (the old figure was the depth-10 price, 10× lower than the depth-100 default actually bills). It also fixed the Smithery listing, which now derives its tool table from the live registry instead of a hand-written card. The full story of the v5.0.x hardening cycle is in the &lt;a href="https://www.crawlforge.dev/blog/crawlforge-v5-0-4-live-testing-27-tools" rel="noopener noreferrer"&gt;v5.0.4 live-testing post&lt;/a&gt;.&lt;br&gt;


&lt;p&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Credit cost
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;reddit_search&lt;/code&gt; costs &lt;strong&gt;2 credits&lt;/strong&gt; per call — search or full thread read, same price. For scale: the free plan's 1,000 starter credits cover &lt;strong&gt;500 Reddit searches&lt;/strong&gt;, and a search plus a thread read plus &lt;code&gt;summarize_content&lt;/code&gt; on the result is 8 credits end to end. As always, failed requests are not charged.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to upgrade
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; crawlforge-mcp-server@latest
crawlforge &lt;span class="nt"&gt;--version&lt;/span&gt;   &lt;span class="c"&gt;# 5.1.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or, if your MCP client launches the server with npx, it picks up 5.1.0 automatically on the next restart. No schema, output-shape, or credit-cost changes to any existing tool — this is a drop-in upgrade. The package is &lt;a href="https://www.npmjs.com/package/crawlforge-mcp-server" rel="noopener noreferrer"&gt;crawlforge-mcp-server on npm&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ready to mine Reddit discussions without an API key?&lt;/strong&gt; The free plan's 1,000 credits are enough for 500 searches, and the &lt;a href="https://www.crawlforge.dev/docs/api-reference/tools/reddit-search" rel="noopener noreferrer"&gt;reddit_search API reference&lt;/a&gt; covers every parameter and mode.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.crawlforge.dev/signup" class="crayons-btn crayons-btn--primary" rel="noopener noreferrer"&gt;Start free with 1,000 credits&lt;/a&gt;
&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Answer 3 Questions, Get 1,000 Free CrawlForge Credits</title>
      <dc:creator>Simon</dc:creator>
      <pubDate>Mon, 24 Aug 2026 23:23:40 +0000</pubDate>
      <link>https://dev.to/simon_crawlforge_dev/answer-3-questions-get-1000-free-crawlforge-credits-53ln</link>
      <guid>https://dev.to/simon_crawlforge_dev/answer-3-questions-get-1000-free-crawlforge-credits-53ln</guid>
      <description>&lt;p&gt;We just started paying for feedback. Complete the &lt;a href="https://www.crawlforge.dev" rel="noopener noreferrer"&gt;CrawlForge&lt;/a&gt; product survey — three questions, about twenty seconds — and we add &lt;strong&gt;1,000 free credits&lt;/strong&gt; to your account, instantly and automatically. That is the same amount a brand-new account gets on signup, so a free-tier member who claims it doubles their lifetime credits.&lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
&lt;strong&gt;TL;DR:&lt;/strong&gt; Sign in at &lt;a href="https://www.crawlforge.dev" rel="noopener noreferrer"&gt;crawlforge.dev&lt;/a&gt;, click the floating feedback button in the bottom-right corner, answer 3 questions. If your account has used &lt;strong&gt;250+ credits&lt;/strong&gt; on real API calls, &lt;strong&gt;1,000 credits&lt;/strong&gt; are granted on the spot. One reward per account, ever.&lt;br&gt;

&lt;/div&gt;


&lt;p&gt;There is one honest condition, and we would rather state it up front than bury it in fine print: &lt;strong&gt;the reward only goes to accounts that have actually used the product — at least 250 credits of API usage.&lt;/strong&gt; If your account has not reached that mark yet, the survey still works and we still read every answer — but no credits are granted.&lt;/p&gt;

&lt;p&gt;The reasoning is simple. We are paying for feedback because feedback from real usage is worth paying for. An opinion about a product you have barely run tells us about our marketing, not our product, and a reward with no real-usage requirement would just be a faucet for throwaway accounts.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to claim your 1,000 free credits
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Sign in to your CrawlForge account.&lt;/strong&gt; The grant is keyed to your session, so an anonymous submission cannot be rewarded — there is no account to credit. No account yet? &lt;a href="https://www.crawlforge.dev/signup" rel="noopener noreferrer"&gt;Signing up is free&lt;/a&gt; and comes with its own 1,000 starter credits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make sure your account has used at least 250 credits.&lt;/strong&gt; Every credit-consuming call made with your API key counts toward the total, whether it went through MCP, the REST API, or the CLI — 125 &lt;code&gt;scrape&lt;/code&gt; calls (2 credits each) or 25 &lt;code&gt;deep_research&lt;/code&gt; runs (10 credits each) gets you there. Just getting started? The &lt;a href="https://www.crawlforge.dev/blog/crawlforge-mcp-quickstart" rel="noopener noreferrer"&gt;quickstart guide&lt;/a&gt; gets you from zero to a first scrape in under five minutes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open the survey.&lt;/strong&gt; It lives behind the floating message button in the bottom-right corner of every page on &lt;a href="https://www.crawlforge.dev" rel="noopener noreferrer"&gt;crawlforge.dev&lt;/a&gt; and the dashboard.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Answer the three questions and hit send.&lt;/strong&gt; A rating, a one-tap question about what is blocking you, and an optional comment. If you qualify, the confirmation message tells you the credits were added on the spot — no code, no email, no waiting.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The whole thing takes less time than reading this section did.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who qualifies
&lt;/h2&gt;

&lt;p&gt;The rules, stated plainly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You must be &lt;strong&gt;signed in&lt;/strong&gt; when you submit the survey.&lt;/li&gt;
&lt;li&gt;Your account must have used &lt;strong&gt;at least 250 credits&lt;/strong&gt; on API calls before submitting. Grants and bonuses do not count toward the total — only actual tool calls do.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One reward per account, ever.&lt;/strong&gt; Submitting the survey again is welcome (feedback changes as the product does), but it will not grant twice.&lt;/li&gt;
&lt;li&gt;Already answered the survey before this announcement? Submit it again while signed in — earlier anonymous responses could not be matched to your account, so your claim is still available.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you submit and do not see the credits message, it is almost always one of the first two rules: you were not signed in, or the account has not used 250 credits yet. Fix whichever applies and submit again.&lt;/p&gt;

&lt;h2&gt;
  
  
  What 1,000 credits actually buys
&lt;/h2&gt;

&lt;p&gt;Every CrawlForge tool has a fixed credit price, so the reward converts directly into work. A few examples from the &lt;a href="https://www.crawlforge.dev/pricing" rel="noopener noreferrer"&gt;pricing page&lt;/a&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Credits per call&lt;/th&gt;
&lt;th&gt;1,000 credits =&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;scrape&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;500 pages scraped&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;extract_content&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;500 clean article extractions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;search_web&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;200 web searches&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;serp_rank&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;200 Google rank checks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;deep_research&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;100 full research runs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Mix and match across all 28 tools — the full price list is in the &lt;a href="https://www.crawlforge.dev/docs/api-reference/tools" rel="noopener noreferrer"&gt;API reference&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The survey stays anonymous if you want it to
&lt;/h2&gt;

&lt;p&gt;Nothing about the reward changes how the survey handles your data. It is self-hosted — no third-party survey processor ever sees a response. Your IP address is only ever stored as a salted hash, the email field is optional, and you can submit without an account at all. Signing in is only required for the credits, because a reward needs an account to land in. Signed-out feedback is read with exactly the same attention.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  The fine print
  &lt;ul&gt;
&lt;li&gt;The reward is a &lt;strong&gt;one-time promotional grant&lt;/strong&gt;: it does not renew, has no cash value, cannot be transferred, and — like all one-time credits — is not refundable.&lt;/li&gt;
&lt;li&gt;Submissions are rate-limited, and automated or fraudulent submissions void the reward.&lt;/li&gt;
&lt;li&gt;We may change or end this promotion at any time; credits already granted stay granted.
&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Why we are doing this
&lt;/h2&gt;

&lt;p&gt;CrawlForge is built for people running real workloads — AI agents that need &lt;a href="https://www.crawlforge.dev/blog/best-web-scraping-tools-ai-agents-2026" rel="noopener noreferrer"&gt;reliable web data&lt;/a&gt;, scrapers that hit anti-bot walls, research pipelines that fan out across hundreds of pages. Analytics tell us what those people do; they do not tell us what almost made them leave, or which missing tool they are quietly working around. Three questions from someone who has actually run the tools answer that better than any dashboard, and 1,000 credits is a fair trade for it.&lt;/p&gt;

&lt;p&gt;The button is in the bottom-right corner. Sign in, tell us what you think, and put the credits to work.&lt;/p&gt;

&lt;p&gt;Not a member yet? Start free with 1,000 credits — run a few tools, then come back and take the survey for 1,000 more.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.crawlforge.dev/signup" class="crayons-btn crayons-btn--primary" rel="noopener noreferrer"&gt;Start free with 1,000 credits&lt;/a&gt;
&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>webscraping</category>
      <category>api</category>
      <category>news</category>
    </item>
    <item>
      <title>CrawlForge v5.0.0: Security, Correctness, MCP Spec</title>
      <dc:creator>Simon</dc:creator>
      <pubDate>Fri, 14 Aug 2026 13:58:26 +0000</pubDate>
      <link>https://dev.to/simon_crawlforge_dev/crawlforge-v500-security-correctness-mcp-spec-3i0c</link>
      <guid>https://dev.to/simon_crawlforge_dev/crawlforge-v500-security-correctness-mcp-spec-3i0c</guid>
      <description>&lt;p&gt;&lt;code&gt;http://2130706433/&lt;/code&gt; is a valid URL. Your browser will happily resolve it to &lt;code&gt;127.0.0.1&lt;/code&gt;, because the WHATWG URL parser normalizes decimal, hex (&lt;code&gt;0x7f000001&lt;/code&gt;), and octal integer forms into dotted-quad IPv4.&lt;/p&gt;

&lt;p&gt;Our SSRF guard did not know that. It resolved hostnames through DNS and range-checked the resulting addresses — but Node never routes an IP literal through &lt;code&gt;lookup&lt;/code&gt;, so a URL whose host was &lt;em&gt;already&lt;/em&gt; an IP sailed straight past the check. Loopback, link-local, cloud metadata: all reachable, in a server whose entire job is fetching URLs a model picked for you.&lt;/p&gt;

&lt;p&gt;That is one bug out of the seven-phase internal audit that became &lt;strong&gt;&lt;a href="https://www.npmjs.com/package/crawlforge-mcp-server" rel="noopener noreferrer"&gt;CrawlForge MCP Server&lt;/a&gt; v5.0.0&lt;/strong&gt;. The unit suite went from &lt;strong&gt;480 tests to 914&lt;/strong&gt;. &lt;code&gt;npm audit&lt;/code&gt; went from &lt;strong&gt;16 vulnerabilities to 0&lt;/strong&gt;. Almost none of it is new features.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What actually shipped&lt;/li&gt;
&lt;li&gt;The one breaking change: Node 20&lt;/li&gt;
&lt;li&gt;Phase 1: the SSRF bypass we shipped&lt;/li&gt;
&lt;li&gt;Phase 2: 52 ways tools were silently wrong&lt;/li&gt;
&lt;li&gt;Phase 3: safe to run for days&lt;/li&gt;
&lt;li&gt;Phase 4: HTTP mode only ever had one session&lt;/li&gt;
&lt;li&gt;Phase 5: zero npm audit vulnerabilities&lt;/li&gt;
&lt;li&gt;Phase 6: MCP spec adoption&lt;/li&gt;
&lt;li&gt;Pricing and how to upgrade&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What actually shipped
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Phase&lt;/th&gt;
&lt;th&gt;Theme&lt;/th&gt;
&lt;th&gt;Headline result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Dependency currency&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;npm audit&lt;/code&gt; 16 vulns → 4 moderate, zero code change&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Critical security&lt;/td&gt;
&lt;td&gt;SSRF IP-literal bypass, OAuth token minting, secret leakage, billing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Correctness&lt;/td&gt;
&lt;td&gt;52 fixes — including a &lt;code&gt;crawl_deep&lt;/code&gt; rewrite&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Leaks and timeouts&lt;/td&gt;
&lt;td&gt;24 fixes — browser contexts, unbounded caches, real deadlines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;HTTP transport&lt;/td&gt;
&lt;td&gt;19 fixes — multi-session streamable HTTP, working prompts, webhook HMAC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Dependency modernization&lt;/td&gt;
&lt;td&gt;Node ≥ 20 floor, &lt;strong&gt;0&lt;/strong&gt; npm audit vulnerabilities&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;MCP spec adoption&lt;/td&gt;
&lt;td&gt;Structured output, async tasks, tool whitelisting, registry &lt;code&gt;server.json&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;MCP protocol compliance held at &lt;strong&gt;100.0% COMPLIANT, 0 errors&lt;/strong&gt; at every phase gate.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one breaking change: Node 20
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;engines.node&lt;/code&gt; moved from &lt;code&gt;&amp;gt;=18.0.0&lt;/code&gt; to &lt;code&gt;&amp;gt;=20.16.0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Node 18 hit end-of-life in April 2025, and 20.16 is the floor required by &lt;code&gt;pdf-parse&lt;/code&gt; 2.4.5 — the maintained ESM rewrite we needed to clear the last audit findings. Our Dockerfile (&lt;code&gt;node:20-alpine&lt;/code&gt;) and CI (Node 22) already satisfied it.&lt;/p&gt;

&lt;p&gt;That is the entire breaking surface. &lt;strong&gt;No tool schema, output shape, or credit cost changed&lt;/strong&gt;, and the tool count stays at 27.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;--version&lt;/span&gt;   &lt;span class="c"&gt;# must be &amp;gt;= 20.16.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Phase 1: the SSRF bypass we shipped
&lt;/h2&gt;

&lt;p&gt;Read this phase if you run any MCP scraping server near a private network.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BEFORE: url -&amp;gt; parse -&amp;gt; DNS lookup -&amp;gt; ipBlocked(resolved)?  -&amp;gt; fetch
                          |
                          +--&amp;gt; IP literal? no lookup happens.
                               guard never runs. request goes out.

AFTER:  url -&amp;gt; parse -&amp;gt; ipBlocked(literal host)? --------+
                     -&amp;gt; DNS lookup -&amp;gt; ipBlocked(addrs)? -+-&amp;gt; fetch
                     -&amp;gt; per-connect check in the undici dispatcher
                        (catches every redirect hop too)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;v5.0.0 runs &lt;code&gt;ipBlocked()&lt;/code&gt; on IP-literal hostnames at pre-flight &lt;strong&gt;and&lt;/strong&gt; wraps the undici dispatcher's &lt;code&gt;buildConnector&lt;/code&gt; with a per-connect check, so a redirect hop straight to an internal address is blocked as well.&lt;/p&gt;

&lt;p&gt;Three more guard fixes landed with it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;IPv4-mapped IPv6.&lt;/strong&gt; &lt;code&gt;::ffff:127.0.0.1&lt;/code&gt; and &lt;code&gt;::ffff:169.254.169.254&lt;/code&gt; are normalized to their embedded IPv4 before range checks, in both default and strict modes. Kills the DNS-controlled AAAA-record bypass.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;BLOCKED_DOMAINS&lt;/code&gt; was dead config.&lt;/strong&gt; It was declared and read by nothing. It is now enforced at pre-flight.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The allowlist is evaluated per hop.&lt;/strong&gt; An allowlisted first hop used to unguard every redirect after it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We also wired the guard into five paths that never had it: &lt;code&gt;scrape_with_actions&lt;/code&gt; (with a post-navigation &lt;code&gt;page.url()&lt;/code&gt; re-check that closes the page on a redirect into a blocked range — that was a Playwright internal-network read primitive), &lt;code&gt;map_site&lt;/code&gt;, &lt;code&gt;process_document&lt;/code&gt; PDF downloads, webhook delivery and health checks, and &lt;code&gt;deep_research&lt;/code&gt; webhook notifications.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Beyond SSRF: OAuth, secret leakage, and billing
  &lt;br&gt;
&lt;strong&gt;OAuth.&lt;/strong&gt; &lt;code&gt;/oauth/authorize&lt;/code&gt; now requires proof of the operator's API key before issuing a code, with constant-time digest comparison. The anonymous register → authorize → token flow that minted operator-billed bearer tokens is closed.

&lt;p&gt;&lt;strong&gt;Secret leakage.&lt;/strong&gt; Usage telemetry passes tool params through &lt;code&gt;maskSecrets()&lt;/code&gt; before the payload leaves the process — third-party API keys, auth headers, and webhook signing secrets no longer travel in plaintext. &lt;code&gt;deep_research&lt;/code&gt; stopped writing LLM API keys to Winston file logs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Billing.&lt;/strong&gt; A throw from the credit check itself now bills &lt;strong&gt;zero&lt;/strong&gt;; the error-path half-charge only applies once the handler has actually started. &lt;code&gt;checkCredits&lt;/code&gt; distinguishes 401/403 (invalid or revoked key) from 5xx (grace window) instead of reporting both as "insufficient credits."&lt;br&gt;
&lt;/p&gt;

&lt;br&gt;
&lt;p&gt;&lt;/p&gt;

&lt;p&gt;If you want the general version of this problem rather than our specific one, we wrote it up separately: &lt;a href="https://www.crawlforge.dev/blog/mcp-server-ssrf-cloud-metadata-security" rel="noopener noreferrer"&gt;SSRF in MCP servers&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 2: 52 ways tools were silently wrong
&lt;/h2&gt;

&lt;p&gt;This is the "passes smoke tests, returns misleading output" class — the one that never shows up as an error in your logs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;crawl_deep&lt;/code&gt; is usable for real crawls again.&lt;/strong&gt; BFS child pages were awaited from inside an occupied queue slot, so the per-task queue timeout bounded the &lt;em&gt;entire recursive crawl&lt;/em&gt; rather than one page. Any crawl outliving the 30-second timeout threw away every page it had already fetched with a bare &lt;code&gt;Promise timed out&lt;/code&gt;, and low concurrency settings (including &lt;code&gt;concurrency: 1&lt;/code&gt;) deadlocked outright. Both fixed.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  A representative sample of the other 51
  &lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cache keys that contradicted the request.&lt;/strong&gt; &lt;code&gt;crawl_deep&lt;/code&gt;'s result-cache key now covers &lt;code&gt;extract_content&lt;/code&gt;, content length, include/exclude patterns, &lt;code&gt;follow_external&lt;/code&gt;, &lt;code&gt;respect_robots&lt;/code&gt;, &lt;code&gt;concurrency&lt;/code&gt;, domain filter, and session. &lt;code&gt;map_site&lt;/code&gt;'s covers &lt;code&gt;search&lt;/code&gt;, domain filter, &lt;code&gt;include_metadata&lt;/code&gt;, and &lt;code&gt;group_by_path&lt;/code&gt;. Previously a cached call could contradict your parameters for a full hour-long TTL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Character encoding.&lt;/strong&gt; Bodies decode with their declared charset (&lt;code&gt;Content-Type&lt;/code&gt; header or &lt;code&gt;&amp;lt;meta charset&amp;gt;&lt;/code&gt; sniff) instead of always UTF-8. No more U+FFFD soup from ISO-8859-1 or Shift_JIS sites.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Silently stripped options.&lt;/strong&gt; The &lt;code&gt;options&lt;/code&gt; schemas for &lt;code&gt;extract_content&lt;/code&gt;, &lt;code&gt;summarize_content&lt;/code&gt;, and &lt;code&gt;analyze_content&lt;/code&gt; now use &lt;code&gt;.passthrough()&lt;/code&gt;. Every documented option key was being stripped before it reached the handler — which is &lt;em&gt;also&lt;/em&gt; why &lt;code&gt;summarize_content&lt;/code&gt; always returned the same 2-sentence fallback mislabeled &lt;code&gt;extractive&lt;/code&gt;. The extractive summarizer now actually runs, and &lt;code&gt;summaryLength&lt;/code&gt; changes the output.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Link resolution.&lt;/strong&gt; &lt;code&gt;extract_links&lt;/code&gt; resolves relative hrefs against the final page URL rather than the origin, honors &lt;code&gt;&amp;lt;base href&amp;gt;&lt;/code&gt;, and classifies protocol-relative links as external. The same fixes landed in &lt;code&gt;scrape&lt;/code&gt;'s extractor, so the two finally agree.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;track_changes&lt;/code&gt; similarity.&lt;/strong&gt; Now token-Jaccard over the content. It was previously Hamming distance between sha256 hex digests — so every trivial edit scored roughly 0% similar and fired a "moderate change" alert.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;search_web&lt;/code&gt; scoring.&lt;/strong&gt; Partial &lt;code&gt;ranking_weights&lt;/code&gt; deep-merge over the defaults instead of replacing them wholesale, so no more &lt;code&gt;NaN&lt;/code&gt; final scores or silently disabled duplicate checks. The zero-result expansion retry is capped at one fallback instead of up to five billed backend searches.
&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Phase 3: safe to run for days
&lt;/h2&gt;

&lt;p&gt;24 findings in the class that only surfaces in long-running processes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Browser lifecycle.&lt;/strong&gt; Closing a Playwright page does not close its context — so every &lt;code&gt;scrape_with_actions&lt;/code&gt; call and every browser-rendered &lt;code&gt;extract_content&lt;/code&gt; leaked one context until shutdown. Contexts are now closed alongside their page, and a failed &lt;code&gt;page.goto&lt;/code&gt; (DNS error, timeout, blocked URL) tears down both instead of orphaning them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bounded caches.&lt;/strong&gt; &lt;code&gt;crawl_deep&lt;/code&gt; destroys its per-crawl &lt;code&gt;CacheManager&lt;/code&gt; in a &lt;code&gt;finally&lt;/code&gt;. Previously N crawls permanently leaked N caches of up to 1,000 full HTML documents each — every one of them re-running a &lt;code&gt;JSON.stringify&lt;/code&gt; memory scan every 60 seconds, forever. Dropped instances are now GC-verified with a &lt;code&gt;WeakRef&lt;/code&gt; regression test.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deadlines on every body read.&lt;/strong&gt; The abort timer stays armed through the body stream, so &lt;code&gt;timeout&lt;/code&gt; finally covers a server that returns headers and then stalls. Chunk reassembly is single-pass — it was O(n²), roughly 1.5 seconds of synchronous event-loop block on a 25 MB body. PDF downloads got a real &lt;code&gt;AbortSignal.timeout&lt;/code&gt; (the old &lt;code&gt;timeout:&lt;/code&gt; fetch-init option is silently ignored by undici).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One for Claude Desktop users:&lt;/strong&gt; snapshot storage defaults to &lt;code&gt;~/.crawlforge/snapshots&lt;/code&gt; instead of &lt;code&gt;process.cwd()&lt;/code&gt;. MCP clients launch the server with a working directory of &lt;code&gt;/&lt;/code&gt;, where every snapshot write silently failed.&lt;/p&gt;
&lt;h2&gt;
  
  
  Phase 4: HTTP mode only ever had one session
&lt;/h2&gt;

&lt;p&gt;If you deployed over &lt;code&gt;npm run start:http&lt;/code&gt;, it was worse than you thought. A single shared transport meant exactly one session ever existed, and any clean disconnect bricked &lt;code&gt;/mcp&lt;/code&gt; until you restarted the process.&lt;/p&gt;

&lt;p&gt;Stateful mode now follows the SDK's documented per-session pattern — a &lt;code&gt;Map&amp;lt;sessionId, {transport, server}&amp;gt;&lt;/code&gt; with a fresh transport and cloned &lt;code&gt;McpServer&lt;/code&gt; per &lt;code&gt;initialize&lt;/code&gt;, disposal on DELETE, and a JSON-RPC 404 for unknown session IDs. Second concurrent client, reconnect after a network drop, DELETE then fresh initialize: all work now.&lt;/p&gt;

&lt;p&gt;Also in Phase 4:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;getting-started&lt;/code&gt; prompt was &lt;strong&gt;unretrievable by any client&lt;/strong&gt; — the config object hit the SDK's positional &lt;code&gt;argsSchema&lt;/code&gt; overload, advertising a bogus required argument and failing every &lt;code&gt;prompts/get&lt;/code&gt;. The compliance suite now covers discovery and retrieval for all 6 prompts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Webhook HMAC signatures cover the exact serialized body that is POSTed.&lt;/strong&gt; Only the &lt;code&gt;data&lt;/code&gt; sub-object was being signed, so standard receiver-side raw-body verification failed every single time.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;scrape&lt;/code&gt; no longer inlines multi-megabyte base64 screenshots into the JSON result — it keeps metadata plus a &lt;code&gt;crawlforge://screenshot/{id}&lt;/code&gt; resource URI.&lt;/li&gt;
&lt;li&gt;Auto-setup banners moved from stdout to stderr, so a first launch no longer injects non-JSON lines into the stdio JSON-RPC channel.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Phase 5: zero npm audit vulnerabilities
&lt;/h2&gt;

&lt;p&gt;With the Node 20 floor in place, we retired every abandoned dependency and took the security upgrades the old floor had blocked. 4 moderate → &lt;strong&gt;0&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Removed outright: &lt;code&gt;node-cron&lt;/code&gt; (unused after Phase 3 moved scheduling to &lt;code&gt;setInterval&lt;/code&gt;; removal cleared its vulnerable &lt;code&gt;uuid&lt;/code&gt; chain), &lt;code&gt;@googleapis/customsearch&lt;/code&gt; (unused — the Google adapter calls the REST endpoint directly), and &lt;code&gt;node-summarizer&lt;/code&gt; (abandoned since 2019; the extractive summarizer was rewritten as a &lt;code&gt;compromise&lt;/code&gt;-based Luhn-style word-frequency scorer with identical result shapes).&lt;/p&gt;

&lt;p&gt;The upgrade that mattered most: &lt;strong&gt;&lt;code&gt;pdf-parse&lt;/code&gt; 1.1.1 → 2.4.5&lt;/strong&gt;. &lt;code&gt;PDFProcessor&lt;/code&gt; was ported to the v2 class API, so the &lt;code&gt;password&lt;/code&gt; option now actually decrypts protected PDFs — v1 silently ignored it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On supply chain:&lt;/strong&gt; this phase ran during the ChainDrop npm worm. Every install ran with &lt;code&gt;--ignore-scripts&lt;/code&gt;, every adopted version was publish-date-gated, and the full lockfile diff was cross-checked against public compromised-package lists with zero matches.&lt;/p&gt;
&lt;h2&gt;
  
  
  Phase 6: MCP spec adoption
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Structured output (MCP 2025-06-18).&lt;/strong&gt; &lt;code&gt;scrape&lt;/code&gt;, &lt;code&gt;map_site&lt;/code&gt;, &lt;code&gt;serp_rank&lt;/code&gt;, &lt;code&gt;search_web&lt;/code&gt;, &lt;code&gt;extract_structured&lt;/code&gt;, and &lt;code&gt;crawl_deep&lt;/code&gt; declare an &lt;code&gt;outputSchema&lt;/code&gt; and return &lt;code&gt;structuredContent&lt;/code&gt; alongside the legacy JSON text. The schemas are permissive by design, so a legitimate result can never fail SDK output validation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Async tasks.&lt;/strong&gt; &lt;code&gt;crawl_deep&lt;/code&gt;, &lt;code&gt;batch_scrape&lt;/code&gt;, &lt;code&gt;deep_research&lt;/code&gt;, and &lt;code&gt;agent&lt;/code&gt; are registered with &lt;code&gt;taskSupport: 'optional'&lt;/code&gt; under the &lt;code&gt;io.modelcontextprotocol/tasks&lt;/code&gt; extension. Task-aware clients get a handle immediately and poll &lt;code&gt;tasks/get&lt;/code&gt;; clients without task support still get the synchronous result exactly as before. This is the fix for long crawls timing out inside a client's tool-call window.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Client-side tool selection.&lt;/strong&gt; Two env vars let you expose a subset of the 27 tools and cut context bloat:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# By name&lt;/span&gt;
&lt;span class="nv"&gt;CRAWLFORGE_TOOLS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;scrape,search_web,extract_content

&lt;span class="c"&gt;# Or by group — 12 available: basic, search, crawl, extract, batch,&lt;/span&gt;
&lt;span class="c"&gt;# research, tracking, llmstxt, stealth, templates, scrape, agent&lt;/span&gt;
&lt;span class="nv"&gt;CRAWLFORGE_TOOL_GROUPS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;search,extract
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unset means all tools. Unknown names are ignored with a stderr warning, and &lt;code&gt;batch_scrape&lt;/code&gt; auto-enables &lt;code&gt;get_batch_results&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Protocol hygiene.&lt;/strong&gt; Schemas advertised in JSON Schema 2020-12 instead of draft-07. &lt;code&gt;tools/list&lt;/code&gt; sorted deterministically for client prompt-cache stability. Invalid tool arguments come back as &lt;code&gt;isError: true&lt;/code&gt; tool results — which a calling model can self-correct from — rather than &lt;code&gt;-32602&lt;/code&gt; protocol errors. And &lt;code&gt;server.json&lt;/code&gt; is complete against the 2025-12-11 registry schema.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Missed v4.9.0 and v4.10.0? Two things landed in between
  &lt;br&gt;
&lt;strong&gt;v4.9.0&lt;/strong&gt; added &lt;code&gt;serp_rank&lt;/code&gt;, the &lt;strong&gt;27th tool&lt;/strong&gt; — real Google organic rank positions via DataForSEO, 5 credits per configured lookup. &lt;strong&gt;v4.10.0&lt;/strong&gt; made it return the full top-10 organic listing alongside your target domain's positions. &lt;a href="https://www.crawlforge.dev/docs/api-reference/tools/serp-rank" rel="noopener noreferrer"&gt;Docs&lt;/a&gt;.

&lt;p&gt;&lt;strong&gt;v4.10.0&lt;/strong&gt; also added server-level MCP &lt;code&gt;instructions&lt;/code&gt;: the server tells any connecting client to prefer CrawlForge tools over its own built-in web capabilities. It ships in the server binary, so every client picks it up on the next launch after upgrade — no re-&lt;code&gt;init&lt;/code&gt;. It is guidance, not enforcement; an MCP server cannot disable a client's built-in tools.&lt;br&gt;
&lt;/p&gt;

&lt;br&gt;
&lt;p&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing and how to upgrade
&lt;/h2&gt;

&lt;p&gt;Nothing changed. All &lt;strong&gt;27 tools&lt;/strong&gt; are metered and require an API key, at 1-10 credits per call.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Plan&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;th&gt;Credits&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;$0 (no card)&lt;/td&gt;
&lt;td&gt;1,000 one-time trial (does not reset)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hobby&lt;/td&gt;
&lt;td&gt;$19/mo&lt;/td&gt;
&lt;td&gt;5,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Professional&lt;/td&gt;
&lt;td&gt;$99/mo&lt;/td&gt;
&lt;td&gt;50,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Business&lt;/td&gt;
&lt;td&gt;$399/mo&lt;/td&gt;
&lt;td&gt;250,000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every plan gets every tool. LLM extraction defaults to local Ollama, so you do not need an OpenAI or Anthropic key unless you opt in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# existing users&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; crawlforge-mcp-server@latest   &lt;span class="c"&gt;# or an /mcp reconnect&lt;/span&gt;

&lt;span class="c"&gt;# new users&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; crawlforge-mcp-server &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npx crawlforge init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because Phase 2 fixed tool &lt;em&gt;behavior&lt;/em&gt; rather than tool &lt;em&gt;contracts&lt;/em&gt;, your existing calls keep working — they just return correct results now.&lt;/p&gt;

&lt;p&gt;Deferred rather than rushed: a hosted remote endpoint with OAuth, a keyless tier, scheduled monitoring as a service, persistent sessions, and PII redaction.&lt;/p&gt;

&lt;p&gt;Writing up your own bugs is uncomfortable, but "advertised control, silently non-functional" is the single most common failure mode we found across all seven phases — and it is invisible from the outside. If you find a CrawlForge control that does not behave the way the docs claim, that is exactly the bug we want.&lt;/p&gt;

&lt;p&gt;npm: &lt;a href="https://www.npmjs.com/package/crawlforge-mcp-server" rel="noopener noreferrer"&gt;&lt;code&gt;crawlforge-mcp-server&lt;/code&gt;&lt;/a&gt; · &lt;a href="https://www.crawlforge.dev/blog/crawlforge-v5-0-0-security-hardening-mcp-spec" rel="noopener noreferrer"&gt;full v5.0.0 writeup&lt;/a&gt; · &lt;a href="https://www.crawlforge.dev/blog/crawlforge-v4-8-0-claude-agent-skills" rel="noopener noreferrer"&gt;v4.8.0 release post&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.crawlforge.dev/signup" class="crayons-btn crayons-btn--primary" rel="noopener noreferrer"&gt;Start free with 1,000 credits&lt;/a&gt;
&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>security</category>
      <category>node</category>
      <category>webscraping</category>
    </item>
    <item>
      <title>My Claude Code skills never auto-activated either — here's what we fixed</title>
      <dc:creator>Simon</dc:creator>
      <pubDate>Mon, 29 Jun 2026 12:50:19 +0000</pubDate>
      <link>https://dev.to/simon_crawlforge_dev/my-claude-code-skills-never-auto-activated-either-heres-what-we-fixed-2o82</link>
      <guid>https://dev.to/simon_crawlforge_dev/my-claude-code-skills-never-auto-activated-either-heres-what-we-fixed-2o82</guid>
      <description>&lt;p&gt;If you have ever dropped a markdown "skill" file into &lt;code&gt;~/.claude/skills/&lt;/code&gt; and watched Claude completely ignore it, you are not imagining things. The file sits there, but nothing tells the model &lt;em&gt;when&lt;/em&gt; it is relevant — so it never fires.&lt;/p&gt;

&lt;p&gt;We had exactly that problem. CrawlForge shipped reference-markdown files that were supposed to teach Claude how to use our 26 web-scraping tools. They sat on disk. Claude never actually loaded them. You still had to spell out &lt;em&gt;"use the stealth_mode tool to scrape this"&lt;/em&gt; — which defeats the point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.npmjs.com/package/crawlforge-mcp-server" rel="noopener noreferrer"&gt;CrawlForge MCP Server&lt;/a&gt; v4.8.0&lt;/strong&gt; (shipped June 28, 2026) fixes that. It is a fully additive minor release: the tool count stays &lt;strong&gt;26&lt;/strong&gt;, and no tool schema, output shape, or credit cost changes for existing callers. Here is what changed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Before / after&lt;/li&gt;
&lt;li&gt;7 Claude Agent Skills that actually auto-activate&lt;/li&gt;
&lt;li&gt;Two new scrape formats: branding and screenshot&lt;/li&gt;
&lt;li&gt;Built-in scheduled change monitoring&lt;/li&gt;
&lt;li&gt;Security: controls that were advertised but silently broken&lt;/li&gt;
&lt;li&gt;Pricing and how to upgrade&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Before / after
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BEFORE: "Use the crawlforge stealth_mode tool to scrape this protected page."
        +--&amp;gt; you name the tool, every time

AFTER:  "Scrape this Cloudflare-protected page for me."
        +--&amp;gt; Claude matches the prompt, loads the stealth-browsing skill,
             and calls the right tool on its own
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One behavior change to flag up front, Stripe-changelog style: &lt;strong&gt;clients that support MCP elicitation will now see cost and safety confirmations&lt;/strong&gt; that previously failed to appear (more on that below). Everything else is purely additive.&lt;/p&gt;

&lt;p&gt;Upgrade in one line, then run init:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; crawlforge-mcp-server@latest
npx crawlforge init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Added:&lt;/strong&gt; 7 auto-activating Agent Skills, &lt;code&gt;branding&lt;/code&gt; + &lt;code&gt;screenshot&lt;/code&gt; scrape formats, scheduled change monitoring, &lt;code&gt;list_scheduled_monitors&lt;/code&gt;.&lt;br&gt;
&lt;strong&gt;Fixed:&lt;/strong&gt; SSRF now enforced on the live path, MCP elicitation now fires, screenshots actually render.&lt;br&gt;
&lt;strong&gt;Security:&lt;/strong&gt; per-host rate limiting, &lt;code&gt;executeJavaScript&lt;/code&gt; hardening, DNS-rebinding protection.&lt;/p&gt;
&lt;h2&gt;
  
  
  7 Claude Agent Skills that actually auto-activate
&lt;/h2&gt;

&lt;p&gt;A skill is a folder containing a &lt;code&gt;SKILL.md&lt;/code&gt; file with YAML frontmatter. At startup Claude pre-loads only the &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;description&lt;/code&gt; of every installed skill, then reads the full body &lt;strong&gt;only when it judges the skill relevant&lt;/strong&gt; to your prompt. Anthropic calls this progressive disclosure — skills are not always-loaded context, they are loaded on demand.&lt;/p&gt;

&lt;p&gt;The catch most people miss: auto-activation is &lt;strong&gt;model-judged&lt;/strong&gt;, not guaranteed. The quality of that &lt;code&gt;description&lt;/code&gt; field is what decides whether the right skill fires. Here is the frontmatter shape we now ship:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;crawlforge-stealth-browsing&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;gt;-"&lt;/span&gt;
  &lt;span class="s"&gt;Scrape sites protected by Cloudflare, anti-bot, or JavaScript&lt;/span&gt;
  &lt;span class="s"&gt;rendering. Use when a normal fetch is blocked, returns a challenge&lt;/span&gt;
  &lt;span class="s"&gt;page, or the content is rendered client-side. Triggers on&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bypass&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;bot&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;detection"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Cloudflare"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;headless"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stealth".&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Trigger-rich descriptions dramatically raise the probability the right skill fires. v4.8.0 ships &lt;strong&gt;seven&lt;/strong&gt; skills covering all 26 tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;crawlforge-web-scraping&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;crawlforge-deep-research&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;crawlforge-stealth-browsing&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;crawlforge-structured-extraction&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;crawlforge-change-tracking&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;crawlforge-batch-automation&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;crawlforge-getting-started&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They install to the personal scope at &lt;code&gt;~/.claude/skills/&amp;lt;name&amp;gt;/SKILL.md&lt;/code&gt;, and because activation is a heuristic, you can always name the skill or tool explicitly in your prompt to force it.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  How skills relate to MCP (they complement, not replace)
  &lt;br&gt;
MCP and skills solve different halves of the same problem. MCP &lt;strong&gt;exposes&lt;/strong&gt; the 26 tools to Claude. Skills &lt;strong&gt;teach Claude when and how to use them&lt;/strong&gt; — think of MCP as giving a new hire access to the tools, and skills as the onboarding guide that explains which tool to reach for.

&lt;p&gt;Upgrades self-heal: the installer removes the legacy bare reference files and leaves unrelated skills untouched. &lt;code&gt;npm run skills:gen&lt;/code&gt; regenerates the root &lt;code&gt;SKILL.md&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Want to push activation even harder? There is an &lt;strong&gt;opt-in&lt;/strong&gt; forced-eval hook — an idempotent &lt;code&gt;UserPromptSubmit&lt;/code&gt; reminder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx crawlforge init &lt;span class="nt"&gt;--with-hook&lt;/span&gt;          &lt;span class="c"&gt;# or: install-skills --with-hook&lt;/span&gt;
npx crawlforge uninstall-skills &lt;span class="nt"&gt;--remove-hook&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is &lt;strong&gt;OFF by default&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;br&gt;
&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npx crawlforge init&lt;/code&gt; does the whole setup: configures your API key, installs the skills, and registers the MCP server with your AI clients.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two new scrape formats: branding and screenshot
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;scrape&lt;/code&gt; tool gained two formats. Both cost the same &lt;strong&gt;2 credits&lt;/strong&gt; as before.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;branding&lt;/code&gt;&lt;/strong&gt; extracts design tokens statically from HTML + CSS with &lt;strong&gt;no browser required&lt;/strong&gt; — color palette, fonts and typography, logo and favicons, plus &lt;code&gt;border-radius&lt;/code&gt;, shadow, and spacing tokens. It is SSRF-guarded, and linked-CSS fetches are count- and size-capped.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://stripe.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"formats"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"branding"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;screenshot&lt;/code&gt;&lt;/strong&gt; now actually works (it was a no-op before). It lazily renders through the shared browser pool and returns &lt;code&gt;crawlforge://screenshot/{id}&lt;/code&gt; MCP resources. The browser launches &lt;strong&gt;only&lt;/strong&gt; when you request a screenshot, and a render failure degrades to a warning so partial success is preserved.&lt;/p&gt;

&lt;h2&gt;
  
  
  Built-in scheduled change monitoring
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;track_changes&lt;/code&gt; (3 credits) gained real scheduling operations — &lt;code&gt;create_scheduled_monitor&lt;/code&gt;, &lt;code&gt;stop_scheduled_monitor&lt;/code&gt;, and a new &lt;code&gt;list_scheduled_monitors&lt;/code&gt;. These were previously dead code that threw. They are now backed by a persisted scheduler (&lt;code&gt;MonitorScheduler.js&lt;/code&gt; + &lt;code&gt;MonitorStore.js&lt;/code&gt;), and baselines rehydrate from snapshots on restart.&lt;/p&gt;

&lt;p&gt;You can attach an optional plain-English &lt;strong&gt;goal&lt;/strong&gt; that is LLM-judged (Ollama-first) and degrades gracefully to threshold significance when no LLM is available — e.g. &lt;em&gt;"alert me only when the pricing changes, not when the copyright year flips."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  The honest firing model (read this before you rely on it)
  &lt;br&gt;
A stdio MCP server is &lt;strong&gt;not a long-lived daemon&lt;/strong&gt; — it only runs while your client has it open. So reliable scheduled firing uses the CLI plus system cron:&lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;crawlforge monitor:create &lt;span class="nt"&gt;--url&lt;/span&gt; https://api.example.com/changelog
crawlforge monitor:list
crawlforge monitor:stop &amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;# system cron runs this; it guarantees due monitors fire:&lt;/span&gt;
&lt;span class="k"&gt;*&lt;/span&gt;/30 &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; crawlforge monitor:run-due
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;monitor:run-due&lt;/code&gt; is a one-shot designed for cron. We would rather tell you this than pretend a stdio process magically wakes itself up.&lt;br&gt;
&lt;/p&gt;

&lt;br&gt;
&lt;p&gt;&lt;/p&gt;

&lt;p&gt;See the &lt;a href="https://www.crawlforge.dev/docs/api-reference/tools/track-changes" rel="noopener noreferrer"&gt;track_changes docs&lt;/a&gt; for the full schema.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security: controls that were advertised but silently broken
&lt;/h2&gt;

&lt;p&gt;MCP servers are now a recognized SSRF attack surface. A web-scraping server that fetches arbitrary URLs on your behalf is exactly the shape of thing an attacker points at the cloud-metadata endpoint (&lt;code&gt;169.254.169.254&lt;/code&gt;) to read credentials. We audited our own posture and found two controls that were &lt;em&gt;advertised but silently non-functional.&lt;/em&gt; Both are fixed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SSRF is now enforced on the live path.&lt;/strong&gt; A robust &lt;code&gt;ssrfProtection.js&lt;/code&gt; existed in the codebase but was never wired into the tools — every scrape used raw &lt;code&gt;fetch()&lt;/code&gt; with zero IP/host validation. A new &lt;code&gt;ssrfGuard.js&lt;/code&gt; injects an undici dispatcher whose connect-time lookup validates &lt;strong&gt;every connection — the initial request and every redirect hop — and pins to the validated IP&lt;/strong&gt;, closing the DNS-rebinding TOCTOU window.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Stage 1 (default): blocks loopback, link-local / cloud-metadata&lt;/span&gt;
&lt;span class="c"&gt;#                     (169.254.169.254), and 0.0.0.0&lt;/span&gt;
&lt;span class="nv"&gt;SSRF_STRICT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;              &lt;span class="c"&gt;# adds full RFC1918 / ULA private-range enforcement&lt;/span&gt;
&lt;span class="nv"&gt;ALLOWED_DOMAINS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;internal.corp &lt;span class="c"&gt;# trusted-host bypass&lt;/span&gt;
&lt;span class="nv"&gt;SSRF_PROTECTION_ENABLED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt; &lt;span class="c"&gt;# kill switch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is routed through roughly 14 modules — the basic fetch path, batch scrape, &lt;code&gt;map_site&lt;/code&gt;, &lt;code&gt;crawl&lt;/code&gt;, &lt;code&gt;extract&lt;/code&gt;, &lt;code&gt;process_document&lt;/code&gt;, &lt;code&gt;research&lt;/code&gt;, &lt;code&gt;llms-txt&lt;/code&gt;, robots/sitemap, and the &lt;code&gt;track_changes&lt;/code&gt; differ.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MCP elicitation now actually fires.&lt;/strong&gt; The old code called &lt;code&gt;server.elicit()&lt;/code&gt; — a method that does not exist — and never checked the client capability, so every cost/safety confirmation (for example, deep_research over 50 URLs, batch_scrape, and crawl_deep) silently fail-opened. It now uses &lt;code&gt;elicitInput&lt;/code&gt;, gates on the client's elicitation capability, and parses the &lt;code&gt;accept&lt;/code&gt; / &lt;code&gt;decline&lt;/code&gt; / &lt;code&gt;cancel&lt;/code&gt; action. It still fail-opens for clients that do not support elicitation — but capable clients will finally see the prompts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two more layers of defense-in-depth:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Per-host rate limiting&lt;/strong&gt; (&lt;code&gt;hostRateLimiter.js&lt;/code&gt;): default 10 req/s per host via &lt;code&gt;RATE_LIMIT_PER_DOMAIN&lt;/code&gt;, with no global cap, so broad multi-host crawls are unaffected. This is politeness/defense, not an SSRF boundary itself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;executeJavaScript&lt;/code&gt; hardening&lt;/strong&gt; (still OFF by default): &lt;code&gt;JS_MAX_SCRIPT_LENGTH&lt;/code&gt;, &lt;code&gt;JS_EXECUTION_TIMEOUT_MS&lt;/code&gt;, and a structured stderr audit log (script sha256 + length + url).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Pricing and how to upgrade
&lt;/h2&gt;

&lt;p&gt;No new tools — the new capabilities were added to existing ones, so the count stays &lt;strong&gt;26&lt;/strong&gt;. All 26 are metered and require an API key; costs range &lt;strong&gt;1-10 credits&lt;/strong&gt; per call. Heads up: &lt;code&gt;list_ollama_models&lt;/code&gt; is now &lt;strong&gt;1 credit&lt;/strong&gt; (it used to be free), so nothing is free per-call.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Plan&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;th&gt;Credits&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;$0 (no card)&lt;/td&gt;
&lt;td&gt;1,000 one-time trial (does not reset)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hobby&lt;/td&gt;
&lt;td&gt;$19/mo&lt;/td&gt;
&lt;td&gt;5,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Professional&lt;/td&gt;
&lt;td&gt;$99/mo&lt;/td&gt;
&lt;td&gt;50,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Business&lt;/td&gt;
&lt;td&gt;$399/mo&lt;/td&gt;
&lt;td&gt;250,000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every plan gets every tool. LLM extraction defaults to &lt;strong&gt;local Ollama&lt;/strong&gt;, so you do not need an OpenAI or Anthropic key unless you opt in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# new users&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; crawlforge-mcp-server &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npx crawlforge init

&lt;span class="c"&gt;# existing users&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; crawlforge-mcp-server@latest   &lt;span class="c"&gt;# or an /mcp reconnect&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Re-running &lt;code&gt;init&lt;/code&gt; (or &lt;code&gt;install-skills&lt;/code&gt;) gets you the 7 skills and self-heals the legacy bare files. v4.8.0 is additive, so nothing breaks. This continues the 4.7.x correctness work: 4.7.2 live-audited all 26 tools (&lt;code&gt;scrape_with_actions&lt;/code&gt;, &lt;code&gt;extract_structured&lt;/code&gt;, &lt;code&gt;resources/read&lt;/code&gt;), 4.7.1 fixed &lt;code&gt;deep_research&lt;/code&gt; &lt;code&gt;credibilityThreshold&lt;/code&gt; and &lt;code&gt;generate_llms_txt&lt;/code&gt; emitting literal "undefined", and 4.7.0 moved to a fully metered model.&lt;/p&gt;

&lt;p&gt;That is the whole release: skills that fire, controls that enforce, screenshots that render. &lt;strong&gt;Try it, break it, and tell us what does not work&lt;/strong&gt; — that feedback is what drives this cadence.&lt;/p&gt;

&lt;p&gt;npm: &lt;a href="https://www.npmjs.com/package/crawlforge-mcp-server" rel="noopener noreferrer"&gt;&lt;code&gt;crawlforge-mcp-server&lt;/code&gt;&lt;/a&gt; · &lt;a href="https://www.crawlforge.dev/blog/best-mcp-servers-web-scraping-2026" rel="noopener noreferrer"&gt;Best MCP servers for web scraping in 2026&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.crawlforge.dev/signup" class="crayons-btn crayons-btn--primary" rel="noopener noreferrer"&gt;Start free with 1,000 credits&lt;/a&gt;
&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>claude</category>
      <category>webscraping</category>
      <category>security</category>
    </item>
    <item>
      <title>How to Give ChatGPT Web Scraping with MCP Connectors (2026)</title>
      <dc:creator>Simon</dc:creator>
      <pubDate>Tue, 16 Jun 2026 20:20:51 +0000</pubDate>
      <link>https://dev.to/simon_crawlforge_dev/how-to-give-chatgpt-web-scraping-with-mcp-connectors-2026-4ba6</link>
      <guid>https://dev.to/simon_crawlforge_dev/how-to-give-chatgpt-web-scraping-with-mcp-connectors-2026-4ba6</guid>
      <description>&lt;p&gt;ChatGPT can now call your own tools through custom MCP connectors — including web scraping. But there is a catch the marketing pages skip: connectors must be &lt;strong&gt;remote&lt;/strong&gt; servers, so a local tool like CrawlForge cannot be pasted in directly. This is the honest version: what is actually possible, why a wrapper is needed, and the exact bridge to build.&lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
&lt;strong&gt;TL;DR:&lt;/strong&gt; ChatGPT custom MCP connectors (renamed "apps" in Dec 2025) work on &lt;strong&gt;Plus, Pro, Business, Enterprise, and Edu&lt;/strong&gt; via Developer mode — &lt;strong&gt;not&lt;/strong&gt; Free/Go. Connectors must be &lt;strong&gt;remote HTTPS&lt;/strong&gt; servers, so a local stdio server like &lt;a href="https://www.crawlforge.dev" rel="noopener noreferrer"&gt;CrawlForge&lt;/a&gt; can't be added directly. The fix: a ~30-line remote MCP wrapper that proxies CrawlForge's REST API.&lt;br&gt;

&lt;/div&gt;


&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What ChatGPT Connectors Are&lt;/li&gt;
&lt;li&gt;Which Plans Can Use Them&lt;/li&gt;
&lt;li&gt;The Transport Catch: Remote Only&lt;/li&gt;
&lt;li&gt;Why CrawlForge Needs a Wrapper&lt;/li&gt;
&lt;li&gt;Build the Bridge&lt;/li&gt;
&lt;li&gt;Add the Connector in ChatGPT&lt;/li&gt;
&lt;li&gt;Auth and Safety&lt;/li&gt;
&lt;li&gt;A Simpler Alternative&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What ChatGPT Connectors Are
&lt;/h2&gt;

&lt;p&gt;ChatGPT supports &lt;strong&gt;custom MCP connectors&lt;/strong&gt; — renamed &lt;strong&gt;"apps"&lt;/strong&gt; in December 2025, so the UI now says "Apps &amp;amp; Connectors." Through &lt;strong&gt;Developer mode&lt;/strong&gt;, you connect an external MCP server and ChatGPT calls its tools mid-conversation, asking you to confirm before any write action. Same Model Context Protocol that powers web scraping in Claude — different client. Developer mode is explicitly a &lt;strong&gt;beta&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which Plans Can Use Them
&lt;/h2&gt;

&lt;p&gt;Per OpenAI's plan table, adding a custom MCP connector is available on &lt;strong&gt;Plus, Pro, Business, Enterprise, and Edu&lt;/strong&gt; — not Free or Go. Full write-action support is rolling out most broadly to Business, Enterprise, and Edu. If you only need ChatGPT to &lt;em&gt;read&lt;/em&gt; scraped data, the read-only path below is enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Transport Catch: Remote Only
&lt;/h2&gt;

&lt;p&gt;This trips people up. &lt;strong&gt;A ChatGPT connector must be a remote MCP server reachable over HTTPS&lt;/strong&gt; (SSE or Streamable HTTP transport). You paste a URL; you do not point it at a command on your machine. That rules out &lt;strong&gt;local stdio servers&lt;/strong&gt; — the kind you install with &lt;code&gt;npx&lt;/code&gt;. To use one, host it publicly or tunnel a local server via ngrok or Cloudflare Tunnel.&lt;/p&gt;

&lt;p&gt;There is also a naming rule: ChatGPT's &lt;strong&gt;deep research / company-knowledge&lt;/strong&gt; paths require two read-only tools named &lt;code&gt;search&lt;/code&gt; and &lt;code&gt;fetch&lt;/code&gt; with a specific schema. Full &lt;strong&gt;Developer mode&lt;/strong&gt; allows arbitrary tools, so that constraint applies only to the deep-research path.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why CrawlForge Needs a Wrapper
&lt;/h2&gt;

&lt;p&gt;CrawlForge ships as a &lt;strong&gt;local stdio MCP server&lt;/strong&gt; (via &lt;code&gt;npx&lt;/code&gt;) plus a &lt;strong&gt;REST API&lt;/strong&gt; at &lt;code&gt;https://www.crawlforge.dev/api/v1/tools/&lt;/code&gt;. Neither is a remote MCP URL, and its tools are named &lt;code&gt;search_web&lt;/code&gt;, &lt;code&gt;fetch_url&lt;/code&gt;, and &lt;code&gt;extract_content&lt;/code&gt; — not the &lt;code&gt;search&lt;/code&gt;/&lt;code&gt;fetch&lt;/code&gt; pair deep research expects. So you cannot paste CrawlForge straight into ChatGPT today. The practical path is a &lt;strong&gt;thin remote MCP wrapper&lt;/strong&gt; — about 30 lines.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build the Bridge
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://gofastmcp.com/integrations/chatgpt" rel="noopener noreferrer"&gt;FastMCP&lt;/a&gt; (Python) is the quickest way to stand up a remote MCP server exposing the &lt;code&gt;search&lt;/code&gt; + &lt;code&gt;fetch&lt;/code&gt; tools ChatGPT wants. Each calls CrawlForge's REST API with your &lt;code&gt;cf_live_&lt;/code&gt; key in the &lt;code&gt;X-API-Key&lt;/code&gt; header:&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  server.py — the full bridge
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastmcp&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastMCP&lt;/span&gt;

&lt;span class="n"&gt;mcp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastMCP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CrawlForge Bridge&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;BASE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://www.crawlforge.dev/api/v1/tools&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;HEADERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;X-API-Key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CRAWLFORGE_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;

&lt;span class="nd"&gt;@mcp.tool&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Search the web. Returns id/title/url results for ChatGPT.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AsyncClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;BASE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/search_web&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;HEADERS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                              &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;limit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;results&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;link&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;link&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nd"&gt;@mcp.tool&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Fetch full page content by id (the URL) for ChatGPT.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AsyncClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;BASE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/extract_content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;HEADERS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                              &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;mcp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transport&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.0.0.0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Run it and expose it over HTTPS. For a quick test, tunnel your local port:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;fastmcp httpx
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CRAWLFORGE_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"cf_live_your_key_here"&lt;/span&gt;
python server.py
&lt;span class="c"&gt;# in another terminal:&lt;/span&gt;
ngrok http 8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Developer mode you can skip the &lt;code&gt;search&lt;/code&gt;/&lt;code&gt;fetch&lt;/code&gt; naming and map tools one-to-one to CrawlForge — expose &lt;code&gt;scrape_structured&lt;/code&gt;, &lt;code&gt;stealth_mode&lt;/code&gt;, or &lt;code&gt;deep_research&lt;/code&gt; directly. Same pattern.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add the Connector in ChatGPT
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Settings → Apps &amp;amp; Connectors → Advanced&lt;/strong&gt; → enable &lt;strong&gt;Developer mode&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apps &amp;amp; Connectors → Create&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Paste your public HTTPS MCP URL (e.g. your ngrok URL plus &lt;code&gt;/mcp&lt;/code&gt;), name it, choose an auth method.&lt;/li&gt;
&lt;li&gt;Confirm the &lt;strong&gt;"I trust this application"&lt;/strong&gt; checkbox.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Your &lt;code&gt;search&lt;/code&gt; and &lt;code&gt;fetch&lt;/code&gt; tools appear. In a chat, select the connector and ask ChatGPT to research a topic — it calls &lt;code&gt;search&lt;/code&gt;, then &lt;code&gt;fetch&lt;/code&gt;es the best results through CrawlForge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Auth and Safety
&lt;/h2&gt;

&lt;p&gt;Connectors authenticate with &lt;strong&gt;none&lt;/strong&gt; (public) or &lt;strong&gt;OAuth&lt;/strong&gt; — there is no API-key-header option in the UI, which is why the wrapper holds your CrawlForge key server-side. ChatGPT confirms before write actions, and you can inspect each call before approving.&lt;/p&gt;

&lt;p&gt;Take OpenAI's warnings seriously: &lt;strong&gt;only connect servers you trust.&lt;/strong&gt; Custom connectors increase risk, including prompt injection, and a model mistake on a write action could destroy or leak data. A read-only scraping bridge is low-risk; lock it down with OAuth before sharing.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Simpler Alternative
&lt;/h2&gt;

&lt;p&gt;If you would rather not host anything, use CrawlForge from code with the OpenAI Agents SDK or Responses API — no remote server required. See &lt;a href="https://www.crawlforge.dev/blog/crawlforge-openai-agents-integration" rel="noopener noreferrer"&gt;CrawlForge with the OpenAI Agents SDK&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.crawlforge.dev/signup" class="crayons-btn crayons-btn--primary" rel="noopener noreferrer"&gt;Get a Free CrawlForge Key — 1,000 Credits&lt;/a&gt;
&lt;/p&gt;

</description>
      <category>chatgpt</category>
      <category>mcp</category>
      <category>ai</category>
      <category>webscraping</category>
    </item>
    <item>
      <title>How to Use Web Scraping Templates the Right Way (2026)</title>
      <dc:creator>Simon</dc:creator>
      <pubDate>Sat, 06 Jun 2026 15:23:29 +0000</pubDate>
      <link>https://dev.to/simon_crawlforge_dev/how-to-use-web-scraping-templates-the-right-way-2026-5bi4</link>
      <guid>https://dev.to/simon_crawlforge_dev/how-to-use-web-scraping-templates-the-right-way-2026-5bi4</guid>
      <description>&lt;p&gt;Most web scraping projects are not unique snowflakes. Track competitor prices. Enrich a list of leads. Audit a site for SEO. Pull training data for a model. It is the same handful of recipes, over and over.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;web scraping template&lt;/strong&gt; is one of those recipes, pre-wired: a ready-to-use JSON config that chains the right tools in the right order, so you copy it, point it at your targets, and run. &lt;a href="https://www.crawlforge.dev" rel="noopener noreferrer"&gt;CrawlForge&lt;/a&gt; ships 24 of them in the &lt;a href="https://www.crawlforge.dev/templates" rel="noopener noreferrer"&gt;templates gallery&lt;/a&gt;. This guide is about using them &lt;em&gt;well&lt;/em&gt; — not just copy-paste, but read, adapt, and cost them out before you scale.&lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
&lt;strong&gt;TL;DR:&lt;/strong&gt; A CrawlForge template is a copy-paste JSON config that chains multiple MCP tools into one workflow (price monitoring, lead enrichment, SEO audits, market research, AI training data). There are 24 across 9 categories, each costing 3–19 credits per run. Run them from Claude/Cursor, the &lt;code&gt;crawlforge&lt;/code&gt; CLI, or the REST API. Free tier = 1,000 credits, no credit card.&lt;br&gt;

&lt;/div&gt;


&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What Is a Web Scraping Template?&lt;/li&gt;
&lt;li&gt;Templates Gallery vs the scrape_template Tool&lt;/li&gt;
&lt;li&gt;How to Use a Template the Right Way&lt;/li&gt;
&lt;li&gt;8 Templates Worth Copying First&lt;/li&gt;
&lt;li&gt;The Other 16 Templates&lt;/li&gt;
&lt;li&gt;Customizing or Building Your Own&lt;/li&gt;
&lt;li&gt;FAQ&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What Is a Web Scraping Template?
&lt;/h2&gt;

&lt;p&gt;A template is a saved configuration that orchestrates two or three CrawlForge tools into one workflow with a business outcome attached. Instead of wiring &lt;code&gt;search_web&lt;/code&gt; then &lt;code&gt;scrape_structured&lt;/code&gt; then &lt;code&gt;analyze_content&lt;/code&gt; yourself — and guessing every parameter — you copy a config that already does it.&lt;/p&gt;

&lt;p&gt;Each template in the gallery carries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;category&lt;/strong&gt; — E-commerce, Research, Data Collection, Monitoring, AI &amp;amp; LLM, Sales, SEO, Content, or Advanced Scraping (nine in total).&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;difficulty&lt;/strong&gt; — beginner, intermediate, or advanced.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;tool chain&lt;/strong&gt; it runs and a fixed &lt;strong&gt;credit cost&lt;/strong&gt; per run (3–19 credits).&lt;/li&gt;
&lt;li&gt;A copy-paste &lt;strong&gt;JSON config&lt;/strong&gt; with sensible default parameters.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You run that config from any MCP client (Claude, Cursor, Windsurf), the &lt;code&gt;crawlforge&lt;/code&gt; CLI, or the REST API. Same config, same shape of result.&lt;/p&gt;

&lt;h2&gt;
  
  
  Templates Gallery vs the scrape_template Tool
&lt;/h2&gt;

&lt;p&gt;This trips people up, so let's be precise. CrawlForge has two different things with "template" in the name:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Templates gallery&lt;/th&gt;
&lt;th&gt;
&lt;code&gt;scrape_template&lt;/code&gt; tool&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;What it is&lt;/td&gt;
&lt;td&gt;A library of multi-tool config chains&lt;/td&gt;
&lt;td&gt;A single tool with 10 site schemas&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scope&lt;/td&gt;
&lt;td&gt;Any workflow (pricing, SEO, research…)&lt;/td&gt;
&lt;td&gt;10 specific sites (Amazon, LinkedIn, GitHub…)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output&lt;/td&gt;
&lt;td&gt;Whatever the chained tools return&lt;/td&gt;
&lt;td&gt;Structured JSON for that one site&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;3–19 credits/run (sum of its tools)&lt;/td&gt;
&lt;td&gt;1 credit/call&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Use when&lt;/td&gt;
&lt;td&gt;You want a whole workflow, ready-made&lt;/td&gt;
&lt;td&gt;You want data from one popular site&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If your target is one of the ten supported sites, reach for the tool — covered in depth in &lt;a href="https://www.crawlforge.dev/blog/scrape-amazon-linkedin-github-templates" rel="noopener noreferrer"&gt;Scrape Amazon, LinkedIn &amp;amp; 8 More Sites With One Tool&lt;/a&gt;. For everything else — a full pricing-monitoring or lead-enrichment pipeline — you want a gallery template. This guide is about the gallery.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Use a Template the Right Way
&lt;/h2&gt;

&lt;p&gt;Copy-paste is step one. Using a template &lt;em&gt;well&lt;/em&gt; is six.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Pick by outcome, not by tool.&lt;/strong&gt; Start from the job ("monitor competitor prices") and filter the gallery by category and difficulty. New to this? Start with the cheap, two-tool, beginner templates before reaching for a 19-credit research pipeline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Read the config before you run it.&lt;/strong&gt; Look at the tool order, the parameters, and whether it carries a &lt;code&gt;schedule&lt;/code&gt; (&lt;code&gt;hourly&lt;/code&gt;, &lt;code&gt;daily&lt;/code&gt;, or &lt;code&gt;weekly&lt;/code&gt;). Order matters: &lt;code&gt;search_web&lt;/code&gt; finds the URLs, &lt;em&gt;then&lt;/em&gt; &lt;code&gt;scrape_structured&lt;/code&gt; extracts from them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Swap the placeholders.&lt;/strong&gt; Every config ships with example values — &lt;code&gt;https://competitor-a.com/pricing&lt;/code&gt;, &lt;code&gt;{company_name}&lt;/code&gt;, &lt;code&gt;"product name"&lt;/code&gt;, a default schema. Replace those with your real targets and the exact fields you want back. The schema &lt;em&gt;is&lt;/em&gt; your output contract; trim it to what you'll actually use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Do the credit math before you scale.&lt;/strong&gt; A template's cost is just the sum of its tools' costs. Multiply by frequency: a 7-credit template run hourly is 168 credits/day. Here is the per-tool table the configs draw from:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Credits&lt;/th&gt;
&lt;th&gt;Tools&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;fetch_url&lt;/code&gt;, &lt;code&gt;extract_text&lt;/code&gt;, &lt;code&gt;extract_links&lt;/code&gt;, &lt;code&gt;extract_metadata&lt;/code&gt;, &lt;code&gt;scrape_template&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;scrape_structured&lt;/code&gt;, &lt;code&gt;extract_content&lt;/code&gt;, &lt;code&gt;map_site&lt;/code&gt;, &lt;code&gt;process_document&lt;/code&gt;, &lt;code&gt;localization&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;analyze_content&lt;/code&gt;, &lt;code&gt;track_changes&lt;/code&gt;, &lt;code&gt;extract_structured&lt;/code&gt;, &lt;code&gt;extract_with_llm&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;summarize_content&lt;/code&gt;, &lt;code&gt;crawl_deep&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;stealth_mode&lt;/code&gt;, &lt;code&gt;scrape_with_actions&lt;/code&gt;, &lt;code&gt;batch_scrape&lt;/code&gt;, &lt;code&gt;search_web&lt;/code&gt;, &lt;code&gt;generate_llms_txt&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;&lt;code&gt;deep_research&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;5. Run it from your stack of choice.&lt;/strong&gt; In an MCP client, paste the goal and let the agent call the tools. From a terminal or cron job, use the &lt;code&gt;crawlforge&lt;/code&gt; CLI. In an app, hit the REST API. All three share one API key and one credit balance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Schedule and monitor.&lt;/strong&gt; Templates built for monitoring carry a &lt;code&gt;schedule&lt;/code&gt;. Pair them with &lt;code&gt;track_changes&lt;/code&gt; so you act on diffs, not on every identical run.&lt;/p&gt;

&lt;h2&gt;
  
  
  8 Templates Worth Copying First
&lt;/h2&gt;

&lt;p&gt;The gallery has 24. These eight cover the highest-demand jobs and span beginner to advanced. Expand each for the copy-paste config.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Competitor Pricing Monitor
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;E-commerce · intermediate · 7 credits/run · &lt;code&gt;batch_scrape&lt;/code&gt; + &lt;code&gt;scrape_structured&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Scrape a set of competitor pricing pages on a schedule and normalize them into a clean plan / price / features structure.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Config + how to adapt
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tools"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"batch_scrape"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"urls"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="s2"&gt;"https://competitor-a.com/pricing"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="s2"&gt;"https://competitor-b.com/pricing"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"selectors"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;".price"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"h1"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"scrape_structured"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"plans"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"features"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"schedule"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"daily"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Replace &lt;code&gt;urls&lt;/code&gt; with your competitors' pricing pages, then tune &lt;code&gt;selectors&lt;/code&gt; and &lt;code&gt;schema&lt;/code&gt; to the fields you track. Keep &lt;code&gt;schedule&lt;/code&gt; at &lt;code&gt;daily&lt;/code&gt; for most pricing work. Full walkthrough: &lt;a href="https://www.crawlforge.dev/blog/ai-price-monitoring-system-guide" rel="noopener noreferrer"&gt;build an AI price-monitoring system&lt;/a&gt;.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Contact Enrichment Pipeline
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Sales · intermediate · 7 credits/run · &lt;code&gt;search_web&lt;/code&gt; + &lt;code&gt;extract_metadata&lt;/code&gt; + &lt;code&gt;extract_links&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Turn a bare company name into an enriched record — official site, social handles, and key links.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Config + how to adapt
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tools"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"search_web"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{company_name} official website"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"extract_metadata"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"include"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"og:title"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"og:description"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"twitter:site"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"extract_links"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"filter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"linkedin.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"twitter.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"github.com"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Drive &lt;code&gt;{company_name}&lt;/code&gt; from your CRM export, and widen the &lt;code&gt;extract_links&lt;/code&gt; filter to the domains you care about. Run it per row to enrich a whole list. Full walkthrough: &lt;a href="https://www.crawlforge.dev/blog/building-lead-enrichment-engine" rel="noopener noreferrer"&gt;build a lead-enrichment engine&lt;/a&gt;.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. SEO Site Audit
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;SEO · beginner · 6 credits/run · &lt;code&gt;map_site&lt;/code&gt; + &lt;code&gt;extract_metadata&lt;/code&gt; + &lt;code&gt;analyze_content&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Crawl a site, pull every page's metadata, and score content quality — a fast, repeatable audit.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Config + how to adapt
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tools"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"map_site"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://your-site.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"max_depth"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"extract_metadata"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"analyze_content"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"metrics"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"readability"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"topics"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sentiment"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Point &lt;code&gt;url&lt;/code&gt; at your domain and raise or lower &lt;code&gt;max_depth&lt;/code&gt; to control crawl breadth (and cost). One of the cheapest templates to run regularly. Full walkthrough: &lt;a href="https://www.crawlforge.dev/blog/automating-seo-audits-crawlforge" rel="noopener noreferrer"&gt;automating SEO audits with CrawlForge&lt;/a&gt;.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. AI Training Data Collector
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;AI &amp;amp; LLM · intermediate · 7 credits/run · &lt;code&gt;batch_scrape&lt;/code&gt; + &lt;code&gt;extract_content&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Collect and clean web pages at scale into model-ready text — no navigation, no boilerplate.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Config + how to adapt
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tools"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"batch_scrape"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"urls"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"https://docs.example.com/page-1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://docs.example.com/page-2"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"format"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"markdown"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"extract_content"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"format"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"remove_navigation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Feed &lt;code&gt;urls&lt;/code&gt; from a sitemap or CSV, and keep &lt;code&gt;remove_navigation&lt;/code&gt; on so menus and footers don't pollute your dataset. Full walkthrough: &lt;a href="https://www.crawlforge.dev/blog/web-scraping-ai-training-data-pipelines" rel="noopener noreferrer"&gt;web scraping for AI training data pipelines&lt;/a&gt;.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Market Intelligence Dashboard
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Research · advanced · 19 credits/run · &lt;code&gt;deep_research&lt;/code&gt; + &lt;code&gt;batch_scrape&lt;/code&gt; + &lt;code&gt;summarize_content&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The flagship. Run multi-source research, scrape the key industry sources, and summarize it all into a daily briefing.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Config + how to adapt
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tools"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"deep_research"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SaaS market trends and funding rounds"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"sources"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"conflict_detection"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"batch_scrape"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"urls"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"https://techcrunch.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://www.saastr.com"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"format"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"markdown"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"summarize_content"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"max_length"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"format"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bullet_points"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"schedule"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"daily"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Change the &lt;code&gt;query&lt;/code&gt; to your market and swap &lt;code&gt;urls&lt;/code&gt; for your trusted sources. At 19 credits/run it is the most expensive template here — run it &lt;code&gt;daily&lt;/code&gt;, not hourly. Related: &lt;a href="https://www.crawlforge.dev/blog/competitive-intelligence-ai-agents" rel="noopener noreferrer"&gt;competitive intelligence with AI agents&lt;/a&gt;.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Review Sentiment Analyzer
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;E-commerce · intermediate · 10 credits/run · &lt;code&gt;search_web&lt;/code&gt; + &lt;code&gt;scrape_structured&lt;/code&gt; + &lt;code&gt;analyze_content&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Find reviews across platforms, structure them, and score sentiment and topics.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Config + how to adapt
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tools"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"search_web"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;product name&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; reviews"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"max_results"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"scrape_structured"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"reviewer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"rating"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"number"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"analyze_content"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"metrics"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"sentiment"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"topics"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Put your product in the &lt;code&gt;query&lt;/code&gt;, raise &lt;code&gt;max_results&lt;/code&gt; for more coverage, and keep the schema tight so sentiment scoring stays clean. Related: &lt;a href="https://www.crawlforge.dev/blog/ecommerce-product-data-extraction-scale" rel="noopener noreferrer"&gt;e-commerce product data extraction at scale&lt;/a&gt;.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Job Listings Scraper
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Data Collection · intermediate · 7 credits/run · &lt;code&gt;search_web&lt;/code&gt; + &lt;code&gt;scrape_structured&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Search job boards and pull listings into a structured feed — title, company, location, salary, date.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Config + how to adapt
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tools"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"search_web"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"software engineer remote jobs 2026"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"max_results"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"scrape_structured"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"company"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"location"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"salary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"posted_date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Change the &lt;code&gt;query&lt;/code&gt; to your role and region, and add schema fields (remote flag, seniority) as needed. See it on the &lt;a href="https://www.crawlforge.dev/templates/job-listings-scraper" rel="noopener noreferrer"&gt;Job Listings Scraper template page&lt;/a&gt;.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Website Change Detector
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Monitoring · beginner · 6 credits/run · &lt;code&gt;fetch_url&lt;/code&gt; + &lt;code&gt;extract_content&lt;/code&gt; + &lt;code&gt;analyze_content&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Watch a single page and surface when its content shifts — pricing, terms, or announcements.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Config + how to adapt
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tools"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fetch_url"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/page-to-monitor"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"extract_content"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"format"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"analyze_content"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"metrics"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"topics"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"schedule"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"hourly"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Set &lt;code&gt;url&lt;/code&gt; to the page you care about and dial &lt;code&gt;schedule&lt;/code&gt; to your tolerance for staleness — &lt;code&gt;hourly&lt;/code&gt; for fast-moving pages, &lt;code&gt;daily&lt;/code&gt; for the rest. Related: &lt;a href="https://www.crawlforge.dev/blog/build-competitive-intelligence-agent-claude-crawlforge" rel="noopener noreferrer"&gt;build a competitive-intelligence agent&lt;/a&gt;.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Other 16 Templates
&lt;/h2&gt;

&lt;p&gt;The remaining gallery entries, grouped by category — each is a copy-paste config on &lt;a href="https://www.crawlforge.dev/templates" rel="noopener noreferrer"&gt;the templates page&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Research:&lt;/strong&gt; News Aggregation Pipeline (11cr), Multi-Source Research Agent (12cr), Academic Paper Research (14cr).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Collection:&lt;/strong&gt; Real Estate Listings Tracker (7cr), PDF Document Processor (6cr), Government Data Extractor (5cr).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring:&lt;/strong&gt; Compliance Monitoring (9cr), Social Media Monitoring (12cr).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;E-commerce:&lt;/strong&gt; E-commerce Product Extraction (3cr).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI &amp;amp; LLM:&lt;/strong&gt; Documentation Knowledge Base (10cr).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sales:&lt;/strong&gt; Tech Stack Detector (3cr).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SEO:&lt;/strong&gt; Link Building Prospector (7cr).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content:&lt;/strong&gt; Content Migration Tool (7cr), Localization Content Audit (7cr).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Advanced Scraping:&lt;/strong&gt; Dynamic SPA Scraper (7cr), Stealth Data Extraction (7cr).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Customizing or Building Your Own
&lt;/h2&gt;

&lt;p&gt;No template is a perfect fit out of the box — that is the point of step three. When a config gets you 80% there, swap the parameters and schema and you are done. When nothing fits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Start from the closest template&lt;/strong&gt; and rewrite its schema and parameters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compose tools yourself.&lt;/strong&gt; Use &lt;code&gt;scrape_structured&lt;/code&gt; when you know stable CSS selectors, or &lt;a href="https://www.crawlforge.dev/blog/extract-data-with-local-llms-ollama" rel="noopener noreferrer"&gt;&lt;code&gt;extract_with_llm&lt;/code&gt;&lt;/a&gt; when the layout shifts and you want schema-driven, layout-resilient extraction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Request a template.&lt;/strong&gt; If you want a recipe we don't ship yet, ask on &lt;a href="https://discord.gg/crawlforge" rel="noopener noreferrer"&gt;Discord&lt;/a&gt; — popular requests get added to the gallery.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;/p&gt;
  What is a web scraping template?
  &lt;p&gt;A ready-to-use JSON config that chains multiple CrawlForge tools into one workflow with a specific outcome — price monitoring, lead enrichment, SEO auditing, and so on. Copy the config, swap in your URLs and schema, and run it from an MCP client, the &lt;code&gt;crawlforge&lt;/code&gt; CLI, or the REST API. CrawlForge ships 24 templates across 9 categories.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Templates gallery vs the scrape_template tool?
  &lt;p&gt;The gallery is a library of multi-tool config chains for complete workflows (3–19 credits/run). The &lt;code&gt;scrape_template&lt;/code&gt; tool is a single tool with pre-built schemas for 10 popular sites (Amazon, LinkedIn, GitHub…) at 1 credit/call. Use a gallery template for a whole workflow; use &lt;code&gt;scrape_template&lt;/code&gt; for data from one of the ten supported sites.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  How many credits does a template cost?
  &lt;p&gt;A template costs the sum of its tools per run, from 3 credits (E-commerce Product Extraction, Tech Stack Detector) to 19 (Market Intelligence Dashboard). A Competitor Pricing Monitor is &lt;code&gt;batch_scrape&lt;/code&gt; (5) + &lt;code&gt;scrape_structured&lt;/code&gt; (2) = 7. Multiply by frequency to budget: 7 credits hourly is 168/day.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Can I customize a template or change its schema?
  &lt;p&gt;Yes — that is the intended workflow. Every template ships with placeholders (example URLs, a default schema, sample queries) you replace with your real targets. The schema is your output contract, so trim or extend it. If nothing fits, start from the closest template or compose tools with &lt;code&gt;scrape_structured&lt;/code&gt; / &lt;code&gt;extract_with_llm&lt;/code&gt;.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  How do I run a template?
  &lt;p&gt;Three ways, sharing one API key and credit balance: paste the goal into an MCP client like Claude, Cursor, or Windsurf; run it from a terminal or cron job with the &lt;code&gt;crawlforge&lt;/code&gt; CLI; or call the REST API from an app. The same config produces the same result across all three.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Ready to run your first template?&lt;/strong&gt; Free tier includes 1,000 credits and no credit card.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.crawlforge.dev/signup" class="crayons-btn crayons-btn--primary" rel="noopener noreferrer"&gt;Start Free — 1,000 Credits Included&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Or keep reading:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.crawlforge.dev/templates" rel="noopener noreferrer"&gt;Browse the full templates gallery&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.crawlforge.dev/blog/scrape-amazon-linkedin-github-templates" rel="noopener noreferrer"&gt;Scrape Amazon, LinkedIn &amp;amp; 8 more sites with one tool&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.crawlforge.dev/blog/extract-data-with-local-llms-ollama" rel="noopener noreferrer"&gt;Extract data with local LLMs via Ollama&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webscraping</category>
      <category>ai</category>
      <category>mcp</category>
      <category>automation</category>
    </item>
    <item>
      <title>CrawlForge v4.2.2: New CLI + 3 Tools for Local AI Scraping</title>
      <dc:creator>Simon</dc:creator>
      <pubDate>Mon, 18 May 2026 23:21:46 +0000</pubDate>
      <link>https://dev.to/simon_crawlforge_dev/crawlforge-v422-new-cli-3-tools-for-local-ai-scraping-5954</link>
      <guid>https://dev.to/simon_crawlforge_dev/crawlforge-v422-new-cli-3-tools-for-local-ai-scraping-5954</guid>
      <description>&lt;p&gt;Today we are shipping &lt;strong&gt;CrawlForge v4.2.2&lt;/strong&gt;, our biggest release since launch. It brings three new tools, a standalone command-line interface, and a quiet shift in how we think about web scraping for AI: most of it should run locally, on your own machine, without API keys.&lt;/p&gt;

&lt;p&gt;This post is the umbrella for everything in 4.2.2. Three deep-dive guides follow in the next nine days.&lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
&lt;strong&gt;TL;DR:&lt;/strong&gt; v4.2.2 adds the &lt;code&gt;crawlforge&lt;/code&gt; CLI (a standalone CLI that ships with &lt;code&gt;crawlforge-mcp-server&lt;/code&gt; -- no MCP client needed), &lt;code&gt;extract_with_llm&lt;/code&gt; (local LLM extraction via Ollama, no OpenAI/Anthropic key required), &lt;code&gt;scrape_template&lt;/code&gt; (one-line scrapers for 10 popular sites), and &lt;code&gt;list_ollama_models&lt;/code&gt; (free model discovery). Tool count goes from 20 to 23. Free tier still includes 1,000 credits. Install: &lt;code&gt;npm install -g crawlforge-mcp-server&lt;/code&gt;.&lt;br&gt;

&lt;/div&gt;


&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What Shipped&lt;/li&gt;
&lt;li&gt;The New CrawlForge CLI&lt;/li&gt;
&lt;li&gt;Extract With LLM: Local AI Extraction&lt;/li&gt;
&lt;li&gt;Scrape Template: Ten Sites, One Call&lt;/li&gt;
&lt;li&gt;list_ollama_models: Free Model Discovery&lt;/li&gt;
&lt;li&gt;Old Workflow vs v4.2.2 Workflow&lt;/li&gt;
&lt;li&gt;Credit Costs&lt;/li&gt;
&lt;li&gt;How to Upgrade&lt;/li&gt;
&lt;li&gt;What Is Next&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What Shipped
&lt;/h2&gt;

&lt;p&gt;v4.2.2 adds four things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The crawlforge CLI&lt;/strong&gt; -- a standalone command-line tool, shipped in the &lt;code&gt;crawlforge-mcp-server&lt;/code&gt; package, that exposes all 23 CrawlForge tools to your shell. No MCP client required.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;extract_with_llm&lt;/strong&gt; -- LLM-powered structured extraction that defaults to local Ollama. No external API key needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;scrape_template&lt;/strong&gt; -- pre-built scrapers for Amazon, LinkedIn, GitHub, YouTube, Reddit, Hacker News, Stack Overflow, npm, Product Hunt, and Twitter/X.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;list_ollama_models&lt;/strong&gt; -- a free discovery tool that lists models on your local Ollama instance.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Tool count goes from 20 to 23. The CLI is brand new -- it is not a tool, it is a delivery channel.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+----------------+       +-------------------+       +----------------+
|   Your Shell   | &amp;lt;--&amp;gt;  |  crawlforge CLI   | &amp;lt;--&amp;gt;  |  CrawlForge    |
|   (cron, CI)   |       |  (JSON in/out)    |       |   API + Tools  |
+----------------+       +-------------------+       +----------------+
                                  ^
                          No MCP handshake.
                          Just HTTPS + stdout.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The New CrawlForge CLI
&lt;/h2&gt;

&lt;p&gt;The CLI is the shortest path from intent to scraped data. You install it once, set an environment variable, and every CrawlForge tool becomes a command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; crawlforge-mcp-server
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CRAWLFORGE_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"cf_live_your_key_here"&lt;/span&gt;

crawlforge scrape https://example.com
crawlforge search &lt;span class="s2"&gt;"best MCP servers 2026"&lt;/span&gt;
crawlforge research &lt;span class="s2"&gt;"AI agent frameworks"&lt;/span&gt; &lt;span class="nt"&gt;--depth&lt;/span&gt; deep
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why does this matter? Because MCP is great for AI agents, but a lot of scraping work is not an AI agent task. It is a cron job. A CI step. A one-off pull from your terminal. For that, you want JSON on stdout that pipes into jq, not a JSON-RPC handshake.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Why have a CLI when MCP already exists?
  &lt;p&gt;MCP is optimized for AI agents picking tools dynamically. The CLI is optimized for &lt;strong&gt;humans typing commands&lt;/strong&gt; and &lt;strong&gt;scripts piping JSON&lt;/strong&gt;. Different shapes for different jobs:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Workflow&lt;/th&gt;
&lt;th&gt;Best fit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Claude/Cursor agent&lt;/td&gt;
&lt;td&gt;MCP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cron job&lt;/td&gt;
&lt;td&gt;CLI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub Actions step&lt;/td&gt;
&lt;td&gt;CLI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One-off terminal&lt;/td&gt;
&lt;td&gt;CLI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server in a loop&lt;/td&gt;
&lt;td&gt;Raw API&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All three paths hit the same backend, share the same credit balance, and use the same API key.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Read the &lt;a href="https://www.crawlforge.dev/blog/web-scraping-cli-complete-guide" rel="noopener noreferrer"&gt;complete CrawlForge CLI guide&lt;/a&gt; for the full command reference and real-world workflows.&lt;/p&gt;




&lt;h2&gt;
  
  
  Extract With LLM: Local AI Extraction
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;extract_with_llm&lt;/code&gt; is structured extraction powered by a language model. You hand it a URL and a schema, it gives you back JSON. The new part is that it defaults to &lt;strong&gt;local Ollama&lt;/strong&gt; rather than calling OpenAI or Anthropic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://news.ycombinator.com/item?id=123456"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"points"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"number"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"comments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"number"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ollama"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"llama3.1:8b"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three things follow from the local-first default:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No third-party API costs.&lt;/strong&gt; The LLM is free. You only pay 3 CrawlForge credits per extraction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No data leaving your machine.&lt;/strong&gt; Scraped content stays on localhost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No new API key to manage.&lt;/strong&gt; If Ollama is installed, you are done.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;/p&gt;
  When to still use OpenAI or Anthropic
  &lt;p&gt;Local models are great for predictable schemas (titles, prices, counts, ratings). For long-form reasoning -- summarizing a 10,000-word article, classifying nuanced sentiment, extracting fields that require world knowledge -- a frontier model still wins.&lt;/p&gt;

&lt;p&gt;Switch providers with one parameter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;crawlforge extract https://example.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--provider&lt;/span&gt; anthropic &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--model&lt;/span&gt; claude-sonnet-4-6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You pay the provider's per-token cost plus 3 CrawlForge credits. Same schema, same output shape.&lt;/p&gt;



&lt;br&gt;
&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Detailed guide: &lt;a href="https://www.crawlforge.dev/blog/extract-data-with-local-llms-ollama" rel="noopener noreferrer"&gt;extract data with local LLMs&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Scrape Template: Ten Sites, One Call
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;scrape_template&lt;/code&gt; is for the long tail of scraping requests that all look the same: "get me product data from Amazon", "get me a GitHub repo's metadata", "get me the top posts on Hacker News today". You should not need to write CSS selectors for these. We did it once, we maintain it, you call it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;crawlforge template amazon-product &lt;span class="s2"&gt;"https://www.amazon.com/dp/B0CHX1W1XY"&lt;/span&gt;
crawlforge template github-repo &lt;span class="s2"&gt;"https://github.com/anthropics/anthropic-sdk-python"&lt;/span&gt;
crawlforge template hacker-news-front-page &lt;span class="s2"&gt;"https://news.ycombinator.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ten templates ship in this release:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Template&lt;/th&gt;
&lt;th&gt;What it returns&lt;/th&gt;
&lt;th&gt;Credits&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;amazon-product&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Product title, price, rating, reviews, images&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;linkedin-profile&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Profile name, headline, location, about&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;github-repo&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Repo metadata, stars, language, topics&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;youtube-video&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Video title, views, channel, description&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;reddit-thread&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Post title, score, author, body&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hacker-news-front-page&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Front-page story titles, points, URLs&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;stackoverflow-question&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Question, answers, accepted, vote counts&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;npm-package&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Package metadata, weekly downloads, version&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;producthunt-launch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Product name, tagline, upvotes, topics&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tweet&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Tweet text, author, URL, image&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Full walkthrough with code: &lt;a href="https://www.crawlforge.dev/blog/scrape-amazon-linkedin-github-templates" rel="noopener noreferrer"&gt;scrape Amazon, LinkedIn, and GitHub with one tool&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  list_ollama_models: Free Model Discovery
&lt;/h2&gt;

&lt;p&gt;Most useful as a sanity-check before running &lt;code&gt;extract_with_llm&lt;/code&gt;. Lists every model on your local Ollama instance with name, size, and modified date.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;crawlforge extract &lt;span class="nt"&gt;--list-ollama-models&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Costs &lt;strong&gt;zero credits&lt;/strong&gt;. It does no scraping, no LLM call -- it just queries Ollama's local API on &lt;code&gt;127.0.0.1:11434&lt;/code&gt; and returns the result. If you have ever wondered which model you actually have installed, this is the answer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Old Workflow vs v4.2.2 Workflow
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Pre-4.2.2&lt;/th&gt;
&lt;th&gt;v4.2.2&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Scrape from your terminal&lt;/td&gt;
&lt;td&gt;curl + custom parser, or boot a Node REPL&lt;/td&gt;
&lt;td&gt;&lt;code&gt;crawlforge scrape &amp;lt;url&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extract structured data with LLM&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;extract_structured&lt;/code&gt; (CSS selectors) or roll your own with Puppeteer + OpenAI&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;extract_with_llm&lt;/code&gt; (Ollama default)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scrape Amazon, LinkedIn, GitHub&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;scrape_structured&lt;/code&gt; with hand-maintained selectors&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;scrape_template&lt;/code&gt; (we maintain selectors)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Run scraping in CI/cron&lt;/td&gt;
&lt;td&gt;curl with API key in headers&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;crawlforge &amp;lt;cmd&amp;gt;&lt;/code&gt; with env var&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Credit Costs
&lt;/h2&gt;

&lt;p&gt;The three new tools follow our existing credit-cost model. No surprises:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Credits&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;list_ollama_models&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Free discovery helper&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;scrape_template&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Single page, pre-built schema&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;extract_with_llm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;LLM inference (provider-agnostic)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The CLI itself is free. It uses your existing API key and bills against your normal credit balance.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Upgrade
&lt;/h2&gt;

&lt;p&gt;Existing users do not need to do anything. The new tools are live on all plans -- Free, Hobby, Professional, and Business -- and show up automatically in your MCP client.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Install the CLI
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; crawlforge-mcp-server
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CRAWLFORGE_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"cf_live_..."&lt;/span&gt;
crawlforge &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Add the &lt;code&gt;export&lt;/code&gt; line to your shell profile (&lt;code&gt;~/.zshrc&lt;/code&gt;, &lt;code&gt;~/.bashrc&lt;/code&gt;) so it persists. For CI, set &lt;code&gt;CRAWLFORGE_API_KEY&lt;/code&gt; as a repository secret.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Try Ollama-powered extraction
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Install Ollama (one-time)&lt;/span&gt;
curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://ollama.com/install.sh | sh

&lt;span class="c"&gt;# 2. Pull a model (llama3.1:8b is a good start)&lt;/span&gt;
ollama pull llama3.1:8b

&lt;span class="c"&gt;# 3. Run extraction through CrawlForge&lt;/span&gt;
crawlforge extract https://example.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--provider&lt;/span&gt; ollama &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--model&lt;/span&gt; llama3.1:8b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The first run pulls about 5 GB. After that, every extraction is local, free, and offline-capable.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is Next
&lt;/h2&gt;

&lt;p&gt;We are working on three things for 4.3:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;More templates&lt;/strong&gt; -- Etsy, eBay, TikTok, Instagram, Google Maps. Send us requests on &lt;a href="https://discord.gg/crawlforge" rel="noopener noreferrer"&gt;Discord&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Webhook delivery for batch_scrape&lt;/strong&gt; -- get results pushed to your endpoint when long-running jobs complete.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CLI watch mode&lt;/strong&gt; -- &lt;code&gt;crawlforge track --watch&lt;/code&gt; for live diffs on monitored pages.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Ready to try the new tools?&lt;/strong&gt; Free tier still includes 1,000 credits and no credit card.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.crawlforge.dev/signup" class="crayons-btn crayons-btn--primary" rel="noopener noreferrer"&gt;Get 1,000 Free Credits&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Or jump straight into the deep dives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.crawlforge.dev/blog/web-scraping-cli-complete-guide" rel="noopener noreferrer"&gt;The complete CLI guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.crawlforge.dev/blog/extract-data-with-local-llms-ollama" rel="noopener noreferrer"&gt;Extract data with local LLMs via Ollama&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.crawlforge.dev/blog/scrape-amazon-linkedin-github-templates" rel="noopener noreferrer"&gt;Scrape Amazon, LinkedIn, and GitHub with templates&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webscraping</category>
      <category>ai</category>
      <category>cli</category>
      <category>ollama</category>
    </item>
    <item>
      <title>How to Scrape Websites with Claude Code (2026 Guide)</title>
      <dc:creator>Simon</dc:creator>
      <pubDate>Fri, 17 Apr 2026 22:00:26 +0000</pubDate>
      <link>https://dev.to/simon_crawlforge_dev/how-to-scrape-websites-with-claude-code-2026-guide-29lp</link>
      <guid>https://dev.to/simon_crawlforge_dev/how-to-scrape-websites-with-claude-code-2026-guide-29lp</guid>
      <description>&lt;p&gt;&lt;a href="https://docs.anthropic.com/en/docs/claude-code/overview" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt; can edit files, run shell commands, and write tests — but it cannot fetch live web pages on its own. Connect it to CrawlForge MCP and it gains 20 scraping tools that run straight from your terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; crawlforge-mcp-server
npx crawlforge-setup  &lt;span class="c"&gt;# paste your API key&lt;/span&gt;
&lt;span class="c"&gt;# Now in Claude Code:&lt;/span&gt;
&lt;span class="c"&gt;# &amp;gt; Fetch https://news.ycombinator.com and list the top 5 stories&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This guide shows you how to scrape websites with Claude Code using CrawlForge MCP, from installation to stealth-mode bypass. Every code block below is runnable.&lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
&lt;strong&gt;TL;DR:&lt;/strong&gt; Claude Code has no network access by default. Install &lt;a href="https://www.crawlforge.dev" rel="noopener noreferrer"&gt;CrawlForge MCP&lt;/a&gt; and Claude Code gets 20 scraping tools — &lt;code&gt;fetch_url&lt;/code&gt;, &lt;code&gt;extract_content&lt;/code&gt;, &lt;code&gt;scrape_with_actions&lt;/code&gt;, &lt;code&gt;stealth_mode&lt;/code&gt;, and more. Free tier = 1,000 credits, no credit card.&lt;br&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The Problem: Claude Code Cannot Fetch URLs&lt;/li&gt;
&lt;li&gt;Prerequisites&lt;/li&gt;
&lt;li&gt;Step 1: Install CrawlForge MCP&lt;/li&gt;
&lt;li&gt;Step 2: Get Your API Key&lt;/li&gt;
&lt;li&gt;Step 3: Register the MCP Server with Claude Code&lt;/li&gt;
&lt;li&gt;Step 4: Verify the Connection&lt;/li&gt;
&lt;li&gt;Step 5: Your First Scrape&lt;/li&gt;
&lt;li&gt;Full Working Example: Scrape a Pricing Page&lt;/li&gt;
&lt;li&gt;Advanced: Scrape JavaScript-Rendered Sites&lt;/li&gt;
&lt;li&gt;Tool Quick Reference&lt;/li&gt;
&lt;li&gt;Troubleshooting&lt;/li&gt;
&lt;li&gt;FAQ&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Problem: Claude Code Cannot Fetch URLs
&lt;/h2&gt;

&lt;p&gt;By default, Claude Code has no network access. Ask it to "read this blog post" and it will tell you it cannot open URLs. The built-in &lt;code&gt;WebFetch&lt;/code&gt; helper exists in Claude Desktop but is limited, rate-capped, and frequently blocked by Cloudflare, Akamai, and other edge protections.&lt;/p&gt;

&lt;p&gt;CrawlForge MCP solves this by exposing 20 scraping tools — &lt;code&gt;fetch_url&lt;/code&gt;, &lt;code&gt;extract_content&lt;/code&gt;, &lt;code&gt;scrape_structured&lt;/code&gt;, &lt;code&gt;stealth_mode&lt;/code&gt;, &lt;code&gt;deep_research&lt;/code&gt;, and more — as &lt;a href="https://modelcontextprotocol.io/introduction" rel="noopener noreferrer"&gt;Model Context Protocol&lt;/a&gt; tools that Claude Code can call like any other function. For more background on the protocol itself, see the &lt;a href="https://www.crawlforge.dev/blog/complete-guide-mcp-web-scraping" rel="noopener noreferrer"&gt;complete guide to MCP web scraping&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+------------+     MCP       +-------------+     HTTPS     +-----------+
| Claude Code| &amp;lt;-----------&amp;gt; | CrawlForge  | &amp;lt;-----------&amp;gt; |  Target   |
| (terminal) |  JSON-RPC     |   Server    |               |   site    |
+------------+   over stdio  +-------------+               +-----------+
                                    |
                                Credits +
                                Stealth +
                                Actions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Node.js 18+&lt;/strong&gt; — check with &lt;code&gt;node --version&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claude Code&lt;/strong&gt; — install with &lt;code&gt;npm install -g @anthropic-ai/claude-code&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A CrawlForge account&lt;/strong&gt; — free at &lt;a href="https://www.crawlforge.dev/signup" rel="noopener noreferrer"&gt;crawlforge.dev/signup&lt;/a&gt; (1,000 credits included, no credit card)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: Install CrawlForge MCP
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; crawlforge-mcp-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the install:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;crawlforge-mcp-server &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;span class="c"&gt;# crawlforge-mcp-server 3.0.16&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Get Your API Key
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://www.crawlforge.dev/signup" rel="noopener noreferrer"&gt;crawlforge.dev/signup&lt;/a&gt; and create an account.&lt;/li&gt;
&lt;li&gt;Open the dashboard at &lt;a href="https://www.crawlforge.dev/dashboard/api-keys" rel="noopener noreferrer"&gt;crawlforge.dev/dashboard/api-keys&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Copy the key — it starts with &lt;code&gt;cf_live_&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 3: Register the MCP Server with Claude Code
&lt;/h2&gt;

&lt;p&gt;The fastest path is the setup wizard:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx crawlforge-setup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It writes the correct entry to &lt;code&gt;~/.config/claude-code/mcp.json&lt;/code&gt; (Linux/macOS) or &lt;code&gt;%APPDATA%\claude-code\mcp.json&lt;/code&gt; (Windows).&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Prefer manual configuration? Here's the exact JSON
  &lt;p&gt;Add this to your Claude Code MCP config file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"crawlforge"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"crawlforge-mcp-server"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"CRAWLFORGE_API_KEY"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cf_live_your_key_here"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart Claude Code so it picks up the new server.&lt;/p&gt;



&lt;br&gt;
&lt;p&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Verify the Connection
&lt;/h2&gt;

&lt;p&gt;Open Claude Code and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see &lt;code&gt;crawlforge&lt;/code&gt; listed as connected with 20 tools available. If not, jump to Troubleshooting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Your First Scrape
&lt;/h2&gt;

&lt;p&gt;Paste this prompt into Claude Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Fetch https://news.ycombinator.com using CrawlForge and give me the
top 5 story titles with their URLs as a JSON array.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude Code will call &lt;code&gt;fetch_url&lt;/code&gt; (1 credit), parse the HTML, and return something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Show HN: My side project"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/post/1"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Why X is changing Y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/post/2"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is it. You are scraping.&lt;/p&gt;

&lt;h2&gt;
  
  
  Full Working Example: Scrape a Pricing Page
&lt;/h2&gt;

&lt;p&gt;Here is a realistic task: extract pricing tiers from a SaaS site. Paste this prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Use scrape_structured to extract pricing from https://crawlforge.dev/pricing.
Return an array of { plan, price, credits, features[] }.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;/p&gt;
  See what Claude Code builds behind the scenes
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// What Claude Code sends to CrawlForge via MCP&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://crawlforge.dev/api/v1/tools/scrape_structured&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Authorization&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CRAWLFORGE_API_KEY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://crawlforge.dev/pricing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;selectors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.pricing-card h3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.pricing-card .price&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;credits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.pricing-card .credits&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;features&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.pricing-card ul li&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ['Free', 'Hobby', 'Professional', 'Business']&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Cost: &lt;strong&gt;2 credits&lt;/strong&gt;. Compare that to running a headless browser locally: zero infrastructure, no Puppeteer debugging, no Cloudflare roulette.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced: Scrape JavaScript-Rendered Sites
&lt;/h2&gt;

&lt;p&gt;Some sites render pricing or product data through client-side React. &lt;code&gt;fetch_url&lt;/code&gt; returns the pre-hydration HTML shell and misses the data. Switch to &lt;code&gt;scrape_with_actions&lt;/code&gt; (5 credits):&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  scrape_with_actions — clicks, waits, and scrolls for SPAs
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Prompt Claude Code with the goal, and it generates this call&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://app.example.com/dashboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wait&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.data-grid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button.load-more&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wait&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1500&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;formats&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;markdown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://crawlforge.dev/api/v1/tools/scrape_with_actions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Authorization&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CRAWLFORGE_API_KEY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;&lt;/p&gt;

&lt;p&gt;For Cloudflare and Akamai-protected sites, use &lt;code&gt;stealth_mode&lt;/code&gt; (also 5 credits). The fingerprint-rotation tradeoffs are covered in the &lt;a href="https://www.crawlforge.dev/blog/stealth-mode-scraping-bypass-anti-bot-detection" rel="noopener noreferrer"&gt;stealth mode deep dive&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tool Quick Reference
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Credits&lt;/th&gt;
&lt;th&gt;When to use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fetch_url&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Static HTML, you will parse yourself&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;extract_text&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Clean readable text from article pages&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;extract_content&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Readability-style main content extraction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;scrape_structured&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;CSS selectors into typed fields&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;search_web&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;You do not know the URL yet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;scrape_with_actions&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;SPA requires clicks, waits, scrolls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;stealth_mode&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Anti-bot systems (Cloudflare, DataDome)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;deep_research&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;Multi-source research with citations&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Full list in the &lt;a href="https://www.crawlforge.dev/blog/18-web-scraping-tools-one-mcp-server" rel="noopener noreferrer"&gt;20-tools overview&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Troubleshooting
&lt;/h2&gt;

&lt;p&gt;&lt;/p&gt;
  MCP server failed to start
  &lt;p&gt;Confirm &lt;code&gt;crawlforge-mcp-server&lt;/code&gt; is on your PATH:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;which crawlforge-mcp-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If empty, reinstall globally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; crawlforge-mcp-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;br&gt;
&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Unauthorized or 401 errors
  &lt;p&gt;Your API key is missing or malformed. It must start with &lt;code&gt;cf_live_&lt;/code&gt;. Re-export in your shell and restart Claude Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CRAWLFORGE_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"cf_live_..."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;br&gt;
&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Insufficient credits
  &lt;p&gt;Check usage at &lt;a href="https://www.crawlforge.dev/dashboard/usage" rel="noopener noreferrer"&gt;crawlforge.dev/dashboard/usage&lt;/a&gt;. Free tier = 1,000 credits/month. Upgrade to Hobby ($19/mo) for 25,000.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Tools list is empty when running /mcp
  &lt;p&gt;MCP config is not being read. Check the right path for your OS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;macOS:&lt;/strong&gt; &lt;code&gt;~/Library/Application Support/claude-code/mcp.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Linux:&lt;/strong&gt; &lt;code&gt;~/.config/claude-code/mcp.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Windows:&lt;/strong&gt; &lt;code&gt;%APPDATA%\claude-code\mcp.json&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Cloudflare 403 on every fetch
  &lt;p&gt;Swap &lt;code&gt;fetch_url&lt;/code&gt; for &lt;code&gt;stealth_mode&lt;/code&gt;. If you still get blocked, the target uses server-side JA3/JA4 fingerprinting — open a GitHub issue with the URL.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;/p&gt;
  Can Claude Code scrape websites without CrawlForge?
  &lt;p&gt;Not reliably. Claude Code has no built-in network access, and the &lt;code&gt;WebFetch&lt;/code&gt; helper in Claude Desktop is rate-limited and blocked by most anti-bot systems. CrawlForge MCP adds 20 dedicated scraping tools that handle static HTML, JavaScript-rendered pages, and Cloudflare-protected sites.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  How much does it cost to scrape with Claude Code?
  &lt;p&gt;CrawlForge uses a credit model: basic fetches cost 1 credit, structured extraction 2 credits, search 5, stealth 5, deep research 10. Free accounts get 1,000 credits per month with no credit card. The Hobby plan ($19/mo) includes 25,000 credits.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Why do I get 403 errors when Claude Code fetches certain URLs?
  &lt;p&gt;Sites protected by Cloudflare, DataDome, or Akamai block generic HTTP clients via TLS fingerprinting and JavaScript challenges. Switch from &lt;code&gt;fetch_url&lt;/code&gt; (1 credit) to &lt;code&gt;stealth_mode&lt;/code&gt; (5 credits), which rotates browser fingerprints and solves challenges automatically.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Does CrawlForge MCP work with Claude Code on Windows?
  &lt;p&gt;Yes. Install via npm, run &lt;code&gt;npx crawlforge-setup&lt;/code&gt;, and the config lands at &lt;code&gt;%APPDATA%\claude-code\mcp.json&lt;/code&gt;. Node.js 18+ is the only system requirement. Windows users should run the setup command from PowerShell or Windows Terminal for the cleanest experience.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  What is the difference between fetch_url and scrape_with_actions?
  &lt;p&gt;&lt;code&gt;fetch_url&lt;/code&gt; returns raw HTML via a fast HTTP request (1 credit). &lt;code&gt;scrape_with_actions&lt;/code&gt; spins up a headless browser, executes clicks/waits/scrolls, then captures the hydrated DOM (5 credits). Use &lt;code&gt;fetch_url&lt;/code&gt; for static pages and &lt;code&gt;scrape_with_actions&lt;/code&gt; only when JavaScript rendering is required.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Read the &lt;a href="https://www.crawlforge.dev/blog/crawlforge-mcp-quickstart" rel="noopener noreferrer"&gt;CrawlForge quick start&lt;/a&gt; for five copy-paste examples&lt;/li&gt;
&lt;li&gt;Browse the &lt;a href="https://www.crawlforge.dev/docs/getting-started" rel="noopener noreferrer"&gt;getting started docs&lt;/a&gt; for full API reference&lt;/li&gt;
&lt;li&gt;Compare MCP clients in &lt;a href="https://www.crawlforge.dev/blog/how-to-add-web-scraping-to-claude-desktop" rel="noopener noreferrer"&gt;Claude Desktop vs Claude Code&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Evaluate alternatives at &lt;a href="https://www.crawlforge.dev/alternatives/firecrawl-alternative" rel="noopener noreferrer"&gt;Firecrawl alternative&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://www.crawlforge.dev/signup" class="crayons-btn crayons-btn--primary" rel="noopener noreferrer"&gt;Start Free — 1,000 Credits Included&lt;/a&gt;
&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>webscraping</category>
      <category>mcp</category>
      <category>ai</category>
    </item>
    <item>
      <title>im about to launch my new saas project next tuesday. kind of excited this will be my first. here is the link in case anyone wants to try it out for free. hope everyone has a great weekend.
https://www.crawlforge.dev/</title>
      <dc:creator>Simon</dc:creator>
      <pubDate>Fri, 27 Mar 2026 18:18:29 +0000</pubDate>
      <link>https://dev.to/simon_crawlforge_dev/im-about-to-launch-my-new-saas-project-next-tuesday-kind-of-excited-this-will-be-my-first-here-is-1336</link>
      <guid>https://dev.to/simon_crawlforge_dev/im-about-to-launch-my-new-saas-project-next-tuesday-kind-of-excited-this-will-be-my-first-here-is-1336</guid>
      <description>&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://www.crawlforge.dev/" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.crawlforge.dev%2Fapi%2Fog" height="auto" class="m-0"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://www.crawlforge.dev/" rel="noopener noreferrer" class="c-link"&gt;
            CrawlForge - Enterprise Web Scraping for AI Applications
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            18 specialized MCP tools for seamless web scraping and AI-ready data extraction
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.crawlforge.dev%2Ficon.svg%3Ficon.bcd3ce3e.svg"&gt;
          crawlforge.dev
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
    </item>
    <item>
      <title>The Complete Guide to MCP Web Scraping: Everything Developers Need to Know</title>
      <dc:creator>Simon</dc:creator>
      <pubDate>Fri, 27 Mar 2026 17:45:08 +0000</pubDate>
      <link>https://dev.to/simon_crawlforge_dev/the-complete-guide-to-mcp-web-scraping-everything-developers-need-to-know-45l4</link>
      <guid>https://dev.to/simon_crawlforge_dev/the-complete-guide-to-mcp-web-scraping-everything-developers-need-to-know-45l4</guid>
      <description>&lt;p&gt;The Model Context Protocol (MCP) has fundamentally changed how AI assistants interact with the web. If you've been building with Claude, Cursor, or any MCP-compatible client, you've probably wondered: &lt;strong&gt;what's the best way to give your AI agent access to live web data?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This guide covers everything -- from foundational MCP concepts to all 18 CrawlForge tools and how to pick the right one for each job.&lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
&lt;strong&gt;TL;DR:&lt;/strong&gt; MCP is the open standard for connecting AI to tools. &lt;a href="https://www.crawlforge.dev" rel="noopener noreferrer"&gt;CrawlForge&lt;/a&gt; is the most comprehensive MCP web scraping server with 18 tools -- 4x more than alternatives. Free tier includes 1,000 credits, no credit card required.&lt;br&gt;

&lt;/div&gt;


&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Part 1: Understanding MCP&lt;/li&gt;
&lt;li&gt;Part 2: The MCP Web Scraping Ecosystem&lt;/li&gt;
&lt;li&gt;Part 3: All 18 Tools Explained&lt;/li&gt;
&lt;li&gt;Part 4: Integration Guide&lt;/li&gt;
&lt;li&gt;Part 5: Best Practices&lt;/li&gt;
&lt;li&gt;Part 6: Getting Started&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Part 1: Understanding MCP
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is the Model Context Protocol?
&lt;/h3&gt;

&lt;p&gt;MCP is an open standard developed by Anthropic that lets AI assistants connect to external tools and data sources. Think of it as a universal adapter between AI models and specialized tools.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+--------------+      +----------------+      +---------------+
|   Claude     | &amp;lt;--&amp;gt; |  MCP Server    | &amp;lt;--&amp;gt; |  External     |
|  (AI Model)  |      |  (CrawlForge)  |      |  Resources    |
+--------------+      +----------------+      +---------------+
                             ^
                      MCP Protocol
                   (JSON-RPC over stdio)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Why MCP Matters for Web Scraping
&lt;/h3&gt;

&lt;p&gt;Before MCP, getting real-time web data into AI was painful:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Problems&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Training data&lt;/td&gt;
&lt;td&gt;Outdated, knowledge cutoff&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RAG (Retrieval)&lt;/td&gt;
&lt;td&gt;Limited to indexed documents&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Function calling&lt;/td&gt;
&lt;td&gt;Requires custom implementation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Browser plugins&lt;/td&gt;
&lt;td&gt;Inconsistent, security concerns&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;MCP solves these with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Standardized interface&lt;/strong&gt; -- One protocol for all tools&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time data&lt;/strong&gt; -- Fresh information from any source&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tool composability&lt;/strong&gt; -- Combine multiple tools seamlessly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security model&lt;/strong&gt; -- Controlled access to external resources&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  How MCP Works
&lt;/h3&gt;

&lt;p&gt;MCP uses a client-server architecture with JSON-RPC:&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Step 1: Server Discovery
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"crawlforge"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"crawlforge-mcp-server"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Step 2: Tool Registration -- the server advertises its capabilities
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tools"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fetch_url"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Fetch content from a URL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"inputSchema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"format"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"uri"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Step 3: Tool Invocation -- the AI calls a tool
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tools/call"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fetch_url"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"arguments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Step 4: Response -- structured data comes back
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"result"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;html&amp;gt;..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"headers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Part 2: The MCP Web Scraping Ecosystem
&lt;/h2&gt;

&lt;p&gt;Several MCP servers provide web scraping capabilities:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Server&lt;/th&gt;
&lt;th&gt;Tools&lt;/th&gt;
&lt;th&gt;Focus&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CrawlForge&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;18&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Comprehensive scraping, research, stealth&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Firecrawl&lt;/td&gt;
&lt;td&gt;~5&lt;/td&gt;
&lt;td&gt;Basic scraping and crawling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Browser MCP&lt;/td&gt;
&lt;td&gt;~3&lt;/td&gt;
&lt;td&gt;Browser automation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fetch MCP&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Simple HTTP requests&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CrawlForge: ████████████████████ 18 tools
Firecrawl:  █████                 5 tools
Browser:    ███                   3 tools
Fetch:      █                     1 tool
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 3: CrawlForge's 18 Tools Explained
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Basic Scraping (1-2 credits)
&lt;/h3&gt;

&lt;p&gt;&lt;/p&gt;
  1. fetch_url (1 credit) -- Fetch raw HTML from any URL
  &lt;p&gt;The foundation of web scraping. Always try this first.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Usage: "Fetch https://example.com"&lt;/span&gt;
&lt;span class="c1"&gt;// Returns:&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;html&amp;gt;...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;timing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;523&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt; Starting point for any scraping task.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  2. extract_text (1 credit) -- Clean text extraction
  &lt;p&gt;Removes HTML tags, scripts, and styles. Returns readable text with word count and reading time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt; Blog posts, articles, documentation where you need readable text.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  3. extract_links (1 credit) -- Discover all links on a page
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://example.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;filter_external&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;  &lt;span class="c1"&gt;// Internal links only&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// Returns: { links: [{ href: "/about", text: "About Us" }, ...], total: 45 }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt; Site exploration, finding pages to scrape, building sitemaps.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  4. extract_metadata (1 credit) -- SEO metadata extraction
  &lt;p&gt;Pulls title, description, Open Graph, JSON-LD structured data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt; SEO analysis, content previews, structured data extraction.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Structured Extraction (2-3 credits)
&lt;/h3&gt;

&lt;p&gt;&lt;/p&gt;
  5. scrape_structured (2 credits) -- CSS selector-based extraction
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://example.com/products&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;selectors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;h1.product-title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;span.price&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.product-description&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// Returns: { data: { title: "Product Name", price: "$99.99", description: "..." } }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt; E-commerce scraping, structured data, known page layouts.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  6. extract_content (2 credits) -- Intelligent article extraction
  &lt;p&gt;Like Readability -- returns title, author, published date, clean content, images, reading time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt; News articles, blog posts, editorial content.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  7. map_site (2 credits) -- Site structure discovery
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://example.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;max_urls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;include_sitemap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// Returns: pages[], structure tree&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt; Site audits, crawl planning, content discovery.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  8. analyze_content (3 credits) -- NLP analysis
  &lt;p&gt;Language detection, sentiment scoring, topic extraction, named entity recognition, readability analysis.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt; Content analysis, sentiment tracking, topic extraction.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Advanced Scraping (4-5 credits)
&lt;/h3&gt;

&lt;p&gt;&lt;/p&gt;
  9. process_document (2 credits) -- PDF and document handling
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://example.com/report.pdf&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;sourceType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pdf_url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// Returns: { text: "...", pages: 15, metadata: { author, created } }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt; Research papers, reports, documentation PDFs.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  10. summarize_content (4 credits) -- AI-powered summarization
  &lt;p&gt;Returns concise summary, key points, and word reduction percentage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt; Long documents, research synthesis, content digests.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  11. crawl_deep (4 credits) -- Multi-page crawling
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://example.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;max_depth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;max_pages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;include_patterns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/blog/*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="nx"&gt;exclude_patterns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/admin/*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt; Full site scraping, content aggregation, archiving.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  12. batch_scrape (5 credits) -- Parallel scraping of multiple URLs
  &lt;p&gt;Scrape up to 50 URLs in parallel with concurrency control.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt; Multiple known URLs, competitor monitoring, price tracking.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  13. scrape_with_actions (5 credits) -- Browser automation
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://example.com/app&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wait&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.content&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#load-more&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wait&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;scroll&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;body&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;screenshot&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt; SPAs, infinite scroll, dynamic content, login-required pages.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  14. search_web (5 credits) -- Google search integration
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;web scraping best practices 2026&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;site&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;github.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;  &lt;span class="c1"&gt;// Optional site filter&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt; Discovery, finding sources, research starting point.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Specialized Tools (2-10 credits)
&lt;/h3&gt;

&lt;p&gt;&lt;/p&gt;
  15. stealth_mode (5 credits) -- Anti-detection bypass
  &lt;p&gt;Hides WebDriver, randomizes fingerprints, simulates human behavior. Configurable stealth levels.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt; Protected sites, Cloudflare bypass, anti-bot evasion.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  16. track_changes (3 credits) -- Content monitoring
  &lt;p&gt;Set a baseline, then detect changes with before/after diffs and significance scoring.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt; Price monitoring, competitor tracking, content updates.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  17. localization (2 credits) -- Geo-targeted scraping
  &lt;p&gt;Set country code and language to get region-specific content and pricing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt; Regional pricing, localized content, geo-restricted data.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  18. deep_research (10 credits) -- Multi-source research
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;quantum computing commercialization&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;maxUrls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;enableSourceVerification&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;enableConflictDetection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// Returns: { synthesis, sources[], conflicts[], citations[] }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;When to use:&lt;/strong&gt; Research projects, due diligence, market analysis.&lt;/p&gt;



&lt;p&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Part 4: Integration Guide
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Claude Code Setup
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Install CrawlForge MCP server&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; crawlforge-mcp-server

&lt;span class="c"&gt;# 2. Run setup wizard&lt;/span&gt;
npx crawlforge-setup

&lt;span class="c"&gt;# 3. Add to Claude Code&lt;/span&gt;
claude
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /mcp add crawlforge npx crawlforge-mcp-server

&lt;span class="c"&gt;# 4. Verify&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /mcp list
&lt;span class="c"&gt;# Should show: crawlforge (18 tools)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Claude Desktop Setup
&lt;/h3&gt;

&lt;p&gt;Edit your config file:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;macOS:&lt;/strong&gt; &lt;code&gt;~/Library/Application Support/Claude/claude_desktop_config.json&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Windows:&lt;/strong&gt; &lt;code&gt;%APPDATA%\Claude\claude_desktop_config.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"crawlforge"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"crawlforge-mcp-server"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"CRAWLFORGE_API_KEY"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cf_live_your_key_here"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Custom Application (MCP SDK)
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Client&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@modelcontextprotocol/sdk/client/index.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;StdioClientTransport&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@modelcontextprotocol/sdk/client/stdio.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StdioClientTransport&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;npx&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;crawlforge-mcp-server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;CRAWLFORGE_API_KEY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CRAWLFORGE_API_KEY&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-app&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1.0.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// List available tools&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listTools&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Available tools: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Call a tool&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;callTool&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fetch_url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://example.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 5: Best Practices
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Credit Optimization
&lt;/h3&gt;

&lt;p&gt;Pick the cheapest tool that gets the job done:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Goal&lt;/th&gt;
&lt;th&gt;Expensive&lt;/th&gt;
&lt;th&gt;Efficient&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Check if page exists&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;deep_research&lt;/code&gt; (10)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;fetch_url&lt;/code&gt; (1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Get article text&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;scrape_with_actions&lt;/code&gt; (5)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;extract_content&lt;/code&gt; (2)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Find competitor URLs&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;search_web&lt;/code&gt; x 10 (50)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;extract_links&lt;/code&gt; (1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scrape 20 product pages&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;fetch_url&lt;/code&gt; x 20 (20)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;batch_scrape&lt;/code&gt; (5)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  Error Handling
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetchUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Try with stealth mode for blocked requests&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;stealthMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;retryDelay&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Rate Limiting
&lt;/h3&gt;

&lt;p&gt;Respect target sites:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Good: Reasonable delays&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;scrape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 1-3s delay&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Better: Use batch_scrape with built-in rate limiting&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;batchScrape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;delayBetweenRequests&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1500&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Caching
&lt;/h3&gt;

&lt;p&gt;Don't scrape the same URL twice:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ScrapedContent&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;smartScrape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetchUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 6: Getting Started
&lt;/h2&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
&lt;strong&gt;Free Tier&lt;/strong&gt; -- 1,000 one-time trial credits. All 18 tools available. No credit card required.&lt;br&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; crawlforge-mcp-server
npx crawlforge-setup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What 1,000 Credits Gets You
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Credits&lt;/th&gt;
&lt;th&gt;Capacity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Basic scraping&lt;/td&gt;
&lt;td&gt;&lt;code&gt;fetch_url&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1,000 pages&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Article extraction&lt;/td&gt;
&lt;td&gt;&lt;code&gt;extract_content&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;500 articles&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Site mapping&lt;/td&gt;
&lt;td&gt;&lt;code&gt;map_site&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;500 sites&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Batch jobs&lt;/td&gt;
&lt;td&gt;&lt;code&gt;batch_scrape&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;200 batches&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Research projects&lt;/td&gt;
&lt;td&gt;&lt;code&gt;deep_research&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;100 topics&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;MCP is the standard&lt;/strong&gt; -- All major AI assistants support it&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CrawlForge leads with 18 tools&lt;/strong&gt; -- 4x more than alternatives&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start simple&lt;/strong&gt; -- Use &lt;code&gt;fetch_url&lt;/code&gt; (1 credit) before reaching for advanced tools&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Combine tools&lt;/strong&gt; -- Chain operations for powerful workflows&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Be ethical&lt;/strong&gt; -- Respect &lt;code&gt;robots.txt&lt;/code&gt; and rate limits&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;strong&gt;More from CrawlForge:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.crawlforge.dev/blog/crawlforge-vs-firecrawl-mcp-web-scraper-comparison" rel="noopener noreferrer"&gt;CrawlForge vs Firecrawl Comparison&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.crawlforge.dev/blog/build-competitive-intelligence-agent-claude-crawlforge" rel="noopener noreferrer"&gt;Building a Competitive Intelligence Agent&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.crawlforge.dev/blog/stealth-mode-scraping-bypass-anti-bot-detection" rel="noopener noreferrer"&gt;Stealth Mode Technical Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.crawlforge.dev/blog/deep-research-automation-10-hours-to-10-minutes" rel="noopener noreferrer"&gt;Deep Research Automation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.crawlforge.dev/docs" rel="noopener noreferrer"&gt;Full Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://www.crawlforge.dev/signup" class="crayons-btn crayons-btn--primary" rel="noopener noreferrer"&gt;Start Free -- 1,000 Credits Included&lt;/a&gt;
&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>webdev</category>
      <category>ai</category>
      <category>webscraping</category>
    </item>
  </channel>
</rss>
