Migrate from Firecrawl to Skryp
Skryp serves Firecrawl-shaped endpoints under /v2. Code written for Firecrawl's v2 API, including Firecrawl's own SDKs, works against Skryp when you change the API URL and the key. Every row below was called through the official SDKs on 1 October 2026; anything not listed is not supported.
Change two lines
With the Python SDK, keep your code and give the client Skryp's address and your Skryp key. This ran as shown:
migrate-firecrawl/01-firecrawl-sdk.py
# The official Firecrawl Python SDK, unchanged, pointed at Skryp: only the API URL and the key differ.
# pip install firecrawl-py export SKRYP_API_KEY=...
import os
from firecrawl import Firecrawl
app = Firecrawl(api_key=os.environ["SKRYP_API_KEY"], api_url=os.environ.get("SKRYP_API_URL", "https://api.skryp.dev"))
doc = app.scrape("https://quotes.toscrape.com/", formats=["markdown", "links"])
print(f"scrape: {doc.metadata.title!r}, {len(doc.markdown)} characters of Markdown, {len(doc.links)} links")
site = app.map("https://books.toscrape.com/", limit=20)
print(f"map: {len(site.links)} URLs, first {site.links[0].url}")
found = app.search("books to scrape", limit=3)
print(f"search: {[r.url for r in found.web]}")
crawl = app.crawl("https://quotes.toscrape.com/", limit=3, poll_interval=2)
print(f"crawl: {crawl.status}, {len(crawl.data)} pages")
batch = app.batch_scrape(["https://quotes.toscrape.com/page/1/", "https://quotes.toscrape.com/page/2/"], formats=["markdown"], poll_interval=2)
print(f"batch scrape: {batch.status}, {len(batch.data)} pages")
usage = app.get_credit_usage()
print(f"credit usage: {usage.remaining_credits} credits remaining")OutputRan 1 Oct 2026 · Python 3.12.14, firecrawl-py 4.45.1 · 7.7 s
scrape: 'Quotes to Scrape', 4239 characters of Markdown, 49 links
map: 20 URLs, first https://books.toscrape.com/index.html
search: ['https://books.toscrape.com/', 'https://toscrape.com/', 'https://github.com/kawsarlog/books-to-scrape-web-scraper']
crawl: completed, 3 pages
batch scrape: completed, 2 pages
credit usage: 20861 credits remainingThe JavaScript SDK works the same way:
migrate-firecrawl/03-firecrawl-js-sdk.mjs
// The official Firecrawl JavaScript SDK, unchanged, pointed at Skryp: only the API URL and the key differ.
// npm install @mendable/firecrawl-js export SKRYP_API_KEY=...
import Firecrawl from "@mendable/firecrawl-js";
const app = new Firecrawl({ apiKey: process.env.SKRYP_API_KEY, apiUrl: process.env.SKRYP_API_URL ?? "https://api.skryp.dev" });
const doc = await app.scrape("https://quotes.toscrape.com/", { formats: ["markdown"] });
console.log(`scrape: ${JSON.stringify(doc.metadata.title)}, ${doc.markdown.length} characters of Markdown`);
const site = await app.map("https://books.toscrape.com/", { limit: 20 });
console.log(`map: ${site.links.length} URLs`);
const found = await app.search("books to scrape", { limit: 3 });
console.log(`search: ${found.web.map((r) => r.url).join(", ")}`);
const crawl = await app.crawl("https://quotes.toscrape.com/", { limit: 3, pollInterval: 2 });
console.log(`crawl: ${crawl.status}, ${crawl.data.length} pages`);OutputRan 1 Oct 2026 · Node.js 24.16.0, @mendable/firecrawl-js 4.42.1 · 6.6 s
scrape: "Quotes to Scrape", 4239 characters of Markdown
map: 20 URLs
search: https://books.toscrape.com/, https://toscrape.com/, https://www.geeksforgeeks.org/python/scrap-books-using-beautifulsoup-from-books-toscrape-in-python/
crawl: completed, 3 pagesWhat was tested
Tested 1 October 2026
Through the official Python SDK (firecrawl-py 4.45.1) and JavaScript SDK (@mendable/firecrawl-js 4.42.1), against Skryp's preview service. Re-tested whenever the /v2 routes change.
| Endpoint or option | Status | Notes |
|---|---|---|
POST /v2/scrape: Markdown, links, HTML, raw HTML, images, screenshot | Tested | A screenshot comes back as a link to the image stored by Skryp. |
POST /v2/scrape with a json format (prompt or schema) | Tested | Runs Skryp extraction; values are checked against the page. |
Actions: wait, click, write, press, scroll, screenshot | Tested | Run as Skryp browser steps. |
location.country, proxy: basic or enhanced | Tested | basic uses our own network; enhanced a residential proxy in the country. The verified exit is in metadata.egress. |
POST /v2/map | Tested | |
POST /v2/search | Tested | Results under data.web. |
POST /v2/crawl, GET /v2/crawl/{id}, DELETE /v2/crawl/{id} | Tested | |
POST /v2/batch/scrape, GET /v2/batch/scrape/{id} | Tested | |
POST /v2/extract, GET /v2/extract/{id} | Tested | An answer that is a list comes back under items. |
GET /v2/team/credit-usage | Tested | Shows your Skryp balance. |
| Change tracking, branding, summary and audio formats | Not supported | Use Skryp's monitor and extract instead. |
Here is the second half of the test, as it ran:
migrate-firecrawl/02-formats-actions-extract.py
# The rest of the Firecrawl v2 surface through the official SDK: other formats, page actions, extract, cancel.
# pip install firecrawl-py export SKRYP_API_KEY=...
import os
import re
from firecrawl import Firecrawl
app = Firecrawl(api_key=os.environ["SKRYP_API_KEY"], api_url=os.environ.get("SKRYP_API_URL", "https://api.skryp.dev"))
URL = "https://quotes.toscrape.com/"
def check(name, fn):
try:
print(f"ok {name}: {fn()}")
except Exception as e: # report and carry on, so one gap does not hide the others
print(f"FAIL {name}: {type(e).__name__}: {str(e)[:160]}")
check("html", lambda: f"{len(app.scrape(URL, formats=['html']).html)} characters")
check("rawHtml", lambda: f"{len(app.scrape(URL, formats=['rawHtml']).raw_html)} characters")
check("images", lambda: f"{len(app.scrape('https://books.toscrape.com/', formats=['images']).images)} image URLs")
check("screenshot", lambda: app.scrape(URL, formats=["screenshot"]).screenshot[:40] + "…")
check("json with a prompt", lambda: app.scrape(URL, formats=[{"type": "json", "prompt": "The first quote's text and author"}]).json)
def page_two_by_click():
doc = app.scrape(
"https://quotes.toscrape.com/js/",
formats=["markdown"],
actions=[{"type": "wait", "milliseconds": 1000}, {"type": "click", "selector": "li.next a"}, {"type": "wait", "milliseconds": 1000}],
)
return f"after clicking Next the browser is on {doc.metadata.url}"
check("actions", page_two_by_click)
check("extract", lambda: app.extract(urls=[URL], prompt="The authors of the first three quotes").data)
def country():
doc = app.scrape("https://ipinfo.io/json", formats=["markdown"], location={"country": "DE"}, proxy="enhanced")
exit_ = doc.metadata.egress # Skryp adds the verified exit to Firecrawl's metadata
seen = re.search(r'"country": "(\w\w)"', doc.markdown).group(1)
return f"exit {exit_['country'].upper()} (verified: {exit_['verified']}), and ipinfo.io saw a request from {seen}"
check("location.country + proxy=enhanced", country)
def start_and_cancel():
job = app.start_crawl("https://books.toscrape.com/", limit=50)
return f"crawl {job.id} cancelled: {app.cancel_crawl(job.id)}"
check("cancel crawl", start_and_cancel)OutputRan 1 Oct 2026 · Python 3.12.14, firecrawl-py 4.45.1 · 12 s
ok html: 10723 characters
ok rawHtml: 10968 characters
ok images: 20 image URLs
ok screenshot: https://api.skryp.dev/v1/blob/32e376b76b…
ok json with a prompt: {'quote_text': 'The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.', 'author': 'Albert Einstein'}
ok actions: after clicking Next the browser is on https://quotes.toscrape.com/js/page/2/
ok extract: {'items': [{'author': 'Albert Einstein'}, {'author': 'J.K. Rowling'}, {'author': 'Albert Einstein'}]}
ok location.country + proxy=enhanced: exit DE (verified: True), and ipinfo.io saw a request from DE
ok cancel crawl: crawl job_084d93666218 cancelled: TrueDifferences to know
- Credits are Skryp credits. A standard request costs 1 credit, as a basic page does on Firecrawl. Heavier methods cost what they use: 5 credits through a residential proxy (10 with JavaScript rendering) and 25 for advanced unblocking, only when it succeeds; AI extraction adds 5. See Credits and prices.
- Blocked pages cost nothing. Skryp charges 0 credits for a page it could not get past or could not load. A page that loads with an error status, such as a 404, costs its route's price on Skryp and 1 credit on Firecrawl; Firecrawl also charges 1 credit for a page that answers 403.
- Every result says where it came from. Skryp adds
metadata.egress(the exit's country, city and network, and whether it was verified) andmetadata.creditsUsedto scrape results. See Receipts. - Strict country. Add
strictCountry: trueand a country request fails rather than quietly using another country.
Next steps
- Compare the two services on the same 170 pages: Skryp vs Firecrawl.
- Connect an agent over MCP instead of the REST API: Quickstart.