> ## Documentation Index
> Fetch the complete documentation index at: https://docs.firecrawl.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# 変更追跡

> スクレイプ間でのウェブコンテンツの変更を検出・監視する

<img src="https://mintcdn.com/firecrawl/vlKm1oZYK3oSRVTM/images/launch-week/lw3d12.webp?fit=max&auto=format&n=vlKm1oZYK3oSRVTM&q=85&s=cc56c24d15e1b2ed4806ddb66d0f5c3f" alt="変更追跡" width="2400" height="1350" data-path="images/launch-week/lw3d12.webp" />

Change Tracking (変更追跡) は、ページの現在のコンテンツを最後にスクレイプしたときの状態と比較します。ページが新規か、変更なし (`unchanged`) か、変更あり (`modified`) かを検出するために `changeTracking` を `formats` 配列に追加し、必要に応じて「何が変わったか」の構造化された差分を取得できます。

* `/scrape`、`/crawl`、`/batch/scrape` で動作
* 2 つの diff モード: 行単位の変更用 `git-diff`、フィールド単位の比較用 `json`
* チームごとにスコープされ、必要に応じて渡したタグごとにもスコープ可能

<div id="how-it-works">
  ## 仕組み
</div>

`changeTracking` が有効なすべてのスクレイプ実行時にスナップショットが保存され、その URL に対する前回のスナップショットと比較されます。スナップショットは永続的に保存され、有効期限がないため、スクレイプ間でどれだけ時間が空いても比較結果の精度が維持されます。

| Scrape            | Result                                         |
| ----------------- | ---------------------------------------------- |
| First time        | `changeStatus: "new"` (前のバージョンが存在しない)          |
| Content unchanged | `changeStatus: "same"` (コンテンツに変更なし)            |
| Content modified  | `changeStatus: "changed"` (コンテンツが変更され、差分データあり) |
| Page removed      | `changeStatus: "removed"` (ページが削除された)          |

レスポンスには、`changeTracking` オブジェクト内に次のフィールドが含まれます。

| Field              | Type                  | Description                                                             |
| ------------------ | --------------------- | ----------------------------------------------------------------------- |
| `previousScrapeAt` | `string \| null`      | 前回スクレイプのタイムスタンプ (初回スクレイプ時は `null`)                                      |
| `changeStatus`     | `string`              | `"new"`、`"same"`、`"changed"`、または `"removed"`                            |
| `visibility`       | `string`              | `"visible"` (リンクやサイトマップ経由で検出可能) または `"hidden"` (URL は有効だが、もはやリンクされていない) |
| `diff`             | `object \| undefined` | 行レベルの差分 (ステータスが `"changed"` のときに `git-diff` モードでのみ含まれる)                 |
| `json`             | `object \| undefined` | フィールドレベルの比較 (ステータスが `"changed"` のときに `json` モードでのみ含まれる)                 |

<div id="basic-usage">
  ## 基本的な使い方
</div>

`formats` 配列には `markdown` と `changeTracking` の両方を指定します。変更追跡ではページの markdown コンテンツを比較するため、`markdown` フォーマットは必須です。

<CodeGroup>
  ```python Python theme={null}
  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)
  ```

  ```js Node theme={null}
  import { Firecrawl } from 'firecrawl';

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

  const result = await firecrawl.scrape('https://example.com/pricing', {
    formats: ['markdown', 'changeTracking']
  });

  console.log(result.changeTracking);
  ```

  ```bash cURL theme={null}
  curl -s -X POST "https://api.firecrawl.dev/v2/scrape" \
    -H "Authorization: Bearer $FIRECRAWL_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "url": "https://example.com/pricing",
      "formats": ["markdown", "changeTracking"]
    }'
  ```
</CodeGroup>

<div id="response">
  ### レスポンス
</div>

初回のスクレイプでは、`changeStatus` は `"new"`、`previousScrapeAt` は `null` になります。

```json theme={null}
{
  "success": true,
  "data": {
    "markdown": "# Pricing\n\nStarter: $9/mo\nPro: $29/mo...",
    "changeTracking": {
      "previousScrapeAt": null,
      "changeStatus": "new",
      "visibility": "visible"
    }
  }
}
```

以降のスクレイプでは、`changeStatus` にコンテンツが変更されたかどうかが反映されます。

```json theme={null}
{
  "success": true,
  "data": {
    "markdown": "# Pricing\n\nStarter: $12/mo\nPro: $39/mo...",
    "changeTracking": {
      "previousScrapeAt": "2025-06-01T10:00:00.000+00:00",
      "changeStatus": "changed",
      "visibility": "visible"
    }
  }
}
```

<div id="git-diff-mode">
  ## Git-diff モード
</div>

`git-diff` モードは、`git diff` に似た形式で行単位の変更差分を返します。`formats` 配列内に `modes: ["git-diff"]` を含むオブジェクトを指定します。

<CodeGroup>
  ```python Python theme={null}
  result = firecrawl.scrape(
      "https://example.com/pricing",
      formats=[
          "markdown",
          {
              "type": "changeTracking",
              "modes": ["git-diff"]
          }
      ]
  )

  if result.changeTracking.changeStatus == "changed":
      print(result.changeTracking.diff.text)
  ```

  ```js Node theme={null}
  const result = await firecrawl.scrape('https://example.com/pricing', {
    formats: [
      'markdown',
      { type: 'changeTracking', modes: ['git-diff'] }
    ]
  });

  if (result.changeTracking.changeStatus === 'changed') {
    console.log(result.changeTracking.diff.text);
  }
  ```

  ```bash cURL theme={null}
  curl -s -X POST "https://api.firecrawl.dev/v2/scrape" \
    -H "Authorization: Bearer $FIRECRAWL_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "url": "https://example.com/pricing",
      "formats": [
        "markdown",
        { "type": "changeTracking", "modes": ["git-diff"] }
      ]
    }'
  ```
</CodeGroup>

<div id="response">
  ### レスポンス
</div>

`diff` オブジェクトには、プレーンテキスト形式の diff と構造化された JSON 表現の両方が含まれます。

```json theme={null}
{
  "changeTracking": {
    "previousScrapeAt": "2025-06-01T10:00:00.000+00:00",
    "changeStatus": "changed",
    "visibility": "visible",
    "diff": {
      "text": "@@ -1,3 +1,3 @@\n # Pricing\n-Starter: $9/mo\n-Pro: $29/mo\n+Starter: $12/mo\n+Pro: $39/mo",
      "json": {
        "files": [{
          "chunks": [{
            "content": "@@ -1,3 +1,3 @@",
            "changes": [
              { "type": "normal", "content": "# Pricing" },
              { "type": "del", "ln": 2, "content": "Starter: $9/mo" },
              { "type": "del", "ln": 3, "content": "Pro: $29/mo" },
              { "type": "add", "ln": 2, "content": "Starter: $12/mo" },
              { "type": "add", "ln": 3, "content": "Pro: $39/mo" }
            ]
          }]
        }]
      }
    }
  }
}
```

構造化された `diff.json` オブジェクトには次の要素が含まれます:

* `files`: 変更されたファイルの配列 (通常はウェブページごとに1つ)
* `chunks`: ファイル内の変更箇所を表すセクション
* `changes`: 個々の行ごとの変更。`type` (`"add"`、`"del"`、または `"normal"`) 、行番号 (`ln`) 、および `content` を含む

<div id="json-mode">
  ## JSONモード
</div>

`json` モードは、定義したスキーマを使って、ページの現在のバージョンと前回のバージョンの両方から特定のフィールドを抽出します。これは、ページ全体の差分を解析することなく、価格、在庫レベル、メタデータなどの構造化データの変更を追跡するのに便利です。

抽出するフィールドを定義する `schema` とともに `modes: ["json"]` を渡します：

<CodeGroup>
  ```python Python theme={null}
  result = firecrawl.scrape(
      "https://example.com/product/widget",
      formats=[
          "markdown",
          {
              "type": "changeTracking",
              "modes": ["json"],
              "schema": {
                  "type": "object",
                  "properties": {
                      "price": { "type": "string" },
                      "availability": { "type": "string" }
                  }
              }
          }
      ]
  )

  if result.changeTracking.changeStatus == "changed":
      changes = result.changeTracking.json
      print(f"Price: {changes['price']['previous']} → {changes['price']['current']}")
  ```

  ```js Node theme={null}
  const result = await firecrawl.scrape('https://example.com/product/widget', {
    formats: [
      'markdown',
      {
        type: 'changeTracking',
        modes: ['json'],
        schema: {
          type: 'object',
          properties: {
            price: { type: 'string' },
            availability: { type: 'string' }
          }
        }
      }
    ]
  });

  if (result.changeTracking.changeStatus === 'changed') {
    const changes = result.changeTracking.json;
    console.log(`Price: ${changes.price.previous} → ${changes.price.current}`);
  }
  ```

  ```bash cURL theme={null}
  curl -s -X POST "https://api.firecrawl.dev/v2/scrape" \
    -H "Authorization: Bearer $FIRECRAWL_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "url": "https://example.com/product/widget",
      "formats": [
        "markdown",
        {
          "type": "changeTracking",
          "modes": ["json"],
          "schema": {
            "type": "object",
            "properties": {
              "price": { "type": "string" },
              "availability": { "type": "string" }
            }
          }
        }
      ]
    }'
  ```
</CodeGroup>

<div id="response">
  ### レスポンス
</div>

スキーマ内の各フィールドは、`previous` と `current` の値を含めて返されます。

```json theme={null}
{
  "changeTracking": {
    "previousScrapeAt": "2025-06-05T08:00:00.000+00:00",
    "changeStatus": "changed",
    "visibility": "visible",
    "json": {
      "price": {
        "previous": "$19.99",
        "current": "$24.99"
      },
      "availability": {
        "previous": "在庫あり",
        "current": "在庫あり"
      }
    }
  }
}
```

また、任意の `prompt` を渡して、スキーマとあわせて LLM による抽出をガイドすることもできます。

<Info>
  JSONモードは LLM 抽出を使用し、**1ページあたり5クレジット**かかります。基本的な変更追跡と `git-diff` モードには追加コストは発生しません。
</Info>

<div id="using-tags">
  ## タグの使用
</div>

デフォルトでは、変更追跡 (change tracking) は、チームによって同じ URL に対して実行された直近のスクレイプ結果と比較します。タグを使うと、同じ URL に対して**別々の追跡履歴**を維持できます。同じページを異なる間隔や異なるコンテキストで監視したい場合に便利です。

<CodeGroup>
  ```python Python theme={null}
  # 毎時監視（直近の「hourly」スクレイプ結果と比較）
  result = firecrawl.scrape(
      "https://example.com/pricing",
      formats=[
          "markdown",
          { "type": "changeTracking", "tag": "hourly" }
      ]
  )

  # 日次サマリー（直近の「daily」スクレイプ結果と比較）
  result = firecrawl.scrape(
      "https://example.com/pricing",
      formats=[
          "markdown",
          { "type": "changeTracking", "tag": "daily" }
      ]
  )
  ```

  ```js Node theme={null}
  // 毎時監視（直近の「hourly」スクレイプ結果と比較）
  const result = await firecrawl.scrape('https://example.com/pricing', {
    formats: [
      'markdown',
      { type: 'changeTracking', tag: 'hourly' }
    ]
  });

  // 日次サマリー（直近の「daily」スクレイプ結果と比較）
  const result2 = await firecrawl.scrape('https://example.com/pricing', {
    formats: [
      'markdown',
      { type: 'changeTracking', tag: 'daily' }
    ]
  });
  ```

  ```bash cURL theme={null}
  curl -s -X POST "https://api.firecrawl.dev/v2/scrape" \
    -H "Authorization: Bearer $FIRECRAWL_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "url": "https://example.com/pricing",
      "formats": [
        "markdown",
        { "type": "changeTracking", "tag": "hourly" }
      ]
    }'
  ```
</CodeGroup>

<div id="crawl-with-change-tracking">
  ## change tracking を利用したクロール
</div>

サイト全体の変更を監視するために、クロール処理に change tracking を追加します。`scrapeOptions` 内で `changeTracking` フォーマットを指定します。

<CodeGroup>
  ```python Python theme={null}
  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
      print(f"{url}: {status}")
  ```

  ```js Node theme={null}
  const result = await firecrawl.crawl('https://example.com', {
    limit: 50,
    scrapeOptions: {
      formats: ['markdown', 'changeTracking']
    }
  });

  for (const page of result.data) {
    console.log(`${page.metadata.url}: ${page.changeTracking.changeStatus}`);
  }
  ```

  ```bash cURL theme={null}
  curl -s -X POST "https://api.firecrawl.dev/v2/crawl" \
    -H "Authorization: Bearer $FIRECRAWL_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "url": "https://example.com",
      "limit": 50,
      "scrapeOptions": {
        "formats": ["markdown", "changeTracking"]
      }
    }'
  ```
</CodeGroup>

<div id="batch-scrape-with-change-tracking">
  ## changeTracking を使ったバッチスクレイプ
</div>

特定の URL 群を監視するには、[batch scrape](/ja/features/batch-scrape) を使用します：

<CodeGroup>
  ```python Python theme={null}
  result = firecrawl.batch_scrape(
      [
          "https://example.com/pricing",
          "https://example.com/product/widget",
          "https://example.com/blog/latest"
      ],
      formats=["markdown", {"type": "changeTracking", "modes": ["git-diff"]}]
  )
  ```

  ```js Node theme={null}
  const result = await firecrawl.batchScrape([
    'https://example.com/pricing',
    'https://example.com/product/widget',
    'https://example.com/blog/latest'
  ], {
    options: {
      formats: ['markdown', { type: 'changeTracking', modes: ['git-diff'] }]
    }
  });
  ```

  ```bash cURL theme={null}
  curl -s -X POST "https://api.firecrawl.dev/v2/batch/scrape" \
    -H "Authorization: Bearer $FIRECRAWL_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "urls": [
        "https://example.com/pricing",
        "https://example.com/product/widget",
        "https://example.com/blog/latest"
      ],
      "formats": [
        "markdown",
        { "type": "changeTracking", "modes": ["git-diff"] }
      ]
    }'
  ```
</CodeGroup>

<div id="scheduling-change-tracking">
  ## 変更追跡のスケジュール設定
</div>

変更追跡は、定期的にスクレイピングを行う場合に最も効果を発揮します。cron、クラウドスケジューラ、ワークフローツールなどで自動化できます。

<div id="cron-job">
  ### Cronジョブ
</div>

URLをスクレイピングし、変更を検知したらアラートを送るスクリプトを作成します。

```bash check-pricing.sh theme={null}
#!/bin/bash
RESPONSE=$(curl -s -X POST "https://api.firecrawl.dev/v2/scrape" \
  -H "Authorization: Bearer $FIRECRAWL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://competitor.com/pricing",
    "formats": [
      "markdown",
      {
        "type": "changeTracking",
        "modes": ["json"],
        "schema": {
          "type": "object",
          "properties": {
            "starter_price": { "type": "string" },
            "pro_price": { "type": "string" }
          }
        }
      }
    ]
  }')

STATUS=$(echo "$RESPONSE" | jq -r '.data.changeTracking.changeStatus')

if [ "$STATUS" = "changed" ]; then
  echo "$RESPONSE" | jq '.data.changeTracking.json'
  # メール、Slackなどでアラートを送信
fi
```

`crontab -e` でスケジュールを設定します：

```bash theme={null}
0 */6 * * * /path/to/check-pricing.sh >> /var/log/price-monitor.log 2>&1
```

| スケジュール    | 表現            |
| --------- | ------------- |
| 毎時        | `0 * * * *`   |
| 6時間ごと     | `0 */6 * * *` |
| 毎日午前9時    | `0 9 * * *`   |
| 毎週月曜日午前8時 | `0 8 * * 1`   |

<div id="cloud-and-serverless-schedulers">
  ### クラウドおよびサーバーレスのスケジューラー
</div>

* **AWS**: EventBridge ルールによる Lambda 関数のトリガー
* **GCP**: Cloud Scheduler による Cloud Function のトリガー
* **Vercel / Netlify**: Cron によってトリガーされるサーバーレス関数
* **GitHub Actions**: `schedule` および `cron` トリガーによるスケジュールされたワークフロー

<div id="workflow-automation">
  ### ワークフロー自動化
</div>

**n8n**、**Zapier**、**Make** のようなノーコードプラットフォームから、スケジュール実行で Firecrawl API を呼び出し、結果を Slack、メール、データベースなどに送信できます。[ワークフロー自動化ガイド](/ja/developer-guides/workflow-automation/n8n)も参照してください。

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

crawl や batch scrape のような非同期処理では、ポーリングするのではなく [webhooks](/ja/webhooks/overview) を使用して、到着しだい changeTracking の結果を受け取れます。

<CodeGroup>
  ```python Python theme={null}
  job = firecrawl.start_crawl(
      "https://example.com",
      limit=50,
      scrape_options={
          "formats": [
              "markdown",
              {"type": "changeTracking", "modes": ["git-diff"]}
          ]
      },
      webhook={
          "url": "https://your-server.com/firecrawl-webhook",
          "headers": {"Authorization": "Bearer your-webhook-secret"},
          "events": ["crawl.page", "crawl.completed"]
      }
  )
  ```

  ```js Node theme={null}
  const { id } = await firecrawl.startCrawl('https://example.com', {
    limit: 50,
    scrapeOptions: {
      formats: [
        'markdown',
        { type: 'changeTracking', modes: ['git-diff'] }
      ]
    },
    webhook: {
      url: 'https://your-server.com/firecrawl-webhook',
      headers: { Authorization: 'Bearer your-webhook-secret' },
      events: ['crawl.page', 'crawl.completed']
    }
  });
  ```

  ```bash cURL theme={null}
  curl -s -X POST "https://api.firecrawl.dev/v2/crawl" \
    -H "Authorization: Bearer $FIRECRAWL_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "url": "https://example.com",
      "limit": 50,
      "scrapeOptions": {
        "formats": [
          "markdown",
          { "type": "changeTracking", "modes": ["git-diff"] }
        ]
      },
      "webhook": {
        "url": "https://your-server.com/firecrawl-webhook",
        "headers": { "Authorization": "Bearer your-webhook-secret" },
        "events": ["crawl.page", "crawl.completed"]
      }
    }'
  ```
</CodeGroup>

`crawl.page` イベントのペイロードには、各ページごとに `changeTracking` オブジェクトが含まれています。

```json theme={null}
{
  "success": true,
  "type": "crawl.page",
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "data": [{
    "markdown": "# Pricing\n\nStarter: $12/mo...",
    "metadata": {
      "title": "Pricing",
      "url": "https://example.com/pricing",
      "statusCode": 200
    },
    "changeTracking": {
      "previousScrapeAt": "2025-06-05T12:00:00.000+00:00",
      "changeStatus": "changed",
      "visibility": "visible",
      "diff": {
        "text": "@@ -2,1 +2,1 @@\n-Starter: $9/mo\n+Starter: $12/mo"
      }
    }
  }]
}
```

Webhook の構成の詳細 (ヘッダー、メタデータ、イベント、再試行、署名検証) については、[Webhook ドキュメント](/ja/webhooks/overview)を参照してください。

<div id="configuration-reference">
  ## 設定リファレンス
</div>

`changeTracking` フォーマットオブジェクトを渡すときに利用できるオプション一覧:

| Parameter | Type       | Default    | Description                                |
| --------- | ---------- | ---------- | ------------------------------------------ |
| `type`    | `string`   | (required) | `"changeTracking"` でなければなりません              |
| `modes`   | `string[]` | `[]`       | 有効化する差分モード: `"git-diff"`、`"json"`、またはその両方  |
| `schema`  | `object`   | (none)     | フィールド単位の比較用の JSON Schema (`json` モードでは必須)  |
| `prompt`  | `string`   | (none)     | LLM による抽出を制御するためのカスタムプロンプト (`json` モードで使用) |
| `tag`     | `string`   | `null`     | 独立したトラッキング履歴用の識別子                          |

<div id="data-models">
  ### データモデル
</div>

<CodeGroup>
  ```ts TypeScript theme={null}
  interface ChangeTrackingResult {
    previousScrapeAt: string | null;
    changeStatus: "new" | "same" | "changed" | "removed";
    visibility: "visible" | "hidden";
    diff?: {
      text: string;
      json: {
        files: Array<{
          from: string | null;
          to: string | null;
          chunks: Array<{
            content: string;
            changes: Array<{
              type: "add" | "del" | "normal";
              ln?: number;
              ln1?: number;
              ln2?: number;
              content: string;
            }>;
          }>;
        }>;
      };
    };
    json?: Record<string, { previous: any; current: any }>;
  }
  ```

  ```python Python theme={null}
  class ChangeTrackingData(BaseModel):
      previous_scrape_at: Optional[str] = None
      change_status: str  # "new" | "same" | "changed" | "removed"
      visibility: str     # "visible" | "hidden"
      diff: Optional[Dict[str, Any]] = None
      json: Optional[Dict[str, Any]] = None
  ```
</CodeGroup>

<div id="important-details">
  ## 重要な詳細
</div>

<Warning>
  `changeTracking` を使う場合は、必ず `markdown` フォーマットも同時に指定してください。変更追跡は、ページをその markdown コンテンツに基づいて比較します。
</Warning>

* **スナップショットの保持**: スナップショットは永続的に保存され、有効期限はありません。前回のスクレイプから数か月後に再度スクレイプを実行しても、以前のスナップショットと正しく比較されます。
* **スコープ**: 比較はチーム内に限定されます。任意の URL をチームとして初めてスクレイプした場合は、他のユーザーが同じ URL をスクレイプしていても `"new"` が返されます。
* **URL のマッチング**: 過去のスクレイプは、ソース URL、チーム ID、`markdown` フォーマット、`tag` が完全一致したものと照合されます。スクレイプ間で URL を一貫させてください。
* **パラメータの一貫性**: 同じ URL に対して異なる `includeTags`、`excludeTags`、`onlyMainContent` 設定を使うと、比較結果が信頼できなくなります。
* **比較アルゴリズム**: このアルゴリズムは、空白やコンテンツ順序の変化に強く設計されています。CAPTCHA やボット対策によるランダム化に対応するため、iframe のソース URL は無視されます。
* **キャッシュ**: `changeTracking` を指定したリクエストは、インデックス キャッシュをバイパスします。`maxAge` パラメータは無視されます。
* **エラー処理**: レスポンス内の `warning` フィールドを監視し、`changeTracking` オブジェクトが存在しない可能性を考慮して処理してください (これは、前回スクレイプのデータベース検索がタイムアウトした場合に発生することがあります) 。

<div id="billing">
  ## 料金
</div>

| モード            | 料金                        |
| -------------- | ------------------------- |
| 基本的な変更追跡       | 追加料金なし (通常のスクレイプクレジットを使用) |
| `git-diff` モード | 追加料金なし                    |
| `json` モード     | 1ページあたり 5 クレジット           |

> Firecrawl API キーが必要な AI エージェントですか？自動オンボーディング手順については、[firecrawl.dev/agent-onboarding/SKILL.md](https://www.firecrawl.dev/agent-onboarding/SKILL.md) を参照してください。
