Appearance
LLM Extract (JSON Mode)
Updated Feb 2026Extract structured data from any web page using AI-powered JSON extraction. Define a schema or provide a prompt, and Firecrawl returns clean, typed data. This is the JSON format option on the scrape endpoint.
Extract API vs LLM Extract
This page covers JSON mode on /v2/scrape -- extracting structured data from a single URL during scraping. For the dedicated Extract API (/v1/extract) which handles multi-URL extraction and supports the FIRE-1 agent, see Extract API.
Overview
LLM Extract works by converting the page to markdown, then passing it through an LLM with your schema or prompt to produce structured JSON output.
Cost: +4 credits per page (on top of the base 1 credit scrape).
Schema-Based Extraction
With Pydantic (Python)
python
from firecrawl import Firecrawl
from pydantic import BaseModel, Field
from typing import List, Optional
firecrawl = Firecrawl(api_key="fc-YOUR-API-KEY")
class CompanyInfo(BaseModel):
company_mission: str = Field(description="The company's mission statement")
supports_sso: bool = Field(description="Whether the company offers SSO")
is_open_source: bool = Field(description="Whether the product is open source")
pricing_tiers: List[str] = Field(description="Names of pricing tiers")
result = firecrawl.scrape(
"https://firecrawl.dev",
formats=[{
"type": "json",
"schema": CompanyInfo.model_json_schema()
}],
only_main_content=False,
timeout=120000
)
print(result['json'])
# {"company_mission": "...", "supports_sso": true, "is_open_source": true, "pricing_tiers": ["Free", "Starter", "Growth"]}With Zod (Node.js)
javascript
import Firecrawl from '@mendable/firecrawl-js';
import { z } from 'zod';
import { zodToJsonSchema } from 'zod-to-json-schema';
const firecrawl = new Firecrawl({ apiKey: "fc-YOUR-API-KEY" });
const CompanyInfo = z.object({
company_mission: z.string().describe("The company's mission statement"),
supports_sso: z.boolean().describe("Whether the company offers SSO"),
is_open_source: z.boolean().describe("Whether the product is open source"),
pricing_tiers: z.array(z.string()).describe("Names of pricing tiers"),
});
const result = await firecrawl.scrape("https://firecrawl.dev", {
formats: [{
type: "json",
schema: zodToJsonSchema(CompanyInfo)
}],
onlyMainContent: false,
timeout: 120000
});
console.log(result.json);With Raw JSON Schema (cURL)
bash
curl -X POST https://api.firecrawl.dev/v2/scrape \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer fc-YOUR-API-KEY' \
-d '{
"url": "https://firecrawl.dev",
"formats": [{
"type": "json",
"schema": {
"type": "object",
"properties": {
"company_mission": {"type": "string"},
"supports_sso": {"type": "boolean"},
"is_open_source": {"type": "boolean"},
"pricing_tiers": {
"type": "array",
"items": {"type": "string"}
}
},
"required": ["company_mission", "supports_sso", "is_open_source"]
}
}],
"onlyMainContent": false,
"timeout": 120000
}'Prompt-Based Extraction (No Schema)
When you do not need a rigid structure, use a prompt to guide the LLM:
python
result = firecrawl.scrape(
"https://firecrawl.dev",
formats=[{
"type": "json",
"prompt": "Extract the company mission, key features, and pricing information from this page."
}],
only_main_content=False
)
print(result['json'])
# LLM determines the output structure based on your promptjavascript
const result = await firecrawl.scrape("https://firecrawl.dev", {
formats: [{
type: "json",
prompt: "Extract the company mission, key features, and pricing information from this page."
}],
onlyMainContent: false
});bash
curl -X POST https://api.firecrawl.dev/v2/scrape \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer fc-YOUR-API-KEY' \
-d '{
"url": "https://firecrawl.dev",
"formats": [{"type": "json", "prompt": "Extract the company mission, key features, and pricing information."}],
"onlyMainContent": false
}'Schema + Prompt Combined
Use both for maximum control -- the schema defines the structure, and the prompt guides the extraction:
python
result = firecrawl.scrape(
"https://firecrawl.dev",
formats=[{
"type": "json",
"schema": CompanyInfo.model_json_schema(),
"prompt": "Focus on the main product page content. Ignore blog posts and documentation links."
}],
only_main_content=False
)Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
type | string | Yes | Must be "json" |
schema | object | No* | JSON Schema defining output structure |
prompt | string | No* | Natural language extraction guidance |
only_main_content | boolean | No | Filter to main content area (default: true) |
timeout | number | No | Request timeout in milliseconds |
*At least one of schema or prompt is required.
Response Format
json
{
"success": true,
"data": {
"json": {
"company_mission": "Make the web accessible to AI",
"supports_sso": true,
"is_open_source": true,
"pricing_tiers": ["Free", "Starter", "Growth", "Enterprise"]
},
"metadata": {
"title": "Firecrawl - Turn websites into LLM-ready data",
"description": "...",
"ogTitle": "...",
"sourceURL": "https://firecrawl.dev",
"statusCode": 200
}
}
}Important Limitations
HTML Attributes Are Stripped
JSON extraction works on the markdown conversion of the page, which only preserves visible text content. HTML attributes like data-id, class, href, and custom attributes are stripped during conversion and are not accessible to the LLM.
Workarounds:
- Use
rawHtmlformat -- request bothjsonandrawHtml, then parse attributes client-side - Use
executeJavascriptaction -- inject attribute values into visible text before extraction
python
# Workaround: Inject data attributes into visible text
result = firecrawl.scrape(
"https://example.com/products",
formats=[{
"type": "json",
"schema": {...}
}],
actions=[{
"type": "executeJavascript",
"code": """
document.querySelectorAll('[data-product-id]').forEach(el => {
el.textContent += ` [ID: ${el.dataset.productId}]`;
});
"""
}]
)Token Limits
Very long pages may exceed the LLM's context window. Strategies:
- Set
only_main_content: trueto reduce content - Use specific, focused schemas instead of extracting everything
- Consider Extract API for multi-page extraction tasks
Common Patterns
E-Commerce Product Data
python
class Product(BaseModel):
name: str
price: str
description: str
rating: Optional[float]
reviews_count: Optional[int]
in_stock: bool
categories: List[str]
result = firecrawl.scrape(
"https://store.example.com/product/widget-pro",
formats=[{"type": "json", "schema": Product.model_json_schema()}]
)Contact Information
python
class ContactInfo(BaseModel):
company_name: str
email: Optional[str]
phone: Optional[str]
address: Optional[str]
social_links: List[str]
result = firecrawl.scrape(
"https://example.com/contact",
formats=[{"type": "json", "schema": ContactInfo.model_json_schema()}],
only_main_content=False # Contact info often in footer
)Job Listings
python
class JobListing(BaseModel):
title: str
department: str
location: str
type: str # full-time, part-time, contract
description: str
class JobListings(BaseModel):
jobs: List[JobListing]
result = firecrawl.scrape(
"https://example.com/careers",
formats=[{"type": "json", "schema": JobListings.model_json_schema()}]
)Cost
| Operation | Credits |
|---|---|
| Base scrape | 1 |
| JSON extraction add-on | +4 |
| Total per page | 5 |
JSON extraction in batch scrape applies the +4 cost per URL.
Related Pages
- Scrape -- All scrape formats including JSON mode
- Extract API -- Multi-URL extraction with FIRE-1 agent support
- FIRE-1 -- AI agent for complex browser-based extraction
- Batch Scrape -- Bulk extraction with schemas
- AI Models -- Model selection for extraction tasks
Next: AI Models -->