Agent skill
Firecrawl Webhooks Skill
Receive and verify Firecrawl webhooks. Use when setting up Firecrawl webhook handlers, debugging X-Firecrawl-Signature verification, or handling crawl, batch scrape, extract, agent, and monitor events like crawl.page, crawl.completed, batch_scrape.completed, and extract.completed.
Install this skill
npx skills add hookdeck/webhook-skills --skill firecrawl-webhooks
When to Use This Skill
- How do I receive Firecrawl webhooks?
- How do I verify the
X-Firecrawl-Signatureheader? - Why is my Firecrawl webhook signature verification failing?
- How do I handle
crawl.pageandcrawl.completedevents instead of polling? - How do I handle
batch_scrape,extract,agent, ormonitorwebhook events?
Verification (core)
Firecrawl signs the raw request body with HMAC-SHA256, keyed with your account webhook secret, and sends the hex digest in X-Firecrawl-Signature as sha256=<hex>. There is no timestamp or message ID in the signed content, and one account-wide secret signs every webhook. Read the raw body (any content type) and compare timing-safe.
Node:
const crypto = require('crypto');
function verify(rawBody, signatureHeader, secret) {
const [algo, sig] = (signatureHeader || '').split('=');
if (algo !== 'sha256' || !sig) return false;
const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
try {
return crypto.timingSafeEqual(Buffer.from(sig.toLowerCase()), Buffer.from(expected));
} catch {
return false;
}
}
Python:
import hmac, hashlib
def verify(raw_body: bytes, signature_header: str, secret: str) -> bool:
algo, _, sig = (signature_header or "").partition("=")
if algo != "sha256" or not sig:
return False
expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(sig.encode(), expected.encode())
In Express use express.raw({ type: '*/*' }) on the route so verification works whatever Content-Type arrives. Firecrawl has no SDK helper for webhook verification, so verification is manual in every framework.
For complete handlers with route wiring, event dispatch, and tests, see:
Common Event Types
The payload's type field carries the event name:
| Event | Description |
|---|---|
crawl.started | Crawl job begins processing |
crawl.page | A page was scraped during a crawl (data holds the page) |
crawl.completed | Crawl finished and all pages were processed |
batch_scrape.started | Batch scrape job begins processing |
batch_scrape.page | A URL was scraped during a batch scrape |
batch_scrape.completed | All URLs in the batch were processed |
extract.started | Extract job begins processing |
extract.completed | Extraction finished successfully |
extract.failed | Extraction failed (error has the reason) |
agent.started / agent.action / agent.completed / agent.failed / agent.cancelled | Agent job lifecycle |
monitor.page / monitor.check.completed | Monitor page scrape and check results |
For payload shapes and the full list, see references/overview.md and Firecrawl event types
Important Headers
| Header | Description |
|---|---|
X-Firecrawl-Signature | sha256=<hex> HMAC-SHA256 of the raw body |
Environment Variables
FIRECRAWL_WEBHOOK_SECRET=your_webhook_secret # Account settings > Advanced tab
Local Development
# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 firecrawl --path /webhooks/firecrawl
Reference Materials
- references/overview.md - Firecrawl webhook concepts, events, payloads, retries
- references/setup.md - Get the secret and attach a webhook to a job
- references/verification.md - Signature verification details and gotchas