Appearance
Change Tracking
New FeatureDetect and diff website changes over time. Compares current page content against previous scrapes with persistent snapshots.
Overview
Add changeTracking to the formats array in any /scrape, /crawl, or /batch/scrape call. Firecrawl stores snapshots persistently (they never expire) and compares automatically.
Change Status Values
| Status | Meaning |
|---|---|
new | First time this URL has been scraped |
same | Content unchanged since last scrape |
changed | Content modified (diff available) |
removed | Page no longer accessible |
Basic Usage
python
from firecrawl import Firecrawl
firecrawl = Firecrawl(api_key="fc-YOUR-API-KEY")
result = firecrawl.scrape(
"https://example.com/pricing",
formats=["markdown", "changeTracking"]
)
print(result.changeTracking)
# Returns: previousScrapeAt, changeStatus, visibilityRequired
markdown format must always be included alongside changeTracking.
Git-Diff Mode
Get a unified diff showing exactly what changed:
python
result = firecrawl.scrape(
"https://example.com/pricing",
formats=["markdown", {"type": "changeTracking", "modes": ["git-diff"]}]
)
if result.changeTracking.changeStatus == "changed":
print(result.changeTracking.diff.text)
# Unified diff output with +/- linesThe diff response includes both raw text diff and structured JSON with add, del, and normal change types.
JSON Mode (Field-Level Comparison)
Compare specific fields between scrapes using a schema:
python
result = firecrawl.scrape(
"https://example.com/product/widget",
formats=["markdown", {
"type": "changeTracking",
"modes": ["json"],
"schema": {
"type": "object",
"properties": {
"price": {"type": "string"},
"availability": {"type": "string"},
"rating": {"type": "string"}
}
}
}]
)
# Response shows previous vs current for each field:
# {"price": {"previous": "$19.99", "current": "$24.99"}, ...}Combined Modes
Use both git-diff and JSON at the same time:
python
result = firecrawl.scrape(
"https://example.com/pricing",
formats=["markdown", {
"type": "changeTracking",
"modes": ["git-diff", "json"],
"schema": {
"type": "object",
"properties": {
"plan_name": {"type": "string"},
"monthly_price": {"type": "string"},
"features": {"type": "array", "items": {"type": "string"}}
}
}
}]
)Tags (Separate Tracking Histories)
Track the same URL at different frequencies with isolated histories:
python
# Hourly monitoring (separate history)
result = firecrawl.scrape(
"https://example.com/pricing",
formats=["markdown", {"type": "changeTracking", "tag": "hourly"}]
)
# Daily monitoring (separate history)
result = firecrawl.scrape(
"https://example.com/pricing",
formats=["markdown", {"type": "changeTracking", "tag": "daily"}]
)Crawl + Change Tracking
Monitor an entire site for changes:
python
result = firecrawl.crawl(
"https://example.com",
limit=50,
scrape_options={"formats": ["markdown", "changeTracking"]}
)
for page in result.data:
status = page.changeTracking.changeStatus
url = page.metadata.url
if status == "changed":
print(f"CHANGED: {url}")
elif status == "new":
print(f"NEW PAGE: {url}")
elif status == "removed":
print(f"REMOVED: {url}")Batch Scrape + Change Tracking
python
job = firecrawl.batch_scrape(
[
"https://example.com/pricing",
"https://example.com/features",
"https://example.com/about",
],
formats=["markdown", {"type": "changeTracking", "modes": ["git-diff"]}],
poll_interval=2,
wait_timeout=120,
)Configuration Reference
| Parameter | Type | Default | Description |
|---|---|---|---|
type | string | required | Must be "changeTracking" |
modes | string[] | [] | "git-diff", "json", or both |
schema | object | none | JSON Schema for field-level comparison |
prompt | string | none | Custom LLM prompt (with json mode) |
tag | string | null | Separate tracking history identifier |
Important Notes
markdownformat must always be included alongsidechangeTracking- Scoped to your team — first scrape always returns
"new" - URL matching is exact: source URL + team ID + markdown format + tag
- Cache is bypassed —
maxAgeis ignored when using changeTracking - Algorithm is resistant to whitespace and content order changes
- Iframe source URLs are ignored (handles captcha randomization)
- Snapshots never expire — stored persistently
Cost
- Basic + git-diff mode: No extra cost (just the normal scrape credit)
- JSON mode: +5 credits per page
Next: MCP Server →