# Page monitoring (/features/monitoring-page)

<!-- agent-signals: reading_time_min: 3 · est_tokens: 1462 · updated: 2026-07-30 -->
Related: [Search](/features/search.md), [Search Highlights](/features/search-highlights.md), [Research Index](/features/research.md), [Scrape](/features/scrape.md), [Faster Scraping](/features/fast-scraping.md), [Batch Scrape](/features/batch-scrape.md)

Page monitoring watches URLs you already know about. Each check scrapes every URL in the target, diffs it against the last retained snapshot, and reports whether the page is `same`, `changed`, `new`, `removed`, or `error`. It's the right choice for pricing pages, changelogs, docs pages, job posts, status pages, or any known URL where a small change matters.

This page covers the `scrape` target. Scheduling, goals and judging, change tracking, notifications, and pricing are shared across all monitor types. See the [Monitoring overview](/features/monitoring).

## Create a page monitor [#create-a-page-monitor]

Create a monitor with a `scrape` target that lists one or more explicit URLs:

<CodeGroup>
  <CodeBlockTabs defaultValue="Python" groupId="curl+node+python">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="Python">
        Python
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="Node">
        Node
      </CodeBlockTabsTrigger>

      <CodeBlockTabsTrigger value="cURL">
        cURL
      </CodeBlockTabsTrigger>
    </CodeBlockTabsList>

    <CodeBlockTab value="Python">
      ```python  
      from firecrawl import Firecrawl

      firecrawl = Firecrawl(
        # Monitor endpoints require an API key:
        api_key="fc-YOUR-API-KEY",
      )

      monitor = firecrawl.create_monitor(
          name="Hacker News AI monitor",
          schedule={"text": "every 30 minutes", "timezone": "UTC"},
          goal=(
              "Alert when a new Hacker News story related to AI enters the top 10. "
              "Ignore changes to stories that are not about AI. "
              "Do not alert on changes outside the top 10."
          ),
          targets=[
              {
                  "type": "scrape",
                  "urls": ["https://news.ycombinator.com"],
              }
          ],
          notification={
              "email": {
                  "enabled": True,
                  "recipients": ["alerts@example.com"],
                  "includeDiffs": True,
              }
          },
      )

      print(monitor.id)
      ```
    </CodeBlockTab>

    <CodeBlockTab value="Node">
      ```js  
      import Firecrawl from "@mendable/firecrawl-js";

      const firecrawl = new Firecrawl({
        // Monitor endpoints require an API key:
        apiKey: "fc-YOUR-API-KEY",
      });

      const monitor = await firecrawl.createMonitor({
        name: "Hacker News AI monitor",
        schedule: { text: "every 30 minutes", timezone: "UTC" },
        goal:
          "Alert when a new Hacker News story related to AI enters the top 10. Ignore changes to stories that are not about AI. Do not alert on changes outside the top 10.",
        notification: {
          email: {
            enabled: true,
            recipients: ["alerts@example.com"],
            includeDiffs: true,
          },
        },
        targets: [
          {
            type: "scrape",
            urls: ["https://news.ycombinator.com"],
          },
        ],
      });

      console.log(monitor.id);
      ```
    </CodeBlockTab>

    <CodeBlockTab value="cURL">
      ```bash  
      curl -s -X POST "https://api.firecrawl.dev/v2/monitor" \
        -H "Authorization: Bearer $FIRECRAWL_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "name": "Hacker News AI monitor",
          "schedule": {
            "text": "every 30 minutes",
            "timezone": "UTC"
          },
          "goal": "Alert when a new Hacker News story related to AI enters the top 10. Ignore changes to stories that are not about AI. Do not alert on changes outside the top 10.",
          "notification": {
            "email": {
              "enabled": true,
              "recipients": ["alerts@example.com"],
              "includeDiffs": true
            }
          },
          "targets": [
            {
              "type": "scrape",
              "urls": ["https://news.ycombinator.com"]
            }
          ]
        }'
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

You can also create monitors from the Firecrawl CLI:

```bash title="CLI"
firecrawl monitor create --name "Hacker News AI" \
  --schedule "every 30 minutes" \
  --goal "Alert when a new Hacker News story related to AI enters the top 10. Ignore changes to stories that are not about AI. Do not alert on changes outside the top 10." \
  --page https://news.ycombinator.com
```

## Scrape target [#scrape-target]

A `scrape` target requires `type` and a `urls` array with at least one URL. Scrape options are passed through to the underlying scrape jobs. Monitor-triggered scrapes default `maxAge` to `0`, so each check performs a fresh scrape unless you explicitly set a different `maxAge`.

```json title="Scrape target"
{
  "type": "scrape",
  "urls": ["https://example.com/pricing"],
  "scrapeOptions": {
    "formats": ["markdown"],
    "maxAge": 0
  }
}
```

## Detecting field-level changes [#detecting-field-level-changes]

By default a page monitor diffs the page's markdown. To alert only when a **specific field** changes, such as a price, a headline, an in-stock flag, or the items in a list, add a `changeTracking` format to the target's `scrapeOptions`. See [Change tracking](/features/monitoring#change-tracking) for JSON mode and mixed mode.

## Shared configuration [#shared-configuration]

* [Schedules](/features/monitoring#schedules): cron or natural-language cadence, minimum 5 minutes.
* [Goals and judging](/features/monitoring#goals-and-judging): alert only on meaningful changes.
* [Notifications](/features/monitoring#notifications): webhook and email delivery.
* [Check results](/features/monitoring#check-results): inspect each check and its per-page diffs.
* [Pricing](/features/monitoring#pricing): 1 credit per URL per check, plus optional judging.
