Firecrawl Action
Scrape, crawl, search, and map web pages as part of your webhook pipelines. Extract structured data, convert pages to markdown, discover URLs, or search the web — all powered by the Firecrawl API. You provide your own Firecrawl API key.
Overview
The Firecrawl Action node connects to the Firecrawl API to perform web scraping operations. It supports four modes — picked under Operation on the node page — each suited for different use cases, or all four as an AI toolkit. The node appears on the canvas with an orange color.
A new Firecrawl node starts with no operation picked, and it doesn't run until you pick one — so nothing gets scraped, or charged to your Firecrawl credits, by a node nobody set up.
Modes
Scrape
Extracts content from a single URL. Returns markdown, HTML, screenshots, or structured JSON. Best for extracting data from a specific page — product prices, article content, form data, etc.
{{payload.url}} in the URL field to dynamically scrape whatever URL your webhook receives.Crawl
Recursively crawls an entire website starting from a base URL. Discovers and scrapes multiple pages following links. Returns an array of scraped pages — the output is marked as iterable so downstream nodes process each page individually.
By default a crawl only follows pages under the start URL's path: starting at https://site.com/docs/intro it reads/docs/intro and what hangs below it, and starting at a single article it reads just that article. Turn on Crawl the whole site (v2) to also follow links to sibling and parent pages of the same site.
Search
Searches the web for a query and returns scraped content from the results. Combines web search with page scraping in one step. Returns an array of results — also iterable.
Map
Discovers all URLs on a website without scraping them. Returns a list of links with titles and descriptions. Useful for discovering pages before selectively scraping them with a downstream Firecrawl node. Output is iterable.
Node versions
Firecrawl is the first node type with two versions. The pill next to the breadcrumb on the node's page (v1 / v2) says which one a node is on and opens the picker to change it.
| Version | What you can configure |
|---|---|
| v2 current | Formats (several at once), structured extraction as the json format with a prompt and/or a schema, wait-for, include/exclude tags, AI clean-up, base64 images, location and Firecrawl's cache. New nodes are born on v2. |
| v1 legacy | Markdown only, no format selector. Nodes created before v2 existed are on v1 and keep running exactly as they did. |
Switching a node to another version never touches its name, its connections or whether it is active. Going from v1 to v2 loses nothing. Going back to v1 removes the five v2-only settings (onlyCleanContent, removeBase64Images, location, maxAge, scrapeResults) — the dialog lists exactly what goes — and the change can be undone from the same pill.
Configuration
Common Fields
| Field | Type | Default | Description |
|---|---|---|---|
| name | string | — | Display name for the node |
| mode | enum | scrape | scrape | crawl | search | map |
| credentialId | ObjectId | — | Reference to a stored Firecrawl API key (required) |
| triggerOn | enum | success | success | always |
Scrape / Crawl Fields
| Field | Type | Default | Description |
|---|---|---|---|
| url | string | — | Target URL — supports {{payload.field}} templates |
| formats | string[] | ["markdown"] | Output formats, several at once: markdown, html, rawHtml, links, images, summary, screenshot, json. Each one arrives as its own field in the output. The selector is on v2; v1 always asks for markdown. |
| onlyMainContent | boolean | true | Exclude headers, navs, footers |
| timeout | number | 60000 | Scrape timeout in milliseconds |
| mobile | boolean | false | Emulate a mobile device |
| blockAds | boolean | true | Block ads and cookie popups |
Crawl-Specific Fields
| Field | Type | Default | Description |
|---|---|---|---|
| maxDepth | number | 2 | Maximum crawl depth from the starting URL |
| maxPages | number | 10 | Maximum number of pages to crawl |
| crawlTimeout | number | 300000 | Max wait time for crawl completion (ms), at most 5 minutes. When it runs out the crawl is cancelled |
| crawlEntireDomain | boolean | false | v2: also follow links outside the start URL's path (sibling and parent pages). Off, only pages under it are read |
| allowExternalLinks | boolean | false | Follow links to external domains |
Search-Specific Fields
| Field | Type | Default | Description |
|---|---|---|---|
| query | string | — | Search query — supports {{payload.field}} templates |
| searchLimit | number | 5 | Maximum number of search results (max 100) |
| country | string | US | ISO country code for geo-targeted results |
| scrapeResults | boolean | true | v2 only. true scrapes every result with the formats you picked (scrape credits per result); false returns only title, description and URL — no scraping. |
Map-Specific Fields
| Field | Type | Default | Description |
|---|---|---|---|
| mapLimit | number | 5000 | Maximum number of URLs to discover (max 100,000) |
| includeSubdomains | boolean | true | Include subdomains in URL discovery |
Structured Extraction (Scrape / Search)
Ask Firecrawl to extract structured data from the page with a prompt, a schema, or both. It is sent as the json format and the result lands in json in the output. On v2, turn on the JSON format chip and the section appears; turn it off and no extraction is requested (your prompt and schema are kept for later). On v1 only the prompt is available.
The schema box takes one field per line, field: type. This asks for a name, a price, a stock flag, a list of tags, a nested author and a free-text summary:
name: string
price: number
inStock: boolean
tags: string[]
author.name: string
summary: A one-line summary of the pageTypes are string, number, integer, boolean, object, array, and any of them with [] for a list. Dots nest (author.name). Any other text is read as the description of a text field — a good place to tell the model what you mean. Every field you list is requested. The node turns this into a JSON Schema when it calls Firecrawl; a full JSON Schema pasted as-is works too.
{
"json": {
"name": "Nest: Desarrollo backend escalable con Node",
"price": 19.99,
"inStock": true,
"tags": ["backend", "typescript"],
"author": { "name": "Fernando Herrera" },
"summary": "A hands-on course on building APIs with NestJS."
},
"metadata": { "title": "...", "url": "...", "statusCode": 200 }
}| Field | Type | Description |
|---|---|---|
| extractPrompt | string | Natural language prompt describing what to extract |
| extractSchema | object | The fields to extract, as { "name": "string" } shorthand or a full JSON Schema. Optional. |
v2-only fields
| Field | Type | Description |
|---|---|---|
| waitFor | number (ms) | Extra delay before reading the page, for content that loads late. Default 0. |
| includeTags / excludeTags | string[] | CSS selectors or tags to keep or drop (e.g. article, .ads). |
| onlyCleanContent | boolean | AI-based removal of boilerplate the main-content filter misses. Default false. |
| removeBase64Images | boolean | Strip inline images from the Markdown. Default true. |
| location | { country, languages } | Where the page is fetched from (ISO country code) and the preferred languages. |
| maxAge | number (ms) | null | How old a cached copy may be. 0 means always fresh; null leaves Firecrawl's default, which is up to 48 hours. |
| scrapeResults | boolean | Search only. Whether each result is scraped with the chosen formats (true, the default) or just listed with title, description and URL (false, no scrape credits). |
maxAge: 0), or you may be reading yesterday's page.Output Payload
Scrape Output
Returns a single object with the scraped content. Not iterable.
{
"_meta": { "iterable": false, "count": 1 },
"markdown": "# Page Title\n\nPage content...",
"links": ["https://example.com/about", "https://example.com/pricing"],
"json": { "price": 19.99, "inStock": true },
"metadata": {
"title": "Page Title",
"url": "https://example.com",
"statusCode": 200
}
}Every format you asked for arrives as its own field — html, rawHtml, images, summary, screenshot (a URL that expires in 24 hours) and so on.
Crawl Output
Returns an array of pages. Marked as iterable — downstream nodes process each page individually.
{
"_meta": { "iterable": true, "iterateField": "pages", "count": 5 },
"pages": [
{ "markdown": "# Page 1...", "metadata": { "sourceURL": "https://example.com/" } },
{ "markdown": "# Page 2...", "metadata": { "sourceURL": "https://example.com/about" } }
]
}Search Output
Returns an array of search results with scraped content. iterable.
{
"_meta": { "iterable": true, "iterateField": "results", "count": 5 },
"results": [
{ "url": "https://example.com", "title": "Example", "markdown": "..." },
{ "url": "https://other.com", "title": "Other", "markdown": "..." }
]
}Map Output
Returns an array of discovered URLs. iterable.
{
"_meta": { "iterable": true, "iterateField": "links", "count": 150 },
"links": [
{ "url": "https://example.com/", "title": "Home", "description": "..." },
{ "url": "https://example.com/about", "title": "About Us" }
]
}AI toolkit mode
Once the API key is picked, the node asks for a Mode. Single operation is everything above: one of the four operations, your templates, every run. AI toolkit turns the node into four tools that an AI Node — or an MCP client, through one of your MCP servers — calls by name, with the URL or the query and every option of the v2 decided per call.
| Tool | Does | Arguments |
|---|---|---|
| scrape_url | Reads one page — the Scrape mode | url · formats? · only_main_content? · only_clean_content? · remove_base64_images? · wait_for_ms? · timeout_ms? · mobile? · block_ads? · include_tags? · exclude_tags? · location_country? · location_languages? · max_age_ms? · extract_prompt? · extract_schema? |
| crawl_site | Reads several pages of a site by following its links — the Crawl mode. Blocked by default. | url · max_pages? · max_depth? · include_paths? · exclude_paths? · allow_external_links? · crawl_timeout_ms? · formats? · only_main_content? · only_clean_content? · remove_base64_images? · wait_for_ms? · timeout_ms? · mobile? · block_ads? · include_tags? · exclude_tags? · location_country? · location_languages? · max_age_ms? · extract_prompt? · extract_schema? |
| search_web | Searches the web, and optionally reads each result — the Search mode | query · limit? · sources? · country? · scrape_results? · formats? · only_main_content? · only_clean_content? · remove_base64_images? · wait_for_ms? · timeout_ms? · mobile? · block_ads? · include_tags? · exclude_tags? · location_country? · location_languages? · max_age_ms? · extract_prompt? · extract_schema? |
| map_site | Lists the URLs of a site without reading them — the Map mode | url · limit? · include_subdomains? |
Lists go comma-separated. formats takes markdown, html, rawHtml, links, images, summary, screenshot and json (with extract_prompt or extract_schema); sources takes web, news and images. The tools always run as the v2, whatever version the node is on.
What you control
Very little, on purpose: the model decides the rest from what the user asks. What you set in Single operation — formats, mobile, country, limits — does not apply to the tools. The two settings live in the Settings card of the node's AI Toolkit section, and both are optional.
- Allowed domains. With a list, the model can only scrape, crawl and map those domains and their subdomains, a crawl never follows links out of them, and a search only looks inside them — the query is limited with
site:, so no credits go to reading results that would be thrown away. Anything from another domain that still comes back is dropped before the model sees it. Empty means any site. - Characters per page sent to the model. 20,000 by default (about 5,000 tokens), anything from 1,000 to 200,000. Lower it to save tokens; raise it when the agent needs whole long pages and its model has the context for them.
- Fixed limits. Not a setting: a crawl reads at most 50 pages and waits between 30 seconds and 5 minutes, a search returns at most 20 results and a map at most 5,000 URLs. When the model asks for more (or less), the call runs at the limit and the answer says so. Without instructions it uses Firecrawl's usual defaults — markdown, main content only, ads blocked, 10 pages, 5 results — and a map returns 100 URLs.
crawl_siteonly follows pages under its start URL unless the model passescrawl_entire_domain. - Crawling starts blocked. One
crawl_sitecall can spend many credits and take minutes. Unblock it under Block these tool calls if the agent needs it; block any other tool the same way.
What goes back to the model
The same response Firecrawl returns, with two cuts so it fits a model's context: each page's markdown, HTML and summary stop at the node's characters-per-page limit (20,000 unless you change it), and link and image lists at 500. A map's list of URLs is cut to fit the same characters limit. Every cut is listed in a notes field, so the model knows it didn't get everything. Arguments are used as written: a {{payload.x}} the model writes is not resolved, so it can't read the output of other nodes in the flow.
Testing a tool
operation in their payload that names another tool is refused.{ "operation": "scrape_url", "url": "https://example.com/pricing", "formats": "markdown,links" }Use Cases
Price Tracking
Webhook (product URL) --> Firecrawl (scrape) --> Transform (extract price) --> Google Sheets (save)Competitor Monitoring
Scheduled Workflow (daily) --> Firecrawl (crawl competitor site) --> Filter (changed pages) --> Email (report)Web Search + AI Summary
Webhook (search query) --> Firecrawl (search) --> AI Node (summarize) --> Notification (Discord)Site Discovery + Selective Scraping
Webhook (URL) --> Firecrawl (map) --> Split (per URL) --> Firecrawl (scrape each) --> MongoDB (save)Research agent (AI toolkit)
Chat Trigger --> AI Node · tools: Firecrawl toolkit (search_web, map_site, scrape_url)The agent searches, maps the site it lands on and reads the pages that answer the question — each step decided per turn. Add your own domains under Allowed domains to make it a support agent that only reads your documentation.
API Key Setup
The Firecrawl node requires a Firecrawl API key. Get one at firecrawl.dev. In the node's detail page, click "Add Firecrawl API Key" to store it securely in the credentials system. The key is encrypted at rest and never exposed in API responses.
API Reference
Create
curl -X POST /api/firecrawl-actions \
-H "Authorization: Bearer hwk_..." \
-d '{
"workspaceId": "<your-workspace-id>",
"name": "Scrape Product",
"mode": "scrape",
"url": "{{payload.url}}",
"formats": ["markdown"],
"onlyMainContent": true,
"credentialId": "..."
}'Test
curl -X POST /api/firecrawl-actions/:id/test \
-H "Authorization: Bearer hwk_..." \
-d '{ "payload": { "url": "https://example.com" } }'