# 监控 (/zh/features/monitoring)

<!-- agent-signals: reading_time_min: 13 · est_tokens: 8444 · updated: 2026-07-30 -->
Related: [搜索](/zh/features/search.md), [搜索高亮](/zh/features/search-highlights.md), [研究索引](/zh/features/research.md), [抓取](/zh/features/scrape.md), [更快的抓取](/zh/features/fast-scraping.md), [批量抓取](/zh/features/batch-scrape.md)

Firecrawl 监控会定期执行检查，并在有内容发生变化或出现新内容时通知你或你的代理。使用 `/monitor` 可以[监视已知页面](/zh/features/monitoring-page)、[按计划爬取网站](/zh/features/monitoring-website)，或[持续运行网页搜索](/zh/features/monitoring-web-scale)，以查找与某个目标匹配的新结果。

所有监控类型都遵循相同的工作流：选择一个或多个目标，设置计划，添加一个可选的自然语言目标描述，并在有重要变化时接收 Webhook、电子邮件或 Slack 通知。本页介绍通用配置。若要查看特定目标的设置和示例，请前往 [Page](/zh/features/monitoring-page)、[Website](/zh/features/monitoring-website) 或 [全网页规模](/zh/features/monitoring-web-scale) 监控页面。

<CardGroup cols="3">
  <Card title="页面监控" icon="<svg xmlns=&#x22;http://www.w3.org/2000/svg&#x22; viewBox=&#x22;0 0 24 24&#x22; fill=&#x22;none&#x22;><path d=&#x22;M8 7L16 7&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/><path d=&#x22;M8 11L12 11&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/><path d=&#x22;M13 21.5V21C13 18.1716 13 16.7574 13.8787 15.8787C14.7574 15 16.1716 15 19 15H19.5M20 13.3431V10C20 6.22876 20 4.34315 18.8284 3.17157C17.6569 2 15.7712 2 12 2C8.22877 2 6.34315 2 5.17157 3.17157C4 4.34314 4 6.22876 4 10L4 14.5442C4 17.7892 4 19.4117 4.88607 20.5107C5.06508 20.7327 5.26731 20.9349 5.48933 21.1139C6.58831 22 8.21082 22 11.4558 22C12.1614 22 12.5141 22 12.8372 21.886C12.9044 21.8623 12.9702 21.835 13.0345 21.8043C13.3436 21.6564 13.593 21.407 14.0919 20.9081L18.8284 16.1716C19.4065 15.5935 19.6955 15.3045 19.8478 14.9369C20 14.5694 20 14.1606 20 13.3431Z&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/></svg>" href="/zh/features/monitoring-page">
    监视一个或多个已知 URL，将每次抓取与上一次快照进行 diff，并在页面发生有意义的变化时触发告警。
  </Card>

  <Card title="网站监控" icon="<svg xmlns=&#x22;http://www.w3.org/2000/svg&#x22; viewBox=&#x22;0 0 24 24&#x22; fill=&#x22;none&#x22;><path d=&#x22;M8 7L16 7&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/><path d=&#x22;M8 11L12 11&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/><path d=&#x22;M13 21.5V21C13 18.1716 13 16.7574 13.8787 15.8787C14.7574 15 16.1716 15 19 15H19.5M20 13.3431V10C20 6.22876 20 4.34315 18.8284 3.17157C17.6569 2 15.7712 2 12 2C8.22877 2 6.34315 2 5.17157 3.17157C4 4.34314 4 6.22876 4 10L4 14.5442C4 17.7892 4 19.4117 4.88607 20.5107C5.06508 20.7327 5.26731 20.9349 5.48933 21.1139C6.58831 22 8.21082 22 11.4558 22C12.1614 22 12.5141 22 12.8372 21.886C12.9044 21.8623 12.9702 21.835 13.0345 21.8043C13.3436 21.6564 13.593 21.407 14.0919 20.9081L18.8284 16.1716C19.4065 15.5935 19.6955 15.3045 19.8478 14.9369C20 14.5694 20 14.1606 20 13.3431Z&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/></svg>" href="/zh/features/monitoring-website">
    按计划爬取网站，检测新增、变更或移除的页面，并通知你的 Webhook 或收件箱。
  </Card>

  <Card title="全网页规模监控" icon="<svg xmlns=&#x22;http://www.w3.org/2000/svg&#x22; viewBox=&#x22;0 0 24 24&#x22; fill=&#x22;none&#x22;><path d=&#x22;M12.5 19L12.5 22&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/><path d=&#x22;M10.5 22H14.5&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/><circle cx=&#x22;7&#x22; cy=&#x22;7&#x22; r=&#x22;7&#x22; transform=&#x22;matrix(-1 0 0 1 20.5 2)&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/><path d=&#x22;M8.5 4C9.15431 4.0385 9.49236 4.35899 10.0735 4.97301C11.1231 6.08206 12.1727 6.1746 12.8724 5.80492C13.922 5.2504 13.04 4.35221 14.2719 3.86409C15.0748 3.54595 15.1868 2.68026 14.7399 2&#x22; stroke=&#x22;currentColor&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/><path d=&#x22;M20 10C18.5 10 18.2338 11.2468 17 11C14.5 10.5 13.7916 11.0589 13.7916 12.2511C13.7916 13.4432 13.7916 13.4432 13.2717 14.3373C12.9335 14.9189 12.8153 15.5004 13.4894 16&#x22; stroke=&#x22;currentColor&#x22; stroke-linejoin=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/><path d=&#x22;M6.5 2C4.64864 3.79995 3.5 6.3082 3.5 9.08251C3.5 14.5598 7.97715 19 13.5 19C16.2255 19 18.6962 17.9187 20.5 16.165&#x22; stroke=&#x22;currentColor&#x22; stroke-linecap=&#x22;round&#x22; stroke-width=&#x22;1.5&#x22;/></svg>" href="/zh/features/monitoring-web-scale">
    定期运行网页搜索，并在出现与你的目标匹配的新结果时触发告警。
  </Card>
</CardGroup>

每次检查都会将页面级结果记录为 `same`、`new`、`changed`、`removed` 或 `error`。你可以在每个受监控页面处理完成时接收 Webhook，也可以在每次检查完成后接收一个 Webhook；还可以在发生更改或错误时接收电子邮件摘要、向某个频道发送的 Slack 通知，或组合使用这些通知方式。

<div id="targets">
  ## 目标 [#目标]
</div>

每个监控都有一个或多个**目标**。目标类型决定了每次检查会执行什么：

| 目标       | 监控内容        | 设置方式                                         |
| -------- | ----------- | -------------------------------------------- |
| `scrape` | 你指定的已知 URL  | [页面监控](/zh/features/monitoring-page)         |
| `crawl`  | 通过爬取发现的每个页面 | [网站监控](/zh/features/monitoring-website)      |
| `search` | 整个网页中的新结果   | [全网页规模监控](/zh/features/monitoring-web-scale) |

每个监控支持 1–50 个目标，并且你可以在同一个监控中混合使用不同的目标类型。`retentionDays` 的默认值为 `30`，最高可设置为 `365`。

每次创建调用都会返回新创建的监控，其中包含规范化后的 cron、计算得出的 `nextRunAt` 和 `estimatedCreditsPerMonth`。启用判定后，`estimatedCreditsPerMonth` 是一个上限估算值，因为判定额度只会对实际发生变化且被判定的页面计费：

```json title="Response"
{
  "success": true,
  "data": {
    "id": "019df960-06e7-7383-9d89-82c0113dc31a",
    "name": "Hacker News AI monitor",
    "status": "active",
    "schedule": {
      "cron": "*/30 * * * *",
      "timezone": "UTC"
    },
    "nextRunAt": "2026-05-17T16:00:00.000Z",
    "lastRunAt": null,
    "currentCheckId": null,
    "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.",
    "judgeEnabled": true,
    "targets": [
      {
        "id": "019df960-09bb-7c11-8001-1f12f50ab1c2",
        "type": "scrape",
        "urls": ["https://news.ycombinator.com"]
      }
    ],
    "webhook": null,
    "notification": {
      "email": {
        "enabled": true,
        "recipients": ["alerts@example.com"],
        "includeDiffs": true
      }
    },
    "retentionDays": 30,
    "estimatedCreditsPerMonth": 2880,
    "lastCheckSummary": null,
    "createdAt": "2026-05-17T15:30:00.000Z",
    "updatedAt": "2026-05-17T15:30:00.000Z"
  }
}
```

<div id="goals-and-judging">
  ## 目标与判定 [#目标与判定]
</div>

如果你只想在发生有意义的变化时收到告警，请添加一个通俗易懂的 `goal`。如果设置了 `goal` 但省略了 `judgeEnabled`，Firecrawl 会自动启用判定。判定会在已发生变化的页面上运行，并返回一个 `judgment`，其中包含 `meaningful`、`confidence`、`reason` 和 `meaningfulChanges`。

目标如何应用取决于目标：[page](/zh/features/monitoring-page) 和 [website](/zh/features/monitoring-website) 监控会对已发生变化的页面进行判定，而 [entire web-scale monitors](/zh/features/monitoring-web-scale#judging) 会对每个新的搜索结果进行判定。

如果你想先保存目标、暂时不对变化进行判定，请使用 `judgeEnabled: false`。只有当监控同时设置了 `judgeEnabled` 且 `goal` 非空时，判定器才会运行。

<Note>
  对于 `search` 目标 (全网页规模监控) ，除非你设置了 `judgeEnabled: false`，否则 `goal` 为必填。对于 `scrape` 和 `crawl` 目标，则为可选。
</Note>

<Note>
  每次检查都会对底层抓取或爬取照常计费。如果启用了判定，判定器还会为其验证的每个已发生变化的页面额外收取 1 个额度。没有已发生变化页面的检查不会消耗判定额度。
</Note>

好的目标应简短且明确：说明什么情况应触发告警，重申任何范围限制，例如前 N 项、价格、角色类型、公司、地区、主题、状态或实体，并且仅在排除条件本身属于目标意图时才写入。如果目标范围较宽泛，就保持宽泛；例如，"任何变化" 不应再加入会掩盖变化的噪声过滤条件。

例如，一个具有以下目标的监控：

```text
当与 AI 相关的新 Hacker News 故事进入前 10 时发出告警。忽略与 AI 无关的故事的变动。不对前 10 以外的变动发出告警。
```

当匹配的故事进入监控范围时，可能会生成如下这样的 `monitor.page` Webhook：

```json title="monitor.page"
{
  "success": true,
  "type": "monitor.page",
  "id": "019df960-5f2a-75fb-a98b-bd2d32ca67d4",
  "webhookId": "f1e2d3c4-0000-0000-0000-000000000000",
  "data": [
    {
      "monitorId": "019df960-06e7-7383-9d89-82c0113dc31a",
      "checkId": "019df960-5f2a-75fb-a98b-bd2d32ca67d4",
      "url": "https://news.ycombinator.com",
      "status": "changed",
      "previousScrapeId": "019df94f-82c3-7e41-81f0-00c72b2d9c52",
      "currentScrapeId": "019df960-73ee-7ac2-97a9-fb0e442c21f1",
      "error": null,
      "isMeaningful": true,
      "judgment": {
        "meaningful": true,
        "confidence": "high",
        "reason": "A new AI-related story entered the Hacker News top 10.",
        "meaningfulChanges": [
          {
            "type": "added",
            "after": "4. Show HN: Open-source AI coding assistant",
            "reason": "This is a new AI-related story inside the top 10."
          }
        ]
      },
      "diff": {
        "text": "--- previous\n+++ current\n@@ -1,5 +1,6 @@\n # Hacker News\n 1. Database internals for beginners\n 2. A new approach to CSS\n 3. Building reliable queues\n+4. Show HN: Open-source AI coding assistant\n"
      }
    }
  ],
  "metadata": {
    "environment": "production"
  }
}
```

<div id="schedules">
  ## 调度计划 [#调度计划]
</div>

调度计划可以使用 cron 表达式或简单的自然语言文本来设置。

<CodeGroup>
  <CodeBlockTabs defaultValue="Cron" groupId="cron+text">
    <CodeBlockTabsList>
      <CodeBlockTabsTrigger value="Cron">
        Cron
      </CodeBlockTabsTrigger>

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

    <CodeBlockTab value="Cron">
      ```json  
      {
        "schedule": {
          "cron": "*/30 * * * *",
          "timezone": "UTC"
        }
      }
      ```
    </CodeBlockTab>

    <CodeBlockTab value="Text">
      ```json  
      {
        "schedule": {
          "text": "every 30 minutes",
          "timezone": "UTC"
        }
      }
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

支持的自然语言示例：

* `every 30 minutes`
* `every 15 minutes starting at :07`
* `hourly`
* `every 2 hours`
* `daily`
* `daily at 9:00`
* `daily at 9am`
* `daily at 5:30 PM`
* `weekly`

最短间隔为 5 分钟。API 响应始终返回规范化后的 cron 表达式。对于文本调度计划，`timezone` 用于控制像 `daily at 9am` 这类短语何时运行。文本调度计划在转换为 cron 之前，会先按监控 ID 错开分布，因此多个监控不会在同一时刻同时运行。

<div id="change-tracking">
  ## 变更追踪 [#变更追踪]
</div>

[页面](/zh/features/monitoring-page) 和 [网站](/zh/features/monitoring-website) 监控默认会比较每个页面的 markdown 差异，并报告 `same`、`changed`、`new`、`removed` 或 `error`。如果你想检测**特定结构化字段** (如价格、标题、库存状态标记、列表中的条目等) 的变化，请在目标的 `scrapeOptions` 中添加 `changeTracking` 格式，并设置 `modes: ["json"]`，以启用 JSON 模式的变更追踪。

<Note>
  变更追踪适用于 `scrape` 和 `crawl` 目标。面向整个网页规模的 (`search`) 监控会针对新结果触发告警，而不是比较已知页面的差异。请参见 [Statuses and dedup](/zh/features/monitoring-web-scale#statuses-and-dedup)。
</Note>

<div id="markdown-mode-default">
  ### Markdown 模式 (默认) [#markdown-模式-默认]
</div>

当 `scrapeOptions.formats` 仅为 `["markdown"]` 时，检查 响应中的每个已变更页面都会附带统一文本 diff，以及一个 [parseDiff](https://github.com/sergeyt/parse-diff) 风格的 AST：

```json title="Markdown-mode diff"
{
  "diff": {
    "text": "--- previous\n+++ current\n@@ -1,3 +1,3 @@\n # Pricing\n-Starter — $19/mo\n+Starter — $24/mo\n",
    "json": {
      "files": [
        {
          "from": "previous",
          "to": "current",
          "chunks": [
            {
              "content": "@@ -1,3 +1,3 @@",
              "changes": []
            }
          ]
        }
      ]
    }
  }
}
```

<div id="json-mode">
  ### JSON 模式 [#json-模式]
</div>

传入 `changeTracking` 格式并设置 `modes: ["json"]`，同时提供一个 JSON schema (或用于描述你关注字段的 `prompt`) 。Firecrawl 会在每次检查时提取该 JSON，并输出一个**按字段区分的差异**，以字段路径作为键；此外还会附带一个包含当前完整提取结果的 `snapshot.json`，这样消费方就无需重新获取底层 抓取 结果。

<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
      from pydantic import BaseModel
      from typing import List

      firecrawl = Firecrawl(api_key="fc-YOUR-API-KEY")


      class Plan(BaseModel):
          name: str
          price: str
          features: List[str]


      class Pricing(BaseModel):
          plans: List[Plan]


      monitor = firecrawl.create_monitor(
          name="Pricing monitor",
          schedule={"text": "hourly", "timezone": "UTC"},
          goal="Notify me when a pricing tier, price, or headline feature changes",
          targets=[
              {
                  "type": "scrape",
                  "urls": ["https://example.com/pricing"],
                  "scrapeOptions": {
                      "formats": [
                          {
                              "type": "changeTracking",
                              "modes": ["json"],
                              "prompt": "Extract pricing tiers and headline features for each plan.",
                              "schema": Pricing.model_json_schema(),
                          }
                      ]
                  },
              }
          ],
          notification={
              "email": {
                  "enabled": True,
                  "recipients": ["alerts@example.com"],
                  "includeDiffs": True,
              }
          },
      )

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

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

      const firecrawl = new Firecrawl({ apiKey: "fc-YOUR-API-KEY" });

      const pricingSchema = z.object({
        plans: z.array(
          z.object({
            name: z.string(),
            price: z.string(),
            features: z.array(z.string()),
          }),
        ),
      });

      const monitor = await firecrawl.createMonitor({
        name: "Pricing monitor",
        schedule: { text: "hourly", timezone: "UTC" },
        goal: "Notify me when a pricing tier, price, or headline feature changes",
        notification: {
          email: {
            enabled: true,
            recipients: ["alerts@example.com"],
            includeDiffs: true,
          },
        },
        targets: [
          {
            type: "scrape",
            urls: ["https://example.com/pricing"],
            scrapeOptions: {
              formats: [
                {
                  type: "changeTracking",
                  modes: ["json"],
                  prompt: "Extract pricing tiers and headline features for each plan.",
                  schema: pricingSchema,
                },
              ],
            },
          },
        ],
      });

      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": "Pricing monitor",
          "schedule": {
            "text": "hourly",
            "timezone": "UTC"
          },
          "goal": "Notify me when a pricing tier, price, or headline feature changes",
          "notification": {
            "email": {
              "enabled": true,
              "recipients": ["alerts@example.com"],
              "includeDiffs": true
            }
          },
          "targets": [
            {
              "type": "scrape",
              "urls": ["https://example.com/pricing"],
              "scrapeOptions": {
                "formats": [
                  {
                    "type": "changeTracking",
                    "modes": ["json"],
                    "prompt": "Extract pricing tiers and headline features for each plan.",
                    "schema": {
                      "type": "object",
                      "properties": {
                        "plans": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "name": { "type": "string" },
                              "price": { "type": "string" },
                              "features": {
                                "type": "array",
                                "items": { "type": "string" }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                ]
              }
            }
          ]
        }'
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

diff 载荷使用提取结果中的 JSON 路径作为键。每个值都是一个 `{previous, current}` 对：

```json title="JSON-mode diff"
{
  "diff": {
    "json": {
      "plans[0].price": {
        "previous": "$19/mo",
        "current": "$24/mo"
      },
      "plans[1].features[2]": {
        "previous": "10 GB storage",
        "current": "25 GB storage"
      }
    }
  },
  "snapshot": {
    "json": {
      "plans": [
        {
          "name": "Starter",
          "price": "$24/mo",
          "features": ["Up to 3 users", "Basic analytics", "Email support"]
        },
        {
          "name": "Pro",
          "price": "$49/mo",
          "features": ["Unlimited users", "Advanced analytics", "25 GB storage"]
        }
      ]
    }
  }
}
```

<Note>
  即使被跟踪的字段都没有变化，但周围的 markdown 发生了变化，JSON 模式监控仍会报告 `same`，除非你同时启用 git-diff (请参见下方的混合模式) 。该 diff 只关注 schema 中定义的字段。
</Note>

<div id="mixed-mode-json-git-diff">
  ### 混合模式 (JSON + git-diff) [#混合模式-json--git-diff]
</div>

如果你同时需要结构化的逐字段差异 **以及** 原始 markdown 统一 diff，请同时传入这两种模式：

```json title="Mixed target (JSON + git-diff)"
{
  "type": "scrape",
  "urls": ["https://example.com/pricing"],
  "scrapeOptions": {
    "formats": [
      {
        "type": "changeTracking",
        "modes": ["json", "git-diff"],
        "prompt": "Extract pricing tiers and headline features for each plan.",
        "schema": {
          "type": "object",
          "properties": {
            "plans": {
              "type": "array",
              "items": {
                "type": "object",
                "properties": {
                  "name": { "type": "string" },
                  "price": { "type": "string" }
                }
              }
            }
          }
        }
      }
    ]
  }
}
```

随后，检查 响应会同时包含 `diff.text` (markdown sidecar) 和 `diff.json` (逐字段差异) ，以及提取得到的 `snapshot.json`：

```json title="Mixed-mode diff (JSON + git-diff)"
{
  "diff": {
    "text": "--- previous\n+++ current\n@@ -1,3 +1,3 @@\n # Pricing\n-Starter — $19/mo\n+Starter — $24/mo\n",
    "json": {
      "plans[0].price": {
        "previous": "$19/mo",
        "current": "$24/mo"
      }
    }
  },
  "snapshot": {
    "json": {
      "plans": [
        { "name": "Starter", "price": "$24/mo" },
        { "name": "Pro", "price": "$49/mo" }
      ]
    }
  }
}
```

混合模式页面会在**任一**结果形式发生变化时报告 `changed`。

<div id="notifications">
  ## 通知 [#通知]
</div>

<div id="webhooks">
  ### Webhooks [#webhooks]
</div>

当监控配置了 `webhook` 时，Firecrawl 可以发送两种监控事件：

* `monitor.page`：每个被监控的 抓取 在 抓取 worker 中完成后发送。
* `monitor.check.completed`：在完整检查完成汇总后发送。包含检查状态和汇总计数。页面级结果请使用 `monitor.page` 事件或监控检查 API。

如果对已变更页面执行了有意义变更判定，`monitor.page` 会包含 `isMeaningful` 和 `judgment`。

```json title="Webhook config"
{
  "webhook": {
    "url": "https://example.com/webhooks/firecrawl",
    "headers": {
      "Authorization": "Bearer your-secret"
    },
    "metadata": {
      "environment": "production"
    },
    "events": ["monitor.page", "monitor.check.completed"]
  }
}
```

`monitor.page` 载荷：

```json title="monitor.page"
{
  "success": true,
  "type": "monitor.page",
  "id": "019df960-5f2a-75fb-a98b-bd2d32ca67d4",
  "webhookId": "f1e2d3c4-0000-0000-0000-000000000000",
  "data": [
    {
      "monitorId": "019df960-06e7-7383-9d89-82c0113dc31a",
      "checkId": "019df960-5f2a-75fb-a98b-bd2d32ca67d4",
      "url": "https://example.com/blog",
      "status": "changed",
      "previousScrapeId": "019df94f-82c3-7e41-81f0-00c72b2d9c52",
      "currentScrapeId": "019df960-73ee-7ac2-97a9-fb0e442c21f1",
      "error": null,
      "isMeaningful": true,
      "judgment": {
        "meaningful": true,
        "confidence": "high",
        "reason": "The page headline changed to announce a new release cadence.",
        "meaningfulChanges": [
          {
            "type": "changed",
            "before": "Welcome to our weekly update.",
            "after": "Welcome to our weekly update — now with daily releases!",
            "reason": "The headline changed in a way that matches the monitor goal."
          }
        ]
      },
      "diff": {
        "text": "--- previous\n+++ current\n@@ -1,3 +1,3 @@\n # Latest posts\n-Welcome to our weekly update.\n+Welcome to our weekly update — now with daily releases!\n"
      }
    }
  ],
  "metadata": {
    "environment": "production"
  }
}
```

`monitor.check.completed` 载荷：

```json title="monitor.check.completed"
{
  "success": true,
  "type": "monitor.check.completed",
  "id": "019df960-5f2a-75fb-a98b-bd2d32ca67d4",
  "webhookId": "f1e2d3c4-0001-0000-0000-000000000000",
  "data": [
    {
      "monitorId": "019df960-06e7-7383-9d89-82c0113dc31a",
      "checkId": "019df960-5f2a-75fb-a98b-bd2d32ca67d4",
      "status": "completed",
      "summary": {
        "totalPages": 2,
        "same": 1,
        "changed": 1,
        "new": 0,
        "removed": 0,
        "error": 0
      }
    }
  ],
  "metadata": {
    "environment": "production"
  }
}
```

当检查在没有页面级错误的情况下完成时，`success` 为 `true`。对于失败或部分完成的检查，它为 `false`；如果可用，`error` 会包含失败原因。

<div id="email">
  ### 电子邮件 [#电子邮件]
</div>

仅当某次检查出现页面变更、新增、移除或报错时，才会发送电子邮件摘要。

```json title="Email config"
{
  "notification": {
    "email": {
      "enabled": true,
      "recipients": ["alerts@example.com"],
      "includeDiffs": true
    }
  }
}
```

当某个监控设置了目标并启用判定后，电子邮件摘要会优先展示有意义的变更页面。如果所有变更页面都被判定为噪声，且没有新增、移除或报错的页面，则会抑制发送该电子邮件。

如果省略 `recipients`，Firecrawl 会将邮件发送给有资格接收系统告警邮件的团队成员。
你最多可以配置 25 个明确指定的收件人。

<div id="recipient-confirmation-process">
  #### 收件人确认流程 [#收件人确认流程]
</div>

当有新的收件人被添加到某项监控时，Firecrawl 会向其发送一封包含确认链接的电子邮件，以确保对方明确同意接收该监控的通知。如果收件人已是团队成员，则无需确认。

<div id="slack">
  ### Slack [#slack]
</div>

你也可以将监控通知发送到 Slack 频道。

<Note>
  Slack 通知仅支持在 Dashboard 中使用。它们只能通过[监控 Dashboard](https://www.firecrawl.dev/app/monitoring)进行配置，不能通过 API 或 SDKs 配置。
</Note>

要设置 Slack 通知：

1. 打开[监控 Dashboard](https://www.firecrawl.dev/app/monitoring)。你可以在创建新监控时添加 Slack 通知，也可以将其添加到已存在的监控中。
2. 在创建监控时，或选择现有监控后，滚动到 **通知** 并选择 **Slack**。
3. 系统会提示你完成 OAuth 流程。完成后，选择你希望接收通知的工作区和频道。

<div id="check-results">
  ## 查看检查结果 [#查看检查结果]
</div>

使用 `GET /v2/monitor/{monitorId}/checks` 获取检查列表，使用 `GET /v2/monitor/{monitorId}/checks/{checkId}` 查看某次检查的详情。SDKs 默认会自动处理分页。

<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(api_key="fc-YOUR-API-KEY")

      check = firecrawl.get_monitor_check(monitor_id, check_id, limit=25, status="changed")

      for page in check.pages:
          print(page.url, page.status)

          if page.judgment:
              print(page.judgment.meaningful, page.judgment.reason)

          if page.diff and page.diff.text:
              print(page.diff.text)

          if page.snapshot and page.snapshot.json:
              print(page.snapshot.json)
      ```
    </CodeBlockTab>

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

      const firecrawl = new Firecrawl({ apiKey: "fc-YOUR-API-KEY" });

      const check = await firecrawl.getMonitorCheck(monitorId, checkId, {
        limit: 25,
        status: "changed",
      });

      for (const page of check.pages) {
        console.log(page.url, page.status);

        if (page.judgment) {
          console.log(page.judgment.meaningful, page.judgment.reason);
        }

        if (page.diff?.text) {
          console.log(page.diff.text);
        }

        if (page.snapshot?.json) {
          console.log(page.snapshot.json);
        }
      }
      ```
    </CodeBlockTab>

    <CodeBlockTab value="cURL">
      ```bash  
      curl "https://api.firecrawl.dev/v2/monitor/$MONITOR_ID/checks/$CHECK_ID?limit=25&status=changed" \
        -H "Authorization: Bearer $FIRECRAWL_API_KEY"
      ```
    </CodeBlockTab>
  </CodeBlockTabs>
</CodeGroup>

检查列表可按检查 `status` 过滤：`queued`、`running`、`completed`、`failed`、`partial` 或 `skipped_overlap`。

检查详情响应包含 `estimatedCredits`、`actualCredits`、汇总计数以及分页的 `pages` 数组。`estimatedCredits` 是该检查预留额度的上限；`actualCredits` 是 Firecrawl 在确认有多少页面发生变化并需要判定后，最终收取的额度。使用顶层 `next` URL 获取下一页结果，其分页方式与 爬取 保持一致。你还可以按页面 `status` 过滤：`same`、`new`、`changed`、`removed` 或 `error`。每个已变更页面都包含内联 `diff` 数据；来自 JSON 模式监控的页面还会包含带有当前提取结果的 `snapshot`。

<Tabs>
  <Tab title="Markdown 模式">
    ```json title="Markdown-mode response"
    {
      "success": true,
      "next": "https://api.firecrawl.dev/v2/monitor/019df960-06e7-7383-9d89-82c0113dc31a/checks/019df960-5f2a-75fb-a98b-bd2d32ca67d4?skip=25&limit=25",
      "data": {
        "id": "019df960-5f2a-75fb-a98b-bd2d32ca67d4",
        "monitorId": "019df960-06e7-7383-9d89-82c0113dc31a",
        "status": "completed",
        "estimatedCredits": 2,
        "actualCredits": 2,
        "summary": {
          "totalPages": 1,
          "same": 0,
          "changed": 1,
          "new": 0,
          "removed": 0,
          "error": 0
        },
        "pages": [
          {
            "id": "019df960-7708-7c62-a5dc-6206f16ac122",
            "targetId": "019df960-09bb-7c11-8001-1f12f50ab1c2",
            "url": "https://example.com/blog",
            "status": "changed",
            "previousScrapeId": "019df94f-82c3-7e41-81f0-00c72b2d9c52",
            "currentScrapeId": "019df960-73ee-7ac2-97a9-fb0e442c21f1",
            "statusCode": 200,
            "error": null,
            "metadata": {
              "title": "Example Blog",
              "creditsUsed": 1
            },
            "judgment": {
              "meaningful": true,
              "confidence": "high",
              "reason": "The page headline changed to announce a new release cadence.",
              "meaningfulChanges": [
                {
                  "type": "changed",
                  "before": "Welcome to our weekly update.",
                  "after": "Welcome to our weekly update — now with daily releases!",
                  "reason": "The headline changed in a way that matches the monitor goal."
                }
              ]
            },
            "createdAt": "2026-05-17T15:35:00.000Z",
            "diff": {
              "text": "--- previous\n+++ current\n@@ -1,3 +1,3 @@\n # Latest posts\n-Welcome to our weekly update.\n+Welcome to our weekly update — now with daily releases!\n",
              "json": {
                "files": [
                  {
                    "from": "previous",
                    "to": "current",
                    "chunks": []
                  }
                ]
              }
            }
          }
        ],
        "next": "https://api.firecrawl.dev/v2/monitor/019df960-06e7-7383-9d89-82c0113dc31a/checks/019df960-5f2a-75fb-a98b-bd2d32ca67d4?skip=25&limit=25"
      }
    }
    ```
  </Tab>

  <Tab title="JSON 模式">
    ```json title="JSON-mode response"
    {
      "success": true,
      "data": {
        "id": "019df960-5f2a-75fb-a98b-bd2d32ca67d4",
        "monitorId": "019df960-06e7-7383-9d89-82c0113dc31a",
        "status": "completed",
        "estimatedCredits": 2,
        "actualCredits": 2,
        "summary": {
          "totalPages": 1,
          "same": 0,
          "changed": 1,
          "new": 0,
          "removed": 0,
          "error": 0
        },
        "pages": [
          {
            "id": "019df960-7708-7c62-a5dc-6206f16ac122",
            "targetId": "019df960-09bb-7c11-8001-1f12f50ab1c2",
            "url": "https://example.com/pricing",
            "status": "changed",
            "previousScrapeId": "019df94f-82c3-7e41-81f0-00c72b2d9c52",
            "currentScrapeId": "019df960-73ee-7ac2-97a9-fb0e442c21f1",
            "statusCode": 200,
            "error": null,
            "metadata": {
              "title": "Pricing",
              "creditsUsed": 1
            },
            "judgment": {
              "meaningful": true,
              "confidence": "high",
              "reason": "The Starter plan price and Pro storage limit changed.",
              "meaningfulChanges": [
                {
                  "type": "changed",
                  "before": "$19/mo",
                  "after": "$24/mo",
                  "reason": "The Starter plan price changed."
                },
                {
                  "type": "changed",
                  "before": "10 GB storage",
                  "after": "25 GB storage",
                  "reason": "The Pro storage limit changed."
                }
              ]
            },
            "createdAt": "2026-05-17T15:35:00.000Z",
            "diff": {
              "json": {
                "plans[0].price": {
                  "previous": "$19/mo",
                  "current": "$24/mo"
                },
                "plans[1].features[2]": {
                  "previous": "10 GB storage",
                  "current": "25 GB storage"
                }
              }
            },
            "snapshot": {
              "json": {
                "plans": [
                  {
                    "name": "Starter",
                    "price": "$24/mo",
                    "features": ["Up to 3 users", "Basic analytics", "Email support"]
                  },
                  {
                    "name": "Pro",
                    "price": "$49/mo",
                    "features": ["Unlimited users", "Advanced analytics", "25 GB storage"]
                  }
                ]
              }
            }
          }
        ]
      }
    }
    ```
  </Tab>

  <Tab title="混合模式">
    ```json title="Mixed-mode response (JSON + git-diff)"
    {
      "success": true,
      "data": {
        "id": "019df960-5f2a-75fb-a98b-bd2d32ca67d4",
        "monitorId": "019df960-06e7-7383-9d89-82c0113dc31a",
        "status": "completed",
        "estimatedCredits": 2,
        "actualCredits": 2,
        "summary": {
          "totalPages": 1,
          "same": 0,
          "changed": 1,
          "new": 0,
          "removed": 0,
          "error": 0
        },
        "pages": [
          {
            "id": "019df960-7708-7c62-a5dc-6206f16ac122",
            "targetId": "019df960-09bb-7c11-8001-1f12f50ab1c2",
            "url": "https://example.com/pricing",
            "status": "changed",
            "previousScrapeId": "019df94f-82c3-7e41-81f0-00c72b2d9c52",
            "currentScrapeId": "019df960-73ee-7ac2-97a9-fb0e442c21f1",
            "statusCode": 200,
            "error": null,
            "metadata": {
              "title": "Pricing",
              "creditsUsed": 1
            },
            "judgment": {
              "meaningful": true,
              "confidence": "high",
              "reason": "The Starter plan price changed.",
              "meaningfulChanges": [
                {
                  "type": "changed",
                  "before": "Starter — $19/mo",
                  "after": "Starter — $24/mo",
                  "reason": "The Starter plan price changed."
                }
              ]
            },
            "createdAt": "2026-05-17T15:35:00.000Z",
            "diff": {
              "text": "--- previous\n+++ current\n@@ -1,3 +1,3 @@\n # Pricing\n-Starter — $19/mo\n+Starter — $24/mo\n",
              "json": {
                "plans[0].price": {
                  "previous": "$19/mo",
                  "current": "$24/mo"
                }
              }
            },
            "snapshot": {
              "json": {
                "plans": [
                  { "name": "Starter", "price": "$24/mo" },
                  { "name": "Pro", "price": "$49/mo" }
                ]
              }
            }
          }
        ]
      }
    }
    ```
  </Tab>
</Tabs>

<div id="pricing">
  ## 定价 [#定价]
</div>

监控不单独按每个监控收费。每次检查都按其执行的底层 抓取、爬取 或 搜索 计费；此外，如果启用了有效变更判定，则每个发生变更且经判定器确认的页面还会额外消耗 1 个额度。

| 组件                              | 额度                                 |
| ------------------------------- | ---------------------------------- |
| 抓取 监控                           | 每次检查每个 URL 1 个额度                   |
| 爬取 监控                           | 每次检查每个发现的页面 1 个额度                  |
| 网页 监控                           | 每次检查每 10 个结果 2 个额度                 |
| 网页 监控判定                         | 启用 AI 判定时，每个判定结果 1 个额度 (包含抓取和评估结果) |
| 启用有效变更判定                        | 每个经判定器确认的变更页面额外 1 个额度              |
| 格式附加项 (JSON、PDF、question、增强模式等) | 与单独使用 [抓取](/zh/features/scrape) 相同 |

<div id="api-reference">
  ## API 参考 [#api-参考]
</div>

* [创建监控](/zh/api-reference/endpoint/monitor-create)
* [查看监控列表](/zh/api-reference/endpoint/monitor-list)
* [获取监控](/zh/api-reference/endpoint/monitor-get)
* [更新监控](/zh/api-reference/endpoint/monitor-update)
* [删除监控](/zh/api-reference/endpoint/monitor-delete)
* [运行监控](/zh/api-reference/endpoint/monitor-run)
* [查看监控检查列表](/zh/api-reference/endpoint/monitor-checks-list)
* [获取监控检查](/zh/api-reference/endpoint/monitor-check-get)
* [监控页面 Webhook 载荷](/zh/api-reference/endpoint/webhook-monitor-page)
* [监控检查完成 Webhook 载荷](/zh/api-reference/endpoint/webhook-monitor-check-completed)
