> ## Documentation Index
> Fetch the complete documentation index at: https://docs.firecrawl.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Node.js Source of Truth

> Canonical Firecrawl Node.js source of truth for agents using key endpoints like search, scrape, and interact.

Canonical Firecrawl Node.js source of truth for agents. Aligned with `firecrawl` **v4.18.2** (`firecrawl/apps/js-sdk/firecrawl`) and the v2 OpenAPI spec. Method names, parameters, and types match the SDK public API.

## Install

```bash theme={null}
npm install firecrawl
```

## Authenticate

```ts theme={null}
import { Firecrawl } from "firecrawl";

const client = new Firecrawl({
  apiKey: process.env.FIRECRAWL_API_KEY,
  // apiUrl: "https://api.firecrawl.dev" // optional; falls back to FIRECRAWL_API_URL or cloud default
});
```

## When To Use What

* `search`: use when you start with a query and need discovery.
* `scrape`: use when you already have a URL and want page content.
* `interact`: use when the page needs clicks, forms, or other browser actions after a scrape has created a session. For multi-step interactive flows, prefer `interact` over scrape-time `actions`.
* `support/ask`: use when a Firecrawl API call fails or returns unexpected results and you need a diagnosis.
* `support/docs-search`: use when you need to look up Firecrawl documentation.

## Search

### Why use it

Use search to discover relevant pages from a query, then pick URLs to scrape or interact with. You can constrain results to a site with `site:`, for example `site:docs.firecrawl.dev crawl webhooks`.

### Preferred SDK method

`client.search(query, options?)` → `Promise<SearchData>`

### Simple Example

```ts theme={null}
const results = await client.search("site:docs.firecrawl.dev webhook retries");
```

### Complex Example

```ts theme={null}
const results = await client.search("site:docs.firecrawl.dev crawl webhooks", {
  sources: ["web", "news"],
  categories: ["research"],
  limit: 10,
  tbs: "qdr:m",
  location: "San Francisco,California,United States",
  ignoreInvalidURLs: true,
  timeout: 60000,
  scrapeOptions: {
    formats: [
      "markdown",
      "links",
      { type: "json", prompt: "Extract title and key endpoints." }
    ],
    onlyMainContent: true,
    includeTags: ["main", "article"],
    excludeTags: ["nav", "footer"],
    waitFor: 1000
  }
});
```

### Return value

`SearchData` is an object with optional arrays (each entry is either a lightweight result object or a full `Document` when `scrapeOptions` hydrated the hit):

* `web`: web index hits
* `news`: news hits
* `images`: image hits

**Wrong turn to avoid:** `search()` does not return `{ data: [...] }`. Do not access `result.data`. Web results are in `result.web`, news in `result.news`, images in `result.images`.

### Parameters

* `query`
  * Type: string
  * Use when: you need a search query.
  * Notes: use `site:example.com` to limit results to a domain.

* `options` (optional; second argument defaults to `{}`)
  * Type: `Omit<SearchRequest, "query">`

* `options.sources`
  * Type: array of source names or typed source objects
  * Use when: you want to control which sources are searched.
  * Confirmed values:
    * `"web"`: web index results
    * `"news"`: news results
    * `"images"`: image results
    * `{ type: "web" | "news" | "images" }`: typed source object form

* `options.categories`
  * Type: array of category names or typed category objects
  * Use when: you want to filter results by category.
  * Confirmed values:
    * `"github"`: GitHub-focused results
    * `"research"`: research and academic results
    * `"pdf"`: PDF-focused results
    * `{ type: "github" | "research" | "pdf" }`: typed category object form

* `options.limit`
  * Type: number
  * Use when: you want to cap results.

* `options.tbs`
  * Type: string
  * Use when: you need a time-based filter (for example `qdr:d`, `qdr:w`, `sbd:1,qdr:m`).

* `options.location`
  * Type: string
  * Use when: you want localized results.

* `options.ignoreInvalidURLs`
  * Type: boolean
  * Use when: you want to drop URLs that cannot be scraped by other endpoints.

* `options.timeout`
  * Type: number
  * Use when: you need a request timeout in milliseconds.

* `options.scrapeOptions`
  * Type: `ScrapeOptions`
  * Use when: you want to scrape each search result (see Scrape parameters for fields). The SDK runs the same validation as for `scrape` (for example plain string `"json"` in `formats` is rejected).

## Scrape

### Why use it

Use scrape when you already have a URL and want structured content in one or more formats.

### Preferred SDK method

`client.scrape(url, options?)` → `Promise<Document>`

### Simple Example

```ts theme={null}
const doc = await client.scrape("https://docs.firecrawl.dev", {
  formats: ["markdown"]
});
```

### Complex Example

```ts theme={null}
const doc = await client.scrape("https://example.com/pricing", {
  formats: [
    "markdown",
    "links",
    { type: "json", prompt: "Extract plan names and prices." },
    { type: "screenshot", fullPage: true, quality: 80, viewport: { width: 1280, height: 720 } },
    { type: "changeTracking", modes: ["git-diff"], tag: "pricing" },
    { type: "attributes", selectors: [{ selector: "a", attribute: "href" }] }
  ],
  headers: {
    "User-Agent": "FirecrawlDocsBot/1.0"
  },
  onlyMainContent: true,
  waitFor: 1000,
  parsers: [{ type: "pdf", mode: "auto", maxPages: 5 }],
  actions: [
    { type: "click", selector: "#accept" },
    { type: "wait", milliseconds: 750 },
    { type: "scrape" }
  ],
  location: { country: "US", languages: ["en-US"] },
  removeBase64Images: true,
  fastMode: true,
  blockAds: true,
  proxy: "auto",
  maxAge: 86400000,
  minAge: 1,
  storeInCache: true,
  profile: { name: "docs-session", saveChanges: true }
});
```

### Parameters

* `url`
  * Type: string
  * Use when: you want to scrape a specific page.

* `options.formats`
  * Type: array of format strings or format objects
  * Use when: you want multiple output formats.
  * Plain string formats (the `FormatString` union also includes `"json"`, but the SDK rejects `"json"` as a plain string — use a `json` object below):
    * `"markdown"`: markdown content
    * `"html"`: cleaned HTML
    * `"rawHtml"`: raw HTML
    * `"links"`: page links
    * `"images"`: image URLs
    * `"screenshot"`: screenshot output
    * `"summary"`: summary output
    * `"changeTracking"`: change tracking output (for options like `modes`, use `{ type: "changeTracking", modes: [...] }` — `modes` is required on that object in typings)
    * `"attributes"`: attribute extraction (use `{ type: "attributes", selectors: [...] }` when passing selectors)
    * `"branding"`: branding profile output
    * `"audio"`: audio extraction
    * `"video"`: video extraction
  * Object-only format types (at minimum `type` as shown):
    * `{ type: "json", prompt?: string, schema?: JSON schema or Zod schema }`: at least one of `prompt` or `schema` is required (SDK validation).
    * `{ type: "question", question: string }`: question-answer style extraction.
    * `{ type: "highlights", query: string }`: relevant source-text extraction.
    * `{ type: "screenshot", fullPage?, quality?, viewport? }`: same options as the string form but as an object.
    * `{ type: "changeTracking", modes: ("git-diff" | "json")[], schema?, prompt?, tag? }`: `modes` is required.
    * `{ type: "attributes", selectors: Array<{ selector, attribute }> }`
  * Shared object fields where applicable:
    * `schema`: JSON schema or Zod schema for `json`, or for `changeTracking` in `json` mode (Zod is converted to JSON Schema by the SDK).
    * `modes`: for `changeTracking` only: `"git-diff"` and/or `"json"`.
    * `tag`: optional change-tracking branch tag.
    * `fullPage`, `quality`, `viewport`: screenshot options.

* `options.headers`
  * Type: record of string to string
  * Use when: you need custom request headers.

* `options.includeTags`
  * Type: array of strings
  * Use when: you want to include only specific HTML tags.

* `options.excludeTags`
  * Type: array of strings
  * Use when: you want to exclude specific HTML tags.

* `options.onlyMainContent`
  * Type: boolean
  * Use when: you want to strip nav, footer, and other boilerplate.

* `options.timeout`
  * Type: number
  * Use when: you need a timeout in milliseconds.

* `options.waitFor`
  * Type: number
  * Use when: you need to wait for the page to render (milliseconds).

* `options.mobile`
  * Type: boolean
  * Use when: you want a mobile viewport.

* `options.parsers`
  * Type: array of parser names or parser objects
  * Use when: you need file parsing controls (for example PDF parsing).
  * Confirmed values:
    * `"pdf"`: enable PDF parsing
    * `{ type: "pdf", mode?: "fast" | "auto" | "ocr", maxPages?: number }`: PDF parser options

* `options.actions`
  * Type: array of action objects
  * Use when: you need lightweight pre-scrape actions.
  * Confirmed action types:
    * `wait`: `milliseconds` or `selector` required
    * `screenshot`: `fullPage`, `quality`, `viewport` optional
    * `click`: `selector` required
    * `write`: `text` required (click to focus the input first)
    * `press`: `key` required
    * `scroll`: `direction` (`up` or `down`) required, `selector` optional
    * `scrape`: no additional fields
    * `executeJavascript`: `script` required
    * `pdf`: `format` (A0, A1, A2, A3, A4, A5, A6, Letter, Legal, Tabloid, Ledger), `landscape`, `scale` optional

* `options.location`
  * Type: object with `country` and `languages`
  * Use when: you need geo or language-aware scraping.

* `options.skipTlsVerification`
  * Type: boolean
  * Use when: you need to skip TLS verification.

* `options.removeBase64Images`
  * Type: boolean
  * Use when: you want to drop base64 images from markdown output.

* `options.fastMode`
  * Type: boolean
  * Use when: you want faster scrapes with reduced fidelity.

* `options.blockAds`
  * Type: boolean
  * Use when: you want ad and cookie popup blocking.

* `options.proxy`
  * Type: string
  * Use when: you need proxy control.
  * Confirmed values:
    * `"basic"`
    * `"stealth"`
    * `"enhanced"`
    * `"auto"`
    * custom proxy URL string

* `options.maxAge`
  * Type: number
  * Use when: you want cached data up to a maximum age (milliseconds).

* `options.minAge`
  * Type: number
  * Use when: you want cached data only if it is at least this old (milliseconds).

* `options.storeInCache`
  * Type: boolean
  * Use when: you want Firecrawl to cache the result.

* `options.profile`
  * Type: object with `name` and optional `saveChanges`
  * Use when: you want a persistent browser profile shared across scrapes and interactions.

## Interact

### Why use it

Use `interact` for code or natural-language control of the browser session tied to a scrape job (via `metadata.scrapeId`). The SDK requires at least one of `code` or `prompt`. For flows that go beyond quick pre-scrape tweaks, prefer `interact` over scrape-time `actions`.

### Preferred SDK method

`client.interact(jobId, args)` → `Promise<ScrapeExecuteResponse>`

### Simple Example

```ts theme={null}
const doc = await client.scrape("https://example.com", { formats: ["markdown"] });
const jobId = doc.metadata?.scrapeId;
if (!jobId) throw new Error("Missing scrapeId from scrape response");

const result = await client.interact(jobId, {
  prompt: "Click the pricing tab and summarize the plans."
});
```

### Complex Example

```ts theme={null}
const result = await client.interact("<scrapeJobId>", {
  code: "console.log(await page.title());",
  language: "node",
  timeout: 60
});
```

### Parameters

* `jobId`
  * Type: string
  * Use when: you have a scrape job ID from `document.metadata.scrapeId`.

* `args.code`
  * Type: string
  * Use when: you want to run code in the browser session (for example Playwright `page` usage in the `node` runtime).

* `args.prompt`
  * Type: string
  * Use when: you want the browser agent to follow a natural-language instruction.

* At least one of `args.code` or `args.prompt` must be non-empty (SDK throws otherwise).

* `args.language`
  * Type: string
  * Use when: you need a specific runtime.
  * Confirmed values: `"python"`, `"node"`, `"bash"`
  * Default when omitted: `"node"` (set by the SDK on the request body).

* `args.timeout`
  * Type: number
  * Use when: you need an execution timeout in seconds.

### Return value (`interact`)

`ScrapeExecuteResponse` matches `BrowserExecuteResponse`. Confirmed fields include:

* `success`: boolean
* `output`: string (aggregated output when present)
* `stdout`: string
* `result`: string (alias-style field alongside stdout in typings)
* `stderr`: string
* `exitCode`: number
* `killed`: boolean
* `liveViewUrl`: string
* `interactiveLiveViewUrl`: string
* `error`: string

### Stop session

`client.stopInteraction(jobId)` → `Promise<ScrapeBrowserDeleteResponse>`

* `jobId`: scrape job id (same id used for `interact`).
* Response fields in typings include `success`, `sessionDurationMs`, `creditsBilled`, `error`.

## Ask (Agentic Debugging)

### Why use it

Use ask when a Firecrawl API call fails or returns unexpected results. The AI support agent diagnoses the issue, proposes fix parameters, and optionally validates the fix against the live API. Typical latency: 15-30 seconds.

### Preferred SDK method

Not yet available in the Node.js SDK. Use `fetch` directly.

### Simple Example

```ts theme={null}
const response = await fetch("https://api.firecrawl.dev/v2/support/ask", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.FIRECRAWL_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    question: "my scrape returned empty markdown for https://example.com",
  }),
});
const result = await response.json();
console.log(result.answer);
console.log(result.fixParameters);
```

### Complex Example

```ts theme={null}
const response = await fetch("https://api.firecrawl.dev/v2/support/ask", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.FIRECRAWL_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    question: "crawl returned 3 pages but I expected 50",
    rationale: "user is on their third failed crawl attempt today",
    context: { userPlan: "standard", retryCount: 3 },
  }),
});
const result = await response.json();
```

### Agent retry pattern

```ts theme={null}
import { Firecrawl } from "firecrawl";

const client = new Firecrawl({ apiKey: process.env.FIRECRAWL_API_KEY });

const doc = await client.scrape("https://example.com/pricing", {
  formats: ["markdown"],
});

if (!doc.markdown || doc.markdown.length < 100) {
  const diagResponse = await fetch(
    "https://api.firecrawl.dev/v2/support/ask",
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.FIRECRAWL_API_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        question: `scrape returned only ${doc.markdown?.length ?? 0} chars for https://example.com/pricing`,
      }),
    }
  );
  const diagnosis = await diagResponse.json();

  if (diagnosis.fixParameters) {
    const retryDoc = await client.scrape("https://example.com/pricing", {
      formats: ["markdown"],
      ...diagnosis.fixParameters,
    });
  }
}
```

### Parameters

* `question`
  * Type: string (required, 1-8000 chars)
  * Use when: you need to describe the issue.

* `rationale`
  * Type: string (1-2000 chars)
  * Use when: you are an AI agent calling on behalf of a user.

* `context`
  * Type: object (free-form)
  * Use when: you want to pass metadata into the debugging prompt.

## Docs Search

### Why use it

Use docs-search to look up Firecrawl documentation.

### Simple Example

```ts theme={null}
const response = await fetch(
  "https://api.firecrawl.dev/v2/support/docs-search",
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.FIRECRAWL_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      question: "how do I verify webhook signatures?",
    }),
  }
);
const result = await response.json();
console.log(result.answer);
```

### Parameters

* `question`
  * Type: string (required, 1-8000 chars)
  * Use when: you need a docs-grounded answer.

## Notes

* Deprecated client aliases: `scrapeExecute` → `interact`; `stopInteractiveBrowser` and `deleteScrapeBrowser` → `stopInteraction`.
* The default `Firecrawl` export is the v2 client; v1 remains under `client.v1`.
* Zod schemas passed to `formats` (for `json` or `changeTracking`) are converted to JSON Schema by the SDK.
* The package declares **Node.js >= 22** in `engines`.

## Source Of Truth

* `firecrawl/apps/js-sdk/firecrawl/package.json`
* `firecrawl/apps/js-sdk/firecrawl/src/index.ts`
* `firecrawl/apps/js-sdk/firecrawl/src/v2/client.ts`
* `firecrawl/apps/js-sdk/firecrawl/src/v2/types.ts`
* `firecrawl/apps/js-sdk/firecrawl/src/v2/utils/validation.ts`
* `firecrawl/apps/js-sdk/firecrawl/src/v2/methods/search.ts`
* `firecrawl/apps/js-sdk/firecrawl/src/v2/methods/scrape.ts`
* `firecrawl-docs/api-reference/v2-openapi.json`
