Octocrawl / Blog

Moving a Firecrawl workflow to Octocrawl: check the v1 boundary first

A pixel-dithered Golden Gate Bridge at sunset, the city skyline behind it and fog over the bay.

Tested 16 October 2026 with official @mendable/firecrawl-js@4.42.0 against a local Octocrawl API. This is a version-bounded migration check, not v2 drop-in compatibility or a hosted-service benchmark.

Octocrawl is an option when you want to run scrape, map and crawl workflows on your own machine and inspect page evidence. Start by listing the endpoints and formats your application actually calls. Its local Firecrawl shim covers selected v1 shapes; changing the base URL of a current Firecrawl client is not enough to establish compatibility.

Firecrawl’s current introduction uses v2 API paths and documents a wider set of operations. Keep Firecrawl if your workflow depends on those APIs until you have a tested replacement. For a fresh Octocrawl integration, use its native reference and MCP setup rather than assuming a migration shim is a complete API.

Choose a deployment before comparing features

Decision Firecrawl Octocrawl
Managed service Official hosted API; current docs use v2 Hosted native REST/MCP; scrape and map, with mode/key restrictions
Run it yourself Official self-hosting guide; check that deployment’s supported features Local CLI/API/MCP; local crawl/batch/Monitor exist; capabilities depend on configuration
Compatibility bridge Audit the version your application sends Local /fc/v1/scrape, /fc/v1/map, /fc/v1/crawl, /fc/v1/crawl/:id; selected options only
Evidence / acceptance Inspect the actual fields your workflow uses Native evidenceRecord records source, fetch time and hashes; /fc keeps its response shape and does not carry that native record
Billing comparison Official pricing, retrieved 16 Oct: credit units depend on endpoint/features; free tier listed as 1,000 credits/month Hosted free account allowance is 1,000 credits/month; HTTP page 1 credit, browser page 5; local operation uses your infrastructure

These credits are not equal units of work across providers. No cost or speed winner is claimed. Firecrawl’s pricing page contains differing Monitor credit statements, so no Monitor price is reproduced here. Octocrawl’s core repository is AGPL-3.0-only; individual client packages have their own licenses (for example the TypeScript SDK is MIT). Firecrawl’s repository carries AGPL-3.0; review the applicable package/service terms for your deployment.

What the local bridge covers

The following is source-verified at Octocrawl commit bc47bf0e62b07c45b517c2761f1ccb8c7e599073, in packages/contracts/src/firecrawl.ts and packages/api/src/app.ts. Its snapshot names 18 September 2026 and v1. Parser fixtures and actual client calls were run on 16 October. The client was pinned to 4.42.0, the repository’s frozen comparison version; it is not asserted to be the newest release.

Scope Status Migration action
v1 scrape and map; crawl start/status Selected paths supported Keep /fc/v1 in a raw request; inspect the resulting envelope
Markdown, links, HTML/raw HTML and selected other formats/options Supported subset Check every option against parser refusals; do not assume unknown keys are ignored
Search, interact, agent, monitor and extract endpoints Outside shim Retain original service or write a separate native integration
JSON format through /fc Refused Use native Octocrawl JSON extraction and review its schema/source limits
Local browser actions Partial, local route/configuration dependent Test actual steps and returned artifact shapes; hosted service refuses actions
Default v2 method in the tested 4.42.0 client Fails at /fc/v2/scrape (404) Use an explicitly tested legacy v1 method or a native integration; changing the base URL alone fails
Hosted Octocrawl /fc Unavailable The public hosted gate refuses /fc; run the bridge yourself

What happened with an actual client

On 16 October 2026, we installed the official @mendable/firecrawl-js@4.42.0 from npm outside the Octocrawl checkout. Its requests went through a loopback logging relay to the real local API at source commit 23517407f5c75aa0135db28a9eb42ee498adad23. The relay recorded HTTP requests/responses without mocking the SDK or extraction engine. Public target fetches used the shell’s existing operator proxy; loopback traffic was direct. No Firecrawl hosted calls or paid credits were used.

Call Wire result What the application sees
client.scrape(...), base URL ending in /fc POST /fc/v2/scrape, 404 v2 SDK error; no matching route
client.v1.scrapeUrl(...) POST /fc/v1/scrape, 200, success:true Flattened markdown, html, links, metadata; no data wrapper
v1 scrape of an intentionally missing page API HTTP 200, success:false, target metadata.statusCode:404, metadata.error:http_error SDK throws a misleading “No response received” error with statusCode:0; the wire did receive a response
v1 scrape with JSON format or an unknown parameter HTTP 400 with a named refusal SDK throws; JSON is not available through this bridge
v1 map with sitemap disabled, search and limit POST /fc/v1/map, 200 URL strings; the controlled child filter returned exactly the expected child URL
v1 map with useIndex:true HTTP 400 unsupported_parameter SDK throws; no implicit URL index
v1 crawl start and default status check, limit:1 POST /fc/v1/crawl, then GET /fc/v1/crawl/:id One completed page; this does not test full-site completeness or multi-page pagination
v1 status check with explicit skip:0 HTTP 400, use next instead SDK reports statusCode:500, masking the wire status

The crawl wire response also had expiresAt:null; this SDK converted it to a JavaScript date at 1970-01-01T00:00:00.000Z. Do not interpret that date as a real expiry. These are observed integration caveats, not claims about every Firecrawl client version.

The successful public example returned readable content, while the missing public path returned a genuine target 404 retained inside the failure response. Separate synthetic HTTP pages then checked exact heading/body/link markers: formats: markdown/html/rawHtml/links, includeTags, excludeTags, onlyMainContent:false, fastMode and timeout all reached the API. The Markdown kept the expected absolute child link, cleaned output removed the excluded marker, and raw HTML retained it. Ten controlled client acceptance cases passed, including expected refusals and error-shape mismatches. This validates the listed calls and markers; it does not measure arbitrary-site extraction quality, browser actions, PDF behavior, timeouts under load or service parity.

Try an explicitly versioned v1 call

Start the source checkout used for this check with npm run api (default port 8787), after installing/building its dependencies. Install the pinned client in a separate example project. The base URL ends in /fc, because the SDK appends /v1/scrape itself:

javascript
import Firecrawl from '@mendable/firecrawl-js'; // tested: 4.42.0

const client = new Firecrawl({
  apiKey: 'local-test-only', // dummy label for this loopback server, not a hosted key
  apiUrl: 'http://127.0.0.1:8787/fc',
});

try {
  const page = await client.v1.scrapeUrl('https://example.com/', {
    formats: ['markdown', 'links'],
    fastMode: true, // HTTP only; not a browser fallback
    timeout: 15000,
  });
  // The v1 SDK flattens data. Do not read page.data.markdown here.
  if (page.success !== true || !page.markdown?.trim()) {
    throw new Error('No usable page body');
  }
  console.log(page.markdown, page.metadata?.statusCode);
} catch (error) {
  // For this tested SDK, inspect the API response/log when diagnosing failures:
  // a thrown statusCode 0 can conceal HTTP 200 + success:false.
  console.error(error.message);
}

A nonempty page remains unverified against your task. The bridge does not carry the native evidenceRecord, verification and readiness objects; use the native API when your acceptance check needs those fields. This small example uses the public documentation example domain once; use your own permitted target for sustained tests.

The repository includes the actual-client acceptance harness and reproduction procedure. The harness uses synthetic local HTTP pages and the real SDK/API. Existing parser fixtures remain separately reproducible:

bash
npx vitest run packages/contracts/test/firecrawl.test.ts

Those 24 parser cases and the ten actual-client fixture cases test different layers. Neither runs Firecrawl’s hosted service or establishes cost, speed or coverage superiority. A measured comparison needs identical URLs, declared expected content, versions, region, cache/retry policy and timing boundaries, with every failed/partial item retained.

Who should try which path?

Try native Octocrawl locally if keeping scrape records on your infrastructure and inspecting provenance matters, and you can validate its output on your actual targets. Try the limited bridge only when your existing calls fit its selected v1 surface. Keep or evaluate Firecrawl when you need its documented v2 API families or a managed workflow that has not been reproduced in Octocrawl. Use the free converter to inspect a single eligible public page before building an integration; it is HTTP-only and has its own limits.

Try a page in the browser here, connect your agent to mcp.octocrawl.dev, or run Octocrawl on your computer with npx.Try a page ↗GitHub ↗