Firecrawl Security Basics
Overview
Security best practices for Firecrawl API keys, webhook signature verification, and scraped content handling. Firecrawl API keys start with fc- and grant full access to scrape, crawl, map, and extract endpoints — protecting them is critical.
Prerequisites
- Firecrawl API key
- Understanding of environment variables
- Webhook endpoint (if using async crawl callbacks)
Instructions
Step 1: Secure API Key Storage
FIRECRAWL_API_KEY=fc-your-api-key-here
echo -e "\n.env\n.env.local\n.env.*.local" >> .gitignore
import FirecrawlApp from "@mendable/firecrawl-js";
if (!process.env.FIRECRAWL_API_KEY?.startsWith("fc-")) {
throw new Error("FIRECRAWL_API_KEY must be set and start with 'fc-'");
}
const firecrawl = new FirecrawlApp({
apiKey: process.env.FIRECRAWL_API_KEY,
});
Step 2: Verify Webhook Signatures
Firecrawl signs webhook payloads with HMAC-SHA256 via the X-Firecrawl-Signature header.
import crypto from "crypto";
function verifyWebhookSignature(
payload: string,
signature: string,
secret: string
): boolean {
const expected = crypto
.createHmac("sha256", secret)
.update(payload)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
app.post("/webhooks/firecrawl", (req, res) => {
const signature = req.headers["x-firecrawl-signature"] as string;
const rawBody = JSON.stringify(req.body);
if (!verifyWebhookSignature(rawBody, signature, process.env.FIRECRAWL_WEBHOOK_SECRET!)) {
console.error("Invalid webhook signature — rejecting");
return res.status(401).json({ error: "Invalid signature" });
}
const { type, data } = req.body;
console.log(`Verified webhook: ${type}`);
res.status(200).json({ received: true });
});
Step 3: Separate Keys per Environment
gh secret set FIRECRAWL_API_KEY_DEV --body "fc-dev-..."
gh secret set FIRECRAWL_API_KEY_STAGING --body "fc-staging-..."
gh secret set FIRECRAWL_API_KEY_PROD --body "fc-prod-..."
const KEY_MAP: Record<string, string> = {
development: "FIRECRAWL_API_KEY_DEV",
staging: "FIRECRAWL_API_KEY_STAGING",
production: "FIRECRAWL_API_KEY_PROD",
};
const envVar = KEY_MAP[process.env.NODE_ENV || "development"];
const apiKey = process.env[envVar] || process.env.FIRECRAWL_API_KEY;
Step 4: Rotate Keys
set -euo pipefail
curl -s https://api.firecrawl.dev/v1/scrape \
-H "Authorization: Bearer $NEW_FIRECRAWL_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com","formats":["markdown"]}' | jq .success
Step 5: Sanitize Scraped Content
function sanitizeScrapedContent(markdown: string): string {
return markdown
.replace(/<script[\s\S]*?<\/script>/gi, "")
.replace(/!\[.*?\]\(data:.*?\)/g, "")
.replace(/\[.*?\]\(javascript:.*?\)/g, "")
.replace(/<!--[\s\S]*?-->/g, "")
.trim();
}
Security Checklist
Error Handling
| Security Issue | Detection | Mitigation |
|---|
| Leaked API key in git | git log -p | grep "fc-" | Rotate immediately, revoke old key |
| Invalid webhook signature | Signature verification fails | Reject request, alert team |
| Excessive scraping costs | Credit alerts from Firecrawl | Set credit limits per key |
| PII in scraped content | Content scanning | Sanitize before storage |
Resources
Next Steps
For production deployment, see firecrawl-prod-checklist.