AlterLabAlterLab
PricingComparePlaygroundBlogDocs
    AlterLabAlterLab
    PricingPlaygroundBlogDocsChangelog
    IntroductionInstallationYour First Request
    REST APIJob PollingAPI Keys
    OverviewPythonNode.js
    JavaScript RenderingOutput FormatsPDF & OCRCachingWebhooksJSON Schema FilteringWebSocket Real-TimeBring Your Own ProxyProWeb CrawlingBatch ScrapingSchedulerChange DetectionCloud Storage ExportSpend LimitsOrganizations & TeamsAlerts & Notifications
    Structured ExtractionAIE-commerce ScrapingNews MonitoringPrice MonitoringMulti-Page CrawlingMonitoring DashboardAI Agent / MCPMCPData Pipeline to Cloud
    PricingRate LimitsError Codes
    From FirecrawlFrom ApifyFrom ScrapingBee / ScraperAPI
    PlaygroundPricingStatus
    Guide
    New

    Change Detection

    Monitor any webpage for content changes. AlterLab checks your URLs on a schedule, compares snapshots, and notifies you when something changes.

    Built on the Scheduler

    Monitors use the same cron-based scheduling engine as Schedules. The same balance-based limits apply for check intervals and active monitor counts.

    How It Works

    1

    Create

    Define a monitor with a URL, diff mode, check interval, and optional CSS selectors to narrow focus.

    2

    Snapshot

    At each scheduled time, AlterLab scrapes the page and stores a content snapshot with a hash for fast comparison.

    3

    Compare

    The new snapshot is compared against the previous one using your chosen diff mode. If content changed, a change record is created.

    4

    Notify

    When a change is detected (or on every check, depending on your notify_on setting), your webhook receives the diff.

    Create a Monitor

    POST
    /api/v1/monitors
    Bash
    curl -X POST https://api.alterlab.io/api/v1/monitors \
      -H "Authorization: Bearer your_jwt_token" \
      -H "Content-Type: application/json" \
      -d '{
        "name": "Competitor pricing page",
        "url": "https://competitor.com/pricing",
        "diff_mode": "semantic",
        "check_interval": "0 */6 * * *",
        "timezone": "America/New_York",
        "notify_on": "change",
        "webhook_url": "https://your-server.com/monitor-webhook",
        "options": {
          "wait_for": ".pricing-table",
          "timeout": 30
        }
      }'

    Request Body

    ParameterTypeRequiredDescription
    namestringYesHuman-readable name (1-255 chars)
    urlstringYesURL to monitor for changes
    diff_modestringNosemantic (default), exact, or selector
    check_intervalstringNoCron expression (default: 0 */6 * * *)
    timezonestringNoIANA timezone (default: UTC)
    monitor_selectorsstring[]ConditionalCSS selectors to watch (required when diff_mode=selector, max 20)
    notify_onstringNochange (default) or always
    formatsstring[]NoOutput formats: text, markdown, json, html, rag (default: markdown, json)
    optionsobjectNoScrape options: wait_for, timeout, headers, cookies, proxy_country
    webhook_urlstringNoURL to receive change notifications

    Diff Modes

    Choose how content is compared between snapshots. The diff mode determines what counts as a “change” and how the diff is formatted.

    Semantic
    Default

    Compares the structural content of the page, ignoring whitespace changes, ad injection, and layout shifts. Best for tracking meaningful content updates like price changes, product descriptions, or article text.

    JSON
    {
      "diff_mode": "semantic"
    }

    Exact

    Byte-level comparison. Any change in the rendered content triggers a diff. Use when you need to detect every change, including formatting and whitespace.

    JSON
    {
      "diff_mode": "exact"
    }

    Selector

    Monitor specific elements using CSS selectors. Only the matched elements are compared between snapshots. Ideal for tracking a specific price, stock status, or headline without being triggered by unrelated page changes.

    JSON
    {
      "diff_mode": "selector",
      "monitor_selectors": [
        ".product-price",
        ".stock-status",
        "h1.product-title"
      ]
    }

    Selectors Required

    When using diff_mode: selector, you must provide at least one CSS selector in monitor_selectors. Maximum 20 selectors, each up to 500 characters.

    Check Intervals

    Monitors use standard 5-field cron expressions. The same balance-based limits from the Scheduler apply.

    ExpressionSchedule
    */15 * * * *Every 15 minutes
    0 */6 * * *Every 6 hours (default)
    0 9 * * *Every day at 9:00 AM
    0 8 * * 1-5Weekdays at 8:00 AM
    0 0 * * 0Every Sunday at midnight

    Minimum interval depends on your account balance. See Balance-Based Limits for details.

    Manage Monitors

    List Monitors

    GET
    /api/v1/monitors

    Query parameters: limit (1-100, default 20), offset (default 0), active_only (default false).

    Bash
    curl https://api.alterlab.io/api/v1/monitors?active_only=true \
      -H "Authorization: Bearer your_jwt_token"

    Update a Monitor

    PATCH
    /api/v1/monitors/{monitor_id}

    Send only the fields you want to change. Changing check_interval or timezone recomputes next_run_at.

    Bash
    curl -X PATCH https://api.alterlab.io/api/v1/monitors/{monitor_id} \
      -H "Authorization: Bearer your_jwt_token" \
      -H "Content-Type: application/json" \
      -d '{
        "diff_mode": "selector",
        "monitor_selectors": [".price", ".availability"],
        "check_interval": "0 */2 * * *"
      }'

    Pause & Resume

    Bash
    # Pause a monitor
    curl -X POST https://api.alterlab.io/api/v1/monitors/{monitor_id}/pause \
      -H "Authorization: Bearer your_jwt_token"
    
    # Resume (recomputes next_run_at, re-checks balance limits)
    curl -X POST https://api.alterlab.io/api/v1/monitors/{monitor_id}/resume \
      -H "Authorization: Bearer your_jwt_token"

    Delete a Monitor

    DELETE
    /api/v1/monitors/{monitor_id}

    Soft-deletes the monitor (deactivates it). Returns 204 No Content.

    Snapshots

    Every check stores a snapshot of the page content. Use snapshots to review historical versions or compare content at different points in time.

    GET
    /api/v1/monitors/{monitor_id}/snapshots

    Returns a paginated list of snapshots, most recent first. Query parameters: limit (1-100), offset.

    JSON
    {
      "snapshots": [
        {
          "id": "snap-uuid-...",
          "schedule_id": "monitor-uuid-...",
          "run_id": "run-uuid-...",
          "url": "https://competitor.com/pricing",
          "content_hash": "a1b2c3d4...",
          "metadata": { "status_code": 200, "content_length": 42350 },
          "created_at": "2026-03-24T12:00:05Z"
        }
      ],
      "total": 156
    }

    To retrieve the full content of a specific snapshot:

    GET
    /api/v1/monitors/{monitor_id}/snapshots/{snapshot_id}

    Returns the snapshot with the full content field included.

    Changes & Diffs

    When a snapshot differs from the previous one, a change record is created. Each change includes the full diff and references both the previous and current snapshots.

    GET
    /api/v1/monitors/{monitor_id}/diffs

    Returns a paginated list of detected changes, most recent first.

    JSON
    {
      "changes": [
        {
          "id": "change-uuid-...",
          "schedule_id": "monitor-uuid-...",
          "previous_snapshot_id": "snap-old-...",
          "current_snapshot_id": "snap-new-...",
          "url": "https://competitor.com/pricing",
          "change_type": "content_changed",
          "diff": {
            "added": ["Enterprise plan now $299/mo"],
            "removed": ["Enterprise plan now $199/mo"],
            "summary": "Price increase detected on Enterprise plan"
          },
          "notified": true,
          "created_at": "2026-03-24T12:00:06Z"
        }
      ],
      "total": 12
    }

    To retrieve a specific change:

    GET
    /api/v1/monitors/{monitor_id}/diffs/{change_id}

    Notifications

    Configure when your webhook is called using the notify_on parameter:

    ValueBehavior
    changeWebhook fires only when a diff is detected (default)
    alwaysWebhook fires after every check, even when nothing changed

    Tip

    Use notify_on: "always" for uptime monitoring. Your webhook receives a call on every check, so you can detect when a page goes down even if the content hasn't changed.

    Python Example

    Python
    import requests
    
    API_URL = "https://api.alterlab.io/api/v1"
    HEADERS = {
        "Authorization": "Bearer your_jwt_token",
        "Content-Type": "application/json",
    }
    
    # Create a price monitoring watch
    monitor = requests.post(
        f"{API_URL}/monitors",
        headers=HEADERS,
        json={
            "name": "Competitor pricing tracker",
            "url": "https://competitor.com/pricing",
            "diff_mode": "selector",
            "monitor_selectors": [".price-card", ".plan-name"],
            "check_interval": "0 */6 * * *",
            "notify_on": "change",
            "webhook_url": "https://your-server.com/price-alerts",
        },
    ).json()
    
    print(f"Monitor created: {monitor['id']}")
    print(f"Next check: {monitor['next_run_at']}")
    
    # List active monitors
    monitors = requests.get(
        f"{API_URL}/monitors?active_only=true",
        headers=HEADERS,
    ).json()
    
    for m in monitors["monitors"]:
        print(f"  {m['name']} — mode: {m['diff_mode']}, runs: {m['run_count']}")
    
    # Check recent changes
    changes = requests.get(
        f"{API_URL}/monitors/{monitor['id']}/diffs",
        headers=HEADERS,
    ).json()
    
    for c in changes["changes"]:
        print(f"  [{c['created_at']}] {c['change_type']}")
        if "summary" in c["diff"]:
            print(f"    Summary: {c['diff']['summary']}")
    
    # Get snapshot history
    snapshots = requests.get(
        f"{API_URL}/monitors/{monitor['id']}/snapshots?limit=5",
        headers=HEADERS,
    ).json()
    
    for s in snapshots["snapshots"]:
        print(f"  Snapshot {s['id'][:8]}... hash={s['content_hash'][:12]}")

    Node.js Example

    TYPESCRIPT
    const API_URL = "https://api.alterlab.io/api/v1";
    const headers = {
      Authorization: "Bearer your_jwt_token",
      "Content-Type": "application/json",
    };
    
    // Create a monitor with CSS selector tracking
    const monitor = await fetch(`${API_URL}/monitors`, {
      method: "POST",
      headers,
      body: JSON.stringify({
        name: "Competitor pricing tracker",
        url: "https://competitor.com/pricing",
        diff_mode: "selector",
        monitor_selectors: [".price-card", ".plan-name"],
        check_interval: "0 */6 * * *",
        notify_on: "change",
        webhook_url: "https://your-server.com/price-alerts",
      }),
    }).then((r) => r.json());
    
    console.log(`Monitor: ${monitor.id}, next check: ${monitor.next_run_at}`);
    
    // List active monitors
    const list = await fetch(`${API_URL}/monitors?active_only=true`, {
      headers,
    }).then((r) => r.json());
    
    for (const m of list.monitors) {
      console.log(`  ${m.name} — ${m.diff_mode}, ${m.run_count} runs`);
    }
    
    // Get recent changes
    const changes = await fetch(
      `${API_URL}/monitors/${monitor.id}/diffs`,
      { headers }
    ).then((r) => r.json());
    
    for (const c of changes.changes) {
      console.log(`  [${c.created_at}] ${c.change_type}`);
    }
    
    // Browse snapshot history
    const snapshots = await fetch(
      `${API_URL}/monitors/${monitor.id}/snapshots?limit=5`,
      { headers }
    ).then((r) => r.json());
    
    for (const s of snapshots.snapshots) {
      console.log(`  Snapshot ${s.id.slice(0, 8)}... hash=${s.content_hash.slice(0, 12)}`);
    }
    SchedulerCloud Storage Export
    Last updated: March 2026

    On this page

    AlterLabAlterLab

    AlterLab is the modern web scraping platform for developers. Reliable, scalable, and easy to use.

    Product

    • Pricing
    • Documentation
    • Changelog
    • Status

    Solutions

    • Python API
    • JS Rendering
    • Anti-Bot Bypass
    • Compare APIs

    Comparisons

    • Compare All
    • vs ScraperAPI
    • vs Firecrawl
    • vs ScrapingBee
    • vs Bright Data
    • vs Apify

    Company

    • About
    • Blog
    • Contact
    • FAQ

    Guides

    • Bypass Cloudflare
    • Playwright Anti-Detection
    • Puppeteer Bypass Guide
    • Selenium Detection Fix
    • Best Scraping APIs 2026

    Legal

    • Privacy
    • Terms
    • Acceptable Use
    • DPA
    • Cookie Policy
    • Licenses

    © 2026 RapierCraft Inc. All rights reserved.

    Middletown, DE