crw-extract — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited crw-extract (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
but you need machine-readable fields. If the source is a local PDF, use crw-parse (step 5) with formats:["json"] instead.
prompt to describe what you want.
crw has no `/v1/extract` endpoint (Firecrawl's dedicated extract API). Instead, extraction runs in two ways, both backed by the same LLM pipeline:
| Path | When to use | Sync? |
|---|---|---|
Per-page: formats:["json"] + jsonSchema on scrape | Single URL, or inline during a crawl | Synchronous |
Async multi-URL: POST /v2/extract → poll GET /v2/extract/{id} | Many URLs, fire-and-forget | Async |
/v2/extract is marked deprecated in the server (it recommends /v2/scrape with formats:["json"]), but it works and is useful for multi-URL batches.
Requires a server-side LLM. Set [extraction.llm] in the server config (provider, api_key, model). Without it, requests return an error (HTTP 4xx) — e.g. 422 "no LLM configured". Use crw setup to configure the LLM for the CLI.
CLI — per-page extraction via --extract:
# Inline schema
crw scrape "https://example.com/product" \
--extract '{"type":"object","properties":{"price":{"type":"number"},"inStock":{"type":"boolean"}}}'
# Schema from file
crw scrape "https://example.com/job" --extract @schema.json -o result.jsonMCP — pass formats:["json"] with jsonSchema on a scrape:
crw_scrape(
url="https://example.com/product",
formats=["json"],
extract={"schema": {"type":"object","properties":{"price":{"type":"number"}}}}
)Note: the MCP crw_scrape accepts extract.schema (Firecrawl style). The REST API also accepts jsonSchema as a top-level alias.
REST — per-page (synchronous):
curl -X POST "$CRW_API_URL/v1/scrape" \
-H "Authorization: Bearer $CRW_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/product",
"formats": ["json"],
"jsonSchema": {
"type": "object",
"properties": {
"price": {"type": "number"},
"inStock": {"type": "boolean"}
}
}
}'REST — async multi-URL (deprecated endpoint, still functional):
# Start job
curl -X POST "$CRW_API_URL/v2/extract" \
-H "Authorization: Bearer $CRW_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"urls": ["https://example.com/p1", "https://example.com/p2"],
"schema": {"type":"object","properties":{"price":{"type":"number"}}}
}'
# → {"success":true,"id":"<uuid>","warnings":["...use /v2/scrape..."], ...}
# Poll until completed
curl "$CRW_API_URL/v2/extract/<uuid>" -H "Authorization: Bearer $CRW_API_KEY"
# → {"success":true,"status":"completed|scraping|failed","data":{...}}| Need | CLI | MCP / REST |
|---|---|---|
| JSON schema | --extract '<schema>' or @file.json | jsonSchema / extract.schema |
| Free-text prompt (no schema) | — | prompt on /v2/extract |
| Save output | -o FILE | write the response yourself |
| Multi-URL async | not available | POST /v2/extract with urls:[...] |
| LLM override | --llm-provider, --llm-key, --llm-model | server config only |
shape; a free-text prompt is useful for exploration but less reliable. Start with a schema when you know the fields you want.
extract more reliably than wide ones with fifty optional fields.
crw_crawl accepts a jsonSchema parameter— each page in the crawl gets extracted against the schema, saving a second round-trip.
data.json, not data.markdown. The markdown field is also populated for reference.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.