CrawlForge MCP
API Reference

托管 监控

把一组页面和一个 cron 计划交给 CrawlForge。它在自己的调度器上抓取并对比这些页面,记录每一次检查,并通过邮件或已签名的 webhook 告诉您变更了什么。没有按监控收取的费用:每次检查按每个已对比目标收取 track_changes 的价格。

概览

一个监控由名称、最多 20 个目标(一个 url 加可选的 CSS selector)、带 IANA 时区的五段式 cron 计划,以及结果的发送地址组成。CrawlForge 的调度器每 5 分钟运行一次并自行启动每个到期的检查,因此您这边不需要运行任何进程。

对目标的第一次检查会捕获基线并报告为 new。之后的每次检查都与上一次检查对比并把基线向前滚动,因此每次检查报告的是自上一次以来的变更。基线一直保留到监控被删除;检查在 retention_days 之后被清理。

所有端点都接受与工具相同的 X-API-Key 请求头(或 Authorization: Bearer cf_…)。管理调用不计费,且在零 credits 时也能使用。响应使用工具的信封格式 { success, data },错误携带 error.code 和 error.message。

端点

方法路径作用
POST/api/v1/monitors创建监控。返回 201 及该监控,包括其 webhook_secret。
GET/api/v1/monitors列出监控,每个都带有最新一次检查 last_check。查询参数 limit 和 cursor;响应体携带 next_cursor。绝不返回 webhook_secret。
GET/api/v1/monitors/{id}单个监控,包括 webhook_secret。
PATCH/api/v1/monitors/{id}更新创建字段的任意子集。把 status 设为 paused 会将 next_run_at 置为 null。
DELETE/api/v1/monitors/{id}删除监控。返回 { id, deleted: true }。
POST/api/v1/monitors/{id}/run立即内联运行一次检查,并连同 pages 一起返回。已有检查在进行中时返回 409 MONITOR_RUNNING。
GET/api/v1/monitors/{id}/checks不含 pages 的检查历史。查询参数 limit 和 cursor。
GET/api/v1/monitors/{id}/checks/{check_id}单次检查,含 pages 和 webhook deliveries。

创建监控

只有 name 和 targets 是必填项。默认值会为您提供 UTC 时区下每小时一次的检查和 30 天的历史记录。

terminalBash
curl -X POST https://crawlforge.dev/api/v1/monitors \
  -H "X-API-Key: cf_test_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "competitor pricing",
    "targets": [{ "url": "https://competitor.com/pricing", "selector": ".pricing-table" }],
    "schedule_cron": "0 * * * *",
    "webhook_url": "https://example.com/hooks/crawlforge"
  }'

请求体接受的全部字段。PATCH 接受这些字段的任意子集。

字段类型默认值说明
namestring必填1 到 80 个字符。
targetsarray必填1 到 20 个 { url, selector? } 对象。URL 必须是公网 http(s) 地址;私有或本地地址会以 400 拒绝。
schedule_cronstring0 * * * *五段式 cron 表达式。相邻两次运行至少间隔 5 分钟。
timezonestringUTC计算计划时所用的 IANA 时区,例如 Europe/Madrid。
notify_emailsstring[]—最多 5 个邮箱地址,当一次检查发现变化时收到邮件。见“通知”。
webhook_urlstring—接收已签名事件的公网 https URL。见“通知”。
webhook_secretstring自动生成16 到 128 个字符,用于为每次投递签名。省略且已设置 webhook_url 时自动生成。在创建和 GET 单个时返回,列表中绝不返回。
retention_daysnumber301 到 365。早于该天数的检查会被清理;基线一直保留到监控被删除。
statusstringactiveactive 或 paused。暂停的监控保留其基线,且没有 next_run_at。

完整请求体

两个目标、马德里时区的工作日早晨、邮件加使用自有密钥的 webhook、90 天历史记录:

POST /api/v1/monitorsJson
{
  "name": "competitor pricing",
  "targets": [
    { "url": "https://competitor.com/pricing", "selector": ".pricing-table" },
    { "url": "https://competitor.com/changelog" }
  ],
  "schedule_cron": "0 9 * * 1-5",
  "timezone": "Europe/Madrid",
  "notify_emails": ["alerts@example.com"],
  "webhook_url": "https://example.com/hooks/crawlforge",
  "webhook_secret": "3f9a1c7e5b2d48f0a6c1e9d7b5a3f2c4",
  "retention_days": 90,
  "status": "active"
}

监控对象

创建、GET 单个和 PATCH 都返回该监控。next_run_at 是下一个时间槽,last_check_at 是最新一次检查的时间,estimated_credits_per_month 在“计费”中说明。列表响应会额外附上 last_check,即不含页面的最新一次检查。

201 CreatedJson
{
  "success": true,
  "data": {
    "id": "cmf9k2x1a0001s8h4b7d3q2wz",
    "name": "competitor pricing",
    "targets": [
      { "url": "https://competitor.com/pricing", "selector": ".pricing-table" }
    ],
    "schedule_cron": "0 * * * *",
    "timezone": "UTC",
    "notify_emails": [],
    "webhook_url": "https://example.com/hooks/crawlforge",
    "webhook_secret": "3f9a1c7e5b2d48f0a6c1e9d7b5a3f2c4",
    "status": "active",
    "next_run_at": "2026-09-07T15:00:00.000Z",
    "last_check_at": null,
    "retention_days": 30,
    "estimated_credits_per_month": 2160,
    "created_at": "2026-09-07T14:12:08.000Z",
    "updated_at": "2026-09-07T14:12:08.000Z"
  }
}

列出、立即运行和读取检查

列出

terminalBash
curl "https://crawlforge.dev/api/v1/monitors?limit=20" \
  -H "X-API-Key: cf_test_YOUR_KEY"

# Next page: pass the next_cursor from the previous response
curl "https://crawlforge.dev/api/v1/monitors?limit=20&cursor=NEXT_CURSOR" \
  -H "X-API-Key: cf_test_YOUR_KEY"

立即运行

在计划之外立即运行一次检查,并连同其页面一起返回。适用相同的计费规则。该检查仍在运行时再次调用会返回 409 MONITOR_RUNNING。

terminalBash
# Run one check now and get it back with its pages
curl -X POST https://crawlforge.dev/api/v1/monitors/MONITOR_ID/run \
  -H "X-API-Key: cf_test_YOUR_KEY"

检查

terminalBash
# Check history (no pages)
curl "https://crawlforge.dev/api/v1/monitors/MONITOR_ID/checks?limit=20" \
  -H "X-API-Key: cf_test_YOUR_KEY"

# One check, with its pages and webhook deliveries
curl https://crawlforge.dev/api/v1/monitors/MONITOR_ID/checks/CHECK_ID \
  -H "X-API-Key: cf_test_YOUR_KEY"

检查对象

一次含两个目标的检查:定价表发生了变更并已计费,文档页面遇到 Cloudflare 挑战因此未计费。deliveries 是该次检查的 webhook 日志。

GET /api/v1/monitors/{id}/checks/{check_id}Json
{
  "success": true,
  "data": {
    "id": "cmf9k5r8t0003s8h4m1n6p4vx",
    "monitor_id": "cmf9k2x1a0001s8h4b7d3q2wz",
    "started_at": "2026-09-07T15:00:02.000Z",
    "finished_at": "2026-09-07T15:00:05.000Z",
    "status": "completed",
    "summary": { "total": 2, "new": 0, "changed": 1, "unchanged": 0, "blocked": 1, "errored": 0 },
    "credits_reserved": 6,
    "credits_charged": 3,
    "error": null,
    "pages": [
      {
        "url": "https://competitor.com/pricing",
        "selector": ".pricing-table",
        "status": "changed",
        "change_percent": 12.5,
        "structural_similarity": 0.9713,
        "added_count": 4,
        "removed_count": 2,
        "added_samples": ["Pro $79 / month", "Includes 50,000 credits"],
        "removed_samples": ["Pro $99 / month", "Includes 25,000 credits"],
        "content_hash": "9f2c0b7e4d1a8c6f3e5b2a9d7c4f1e8b0a6d3c2f5e9b1a7d4c8f2e6b3a9d1c7f",
        "error_code": null,
        "error": null,
        "blocked_vendor": null,
        "duration_ms": 1180,
        "charged": true
      },
      {
        "url": "https://competitor.com/docs",
        "selector": null,
        "status": "blocked",
        "change_percent": null,
        "structural_similarity": null,
        "added_count": null,
        "removed_count": null,
        "added_samples": [],
        "removed_samples": [],
        "content_hash": null,
        "error_code": "BLOCKED",
        "error": "Challenge page served by cloudflare",
        "blocked_vendor": "cloudflare",
        "duration_ms": 640,
        "charged": false
      }
    ],
    "deliveries": [
      {
        "id": "cmf9k5rb20005s8h4q7w2e9rt",
        "event": "monitor.page",
        "url": "https://example.com/hooks/crawlforge",
        "attempts": 1,
        "status": "delivered",
        "http_status": 200,
        "error": null,
        "delivered_at": "2026-09-07T15:00:05.100Z"
      },
      {
        "id": "cmf9k5rb20006s8h4z3x8c5vb",
        "event": "monitor.check.completed",
        "url": "https://example.com/hooks/crawlforge",
        "attempts": 1,
        "status": "delivered",
        "http_status": 200,
        "error": null,
        "delivered_at": "2026-09-07T15:00:05.400Z"
      }
    ]
  }
}

计费与月度估算

没有按监控收取的费用,创建、列出、更新或删除监控都不计费。每次检查按每个目标预留 3 credits(即 track_changes 的价格),并对状态为 new、changed 或 unchanged 的每个目标实际扣除 3 credits。结果为 blocked 或 error 的目标不计费。每次检查都会在用量日志中写入一条 track_changes 记录。

如果余额不足以覆盖预留额,该次检查会被记录为 insufficient_credits,并且不会抓取任何内容。

监控上的 estimated_credits_per_month = 计划在未来 30 天内触发的次数 × 目标数 × 3。这是每个目标每次都被抓取并对比的月份的上限。

schedule_cron目标数30 天内运行次数estimated_credits_per_month
0 * * * *17202,160
*/15 * * * *12,8808,640
0 9 * * *530450

检查状态与页面状态

每次检查携带一个 status、一个按页面状态计数的 summary,以及 credits_reserved / credits_charged。

检查 status含义
running检查正在进行中。此期间 POST …/run 返回 409 MONITOR_RUNNING。
completed所有目标均已处理。请读取 summary 和 pages。
failed检查未能完成;error 说明原因。
skipped_overlap该时间槽到来时上一次检查仍在运行。未抓取任何内容。
insufficient_credits余额不足以覆盖预留额。未抓取任何内容。

pages 中的每个条目携带一个 status。changed 页面包含 change_percent、structural_similarity、added_count、removed_count,以及 added_samples 和 removed_samples 中最多 20 条、每条最多 500 个字符的样本行;计数才是真实总数。

页面 status含义是否计费
new对该目标的首次捕获。基线已写入;暂时没有可对比的内容。是
changed内容与上一次检查不同。基线向前滚动到本次捕获。是
unchanged内容哈希与上一次检查相同。是
blocked目标返回了挑战墙(Cloudflare、DataDome、PerimeterX、Akamai、Amazon、Vercel)或不可用的文档。blocked_vendor 给出厂商名称。绝不会报告为变更。否
error抓取失败、选择器未匹配到任何元素,或 robots.txt 禁止该路径。error_code 携带错误码:FETCH_FAILED、SELECTOR_NOT_FOUND、ROBOTS_DISALLOWED 等。否
始终遵守 robots.txt 监控没有 respect_robots 覆盖选项。robots.txt 对 CrawlForge 禁止其路径的目标,在每次检查中都会报告为 error 并带 ROBOTS_DISALLOWED,且绝不计费。

计划规则

schedule_cron 是标准的五段式 cron 表达式(分钟、小时、日、月、星期),按 timezone 计算。相邻两次运行至少间隔 5 分钟,因此 * * * * * 和 */2 * * * * 会以 400 拒绝。

CrawlForge 的调度器每 5 分钟唤醒一次,启动所有时间槽已过的检查,因此检查会在其时间槽后的 5 分钟内开始。监控上的 next_run_at 是下一个时间槽;暂停监控会将其置为 null。

如果监控的上一次检查在下一个时间槽到来时仍在运行,则记录一次 skipped_overlap 检查,而不会启动第二次检查。

表达式运行时间
0 * * * *每小时整点(默认值)。
*/15 * * * *每 15 分钟。
0 9 * * 1-5周一至周五 09:00,按 timezone 计算。
0 6,18 * * *每天 06:00 和 18:00。
30 2 1 * *每月 1 日 02:30。

通知

邮件。 设置了 notify_emails 时,只有当一次检查至少有一个 new、changed、blocked 或 error 页面时才会发送邮件。所有目标都是 unchanged 的检查不会发送任何内容。

Webhook。 设置了 webhook_url 时,每次投递都是一个 POST,JSON 请求体为 { event, id, timestamp, data },并带有以下请求头:

请求头值
Content-Typeapplication/json
X-Webhook-Eventmonitor.page 或 monitor.check.completed
X-Webhook-ID投递 id,在重试之间保持不变,因此接收方可以丢弃重复项。
X-Webhook-Timestamp发送投递时的 Unix 时间,单位毫秒。
X-Webhook-Signaturesha256= 后接以 webhook_secret 为密钥、对原始请求体精确计算的十六进制 HMAC-SHA256。

两种事件。先发送页面事件,再发送检查摘要。

event何时发送data
monitor.page每个状态不是 unchanged 的页面各发送一条。{ monitor: { id, name }, check_id, page, dashboard_url }——page 是完整的页面结果,包含样本。
monitor.check.completed每次完成的检查。{ monitor, check: { id, started_at, finished_at, status, summary, credits_charged }, pages, dashboard_url }——pages 中的每个条目包含 url, selector, status, change_percent, added_count, removed_count, error_code,不含样本。
POST webhook_url — X-Webhook-Event: monitor.check.completedJson
{
  "event": "monitor.check.completed",
  "id": "cmf9k5rb20006s8h4z3x8c5vb",
  "timestamp": 1788793205400,
  "data": {
    "monitor": { "id": "cmf9k2x1a0001s8h4b7d3q2wz", "name": "competitor pricing" },
    "check": {
      "id": "cmf9k5r8t0003s8h4m1n6p4vx",
      "started_at": "2026-09-07T15:00:02.000Z",
      "finished_at": "2026-09-07T15:00:05.000Z",
      "status": "completed",
      "summary": { "total": 2, "new": 0, "changed": 1, "unchanged": 0, "blocked": 1, "errored": 0 },
      "credits_charged": 3
    },
    "pages": [
      {
        "url": "https://competitor.com/pricing",
        "selector": ".pricing-table",
        "status": "changed",
        "change_percent": 12.5,
        "added_count": 4,
        "removed_count": 2,
        "error_code": null
      },
      {
        "url": "https://competitor.com/docs",
        "selector": null,
        "status": "blocked",
        "change_percent": null,
        "added_count": null,
        "removed_count": null,
        "error_code": "BLOCKED"
      }
    ],
    "dashboard_url": "https://www.crawlforge.dev/dashboard/monitors/cmf9k2x1a0001s8h4b7d3q2wz"
  }
}

投递。 最多 4 次尝试(首次加三次重试),间隔分别为 1 秒、2 秒和 4 秒,每次超时 10 秒。2xx 响应视为已投递。除 408 或 429 以外的 4xx 不会重试。投递日志随检查一起保存:GET …/checks/{check_id} 返回 deliveries,包含每个事件的尝试次数、HTTP 状态和错误。

验证签名

在解析 JSON 之前,对原始请求体计算 HMAC,并以恒定时间比较。请求头集合和签名方案与 CrawlForge MCP 服务器的 webhook 完全相同,因此同一个接收端可以同时验证两者。

verifyWebhook.tsTypescript
import { createHmac, timingSafeEqual } from 'node:crypto';
import express from 'express';

// Sign the RAW body exactly as received. Parsing and re-serialising the JSON
// first changes the bytes and the signature no longer matches.
function verifyCrawlForgeWebhook(rawBody: Buffer, signatureHeader: string, secret: string): boolean {
  const expected = Buffer.from('sha256=' + createHmac('sha256', secret).update(rawBody).digest('hex'));
  const received = Buffer.from(signatureHeader);
  return expected.length === received.length && timingSafeEqual(expected, received);
}

const app = express();

// express.raw keeps the body as a Buffer; express.json would have parsed it.
app.post('/hooks/crawlforge', express.raw({ type: 'application/json' }), (req, res) => {
  const secret = process.env.CRAWLFORGE_WEBHOOK_SECRET!;
  if (!verifyCrawlForgeWebhook(req.body, req.header('X-Webhook-Signature') ?? '', secret)) {
    return res.status(401).end();
  }

  const { event, data } = JSON.parse(req.body.toString('utf8'));
  if (event === 'monitor.page') {
    console.log(data.page.status, data.page.url, data.page.change_percent);
  } else if (event === 'monitor.check.completed') {
    console.log('check', data.check.id, data.check.summary);
  }
  res.status(204).end();
});

限制

  • 每个账户 50 个监控。创建第 51 个时返回 409 MONITOR_LIMIT_REACHED。
  • 每个监控 20 个目标,notify_emails 中 5 个地址。
  • 相邻两次运行至少间隔 5 分钟。
  • retention_days 为 1 到 365,默认 30。基线一直保留到监控被删除。
  • 差异样本:added_samples 和 removed_samples 各最多 20 行,每行最多 500 个字符。

错误

状态含义
400 VALIDATION_ERROR某个字段超出范围,cron 表达式无效或触发频率高于每 5 分钟一次,或目标 URL 不是公网 http(s) 地址。
401缺少或无效的 API key。
404您的账户下没有该 id 对应的监控或检查。
409 MONITOR_LIMIT_REACHED您已经有 50 个监控。
409 MONITOR_RUNNING在检查进行中调用了 POST …/run。
相关内容
track_changes
一次性的基线与对比,以及用 operation: "monitor" 从单个 URL 创建监控;MCP 服务器的 create_scheduled_monitor 配合 hosted: true 创建的是同一种监控。
控制台
无需编写请求即可创建、暂停和查看监控及其检查。

页脚

CrawlForge MCP

面向 AI Agent 的企业级网页抓取。31 个专业 MCP 工具,专为构建智能系统的现代开发者而设计。

产品

  • 功能
  • Playground
  • 价格
  • 应用场景
  • 集成
  • 替代方案
  • 更新日志

资源

  • 快速上手
  • API 参考
  • 模板
  • 指南
  • 博客
  • 术语表
  • 常见问题
  • 网站地图

开发者

  • MCP 协议
  • Claude Desktop
  • Cursor IDE
  • LangChain
  • LlamaIndex

公司

  • 关于我们
  • 联系我们
  • 隐私政策
  • 服务条款
  • 可接受使用政策
  • 安全
  • Cookie

保持更新

获取新工具和新功能的最新动态。

基于 Next.js 和 MCP 协议构建

© 2025-2026 CrawlForge。保留所有权利。