# SaaS Pricing Page Monitor — Competitor Price Change Alerts (`joaosbp/competitor-pricing-page-monitor`) Actor

Monitor SaaS competitor pricing pages, detect added and removed price points, store snapshots, and export structured price changes and page diffs.

- **URL**: https://apify.com/joaosbp/competitor-pricing-page-monitor.md
- **Developed by:** [João Victor](https://apify.com/joaosbp) (community)
- **Categories:** SEO tools, Automation, Developer tools
- **Stats:** 2 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-usage

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## SaaS Pricing Page Monitor — Competitor Price Change Alerts

**Monitor SaaS competitor pricing pages, detect added and removed price points, and receive persistent snapshots, structured page diffs, and price change alerts.**

![Apify Actor](https://img.shields.io/badge/Apify-Actor-00c2ff) ![Pricing Monitor](https://img.shields.io/badge/Pricing-Monitor-39ff14) ![SaaS Intelligence](https://img.shields.io/badge/SaaS-Competitive%20Intel-8b5cf6) ![API Ready](https://img.shields.io/badge/API-Ready-f59e0b)

Turn public pricing pages into a recurring competitive-intelligence feed. The Actor monitors competitor prices, plans, packaging, trials, discounts, and CTAs, then writes clean JSON for Apify Schedules, webhooks, Make, n8n, Zapier, Slack alerts, BI dashboards, CRMs, and internal growth workflows.

### Verified in production

- Five live pricing pages processed: Notion, Vercel, Apify, Airtable, and Stripe.
- 5 Dataset rows, 0 item errors.
- Approximately `$0.000224` platform cost per checked page in HTTP mode without proxy.
- Snapshot hashes, price points, and page diffs remained available on successful pages.
- Controlled two-run validation reported `$99` removed, `$49` added, and `$19` unchanged through `pricePointChanges`.

> Cost evidence applies to HTTP mode without proxy. Browser rendering and proxies can materially increase cost.

### Output reliability

| Output | Reliability |
|---|---|
| HTTP status, hashes, timestamps | Deterministic |
| Added/removed normalized text | Primary change evidence |
| `pricePoints` | High-confidence signal that a value appears on the page |
| `pricePointChanges` | Deterministic set comparison against the previous snapshot |
| Currency and billing-period signals | Heuristic |
| `pricingPlans` | Best-effort; review complex usage-based catalogs |

### ⚡ At a glance

| Monitor | Extract | Automate |
|---|---|---|
| SaaS pricing pages | Plan names, prices, currencies | Daily/weekly Apify Schedules |
| Competitor packaging | Billing periods and feature bullets | Webhooks and API pipelines |
| Promotions and offers | Free trials, free plans, discounts | Slack, Make, n8n, Zapier alerts |
| Sales motion | CTAs like trial, demo, contact sales | Dataset exports and dashboards |
| Page changes | Added/removed text and severity | Competitive-intel reports |

### 🎯 Best for

| User | Why they use it |
|---|---|
| SaaS founders | Know when competitors change pricing, packaging, trials, and positioning. |
| Growth teams | Watch discounting, free trials, annual offers, and CTA changes. |
| Product marketers | Track plan names, feature bullets, and go-to-market shifts. |
| Competitive intelligence teams | Build recurring pricing evidence without manual page checks. |
| Automation agencies | Deliver scheduled pricing-monitoring workflows to clients. |

### 🧭 Workflow

```text
Pricing URLs → HTTP/browser fetch → pricing extraction → snapshot diff → Dataset/API/webhook alert
````

Recommended defaults:

- use one named `snapshotStoreName` per monitoring project;
- use a narrow `contentSelector` such as `main` or the pricing container;
- run once with `ALL` to create a baseline, then switch to `CHANGES_ONLY`;
- schedule daily only for urgent competitors; weekly is usually enough;
- enable browser mode only when HTTP mode does not expose the pricing content.

### What this Actor does

1. Accepts one or more public competitor pricing URLs.
2. Fetches pages with cheap HTTP mode by default, with optional Playwright browser rendering for JavaScript-heavy pages.
3. Extracts pricing intelligence:
   - plan/tier names;
   - raw prices and normalized numeric prices;
   - currency codes;
   - billing period: monthly, yearly, one-time, usage-based, or unknown;
   - feature bullets;
   - CTA text;
   - free trial signals;
   - free plan signals;
   - discount/annual-save signals.
4. Stores persistent snapshots in a named key-value store.
5. Compares future runs against previous snapshots.
6. Writes dataset rows with both page-diff fields and pricing-specific fields.
7. Handles one bad URL as an item-level error without failing the whole run.

### Use cases

- Monitor direct competitor pricing pages every day.
- Detect price increases/decreases and packaging changes.
- Track when a competitor adds or removes a free plan.
- Watch for new annual discounts or promo messaging.
- Detect trial/CTA changes such as `Start free trial` → `Contact sales`.
- Feed pricing changes into Slack, Make, Zapier, n8n, Airtable, Sheets, BI, or CRM workflows.
- Build SaaS competitor-intelligence reports for clients.

### Quick start

1. Add competitor pricing URLs.
2. Run once to create the baseline snapshot.
3. Run again later or create an Apify Schedule.
4. Review the Dataset `Pricing overview` and `Extracted plans` views.
5. Connect a webhook if you want alerts on changes.

Minimal input:

```json
{
  "startUrls": [
    { "url": "https://example.com/pricing" }
  ],
  "maxItems": 10,
  "emitMode": "ALL"
}
```

Recommended scheduled input:

```json
{
  "startUrls": [
    { "url": "https://competitor-a.com/pricing" },
    { "url": "https://competitor-b.com/pricing" },
    { "url": "https://competitor-c.com/pricing" }
  ],
  "snapshotStoreName": "my-saas-pricing-monitor",
  "contentSelector": "main",
  "emitMode": "CHANGES_ONLY",
  "useBrowser": false,
  "proxy": { "useApifyProxy": false }
}
```

### Example output

```json
{
  "url": "https://example.com/pricing",
  "finalUrl": "https://example.com/pricing",
  "title": "Pricing | Example SaaS",
  "changeType": "CHANGED",
  "severity": "MEDIUM",
  "isSignificant": true,
  "changeRatio": 0.12,
  "hasPricing": true,
  "planCount": 2,
  "pricePoints": ["$19", "$99"],
  "pricePointChanges": {
    "added": ["$99"],
    "removed": ["$49"],
    "unchanged": ["$19"]
  },
  "currencies": ["USD"],
  "billingPeriods": ["monthly"],
  "hasFreeTrial": true,
  "hasFreePlan": false,
  "hasDiscount": true,
  "ctaTexts": ["Start free trial", "Book a demo"],
  "pricingPlans": [
    {
      "name": "Starter",
      "rawPrice": "$19",
      "price": 19,
      "currency": "USD",
      "billingPeriod": "monthly",
      "features": ["1 workspace", "Email support"],
      "ctaText": "Start free trial",
      "hasFreeTrial": true,
      "hasFreePlan": false,
      "hasDiscount": false
    }
  ],
  "addedText": "Business $99 per month Priority support Contact sales",
  "removedText": "Pro $49 per month Email support Start free trial",
  "snapshotKey": "SNAPSHOT_...",
  "source": "http",
  "error": null
}
```

### Dataset views

| View | Purpose |
|---|---|
| `Pricing overview` | High-level rows with change status, prices, currencies, billing periods, trial/free/discount signals, and CTAs. |
| `Extracted plans` | Full extracted `pricingPlans` array for each URL. |
| `Diff details` | Added/removed text for comparing current and previous snapshots. |
| `Technical details` | Final URL, hashes, snapshot keys, source mode, and content size. |

### Accuracy notes

Pricing pages vary a lot. This Actor uses robust heuristics, not fragile site-specific selectors. It works best on public SaaS pricing pages with visible plan cards and price text. For JavaScript-heavy pages, enable browser mode. For highly custom pages, set `contentSelector` to the pricing container such as `.pricing`, `main`, or `[data-testid="pricing"]`.

### Cost controls

- HTTP mode is default and cheapest.
- Proxy is disabled by default.
- Browser rendering is optional.
- `maxContentBytes`, `maxItems`, `maxConcurrency`, retries, and per-item errors protect cost and memory.
- Private/internal URLs are blocked by default for SSRF protection.

### API usage

Run this Actor through Apify API, CLI, Tasks, Schedules, webhooks, Make, n8n, Zapier, or your own backend.

### FAQ

#### Does this Actor require login?

No. It is designed for public pricing pages.

#### Does it use browser automation?

Not by default. HTTP mode is faster and cheaper. Enable browser mode only for JavaScript-rendered pricing pages.

#### Can it tell me exactly which price changed?

It exports current `pricePoints`, direct `pricePointChanges.added/removed/unchanged`, best-effort `pricingPlans`, and text diffs. Automations can alert on exact raw price values without comparing complete Dataset rows. `pricePoints`, `pricePointChanges`, and snapshot diffs are the authoritative monitoring signals; `pricingPlans` is a heuristic convenience field and can misclassify product or usage-fee labels on complex pages such as payment platforms.

#### Can I monitor many competitors?

Yes. Add multiple URLs and use `maxConcurrency` to control parallelism.

#### Should I use proxy?

Usually no. Keep proxy disabled unless a target site blocks normal HTTP requests.

#### Can I schedule it?

Yes. Save your input as an Apify Task and attach an Apify Schedule.

#### Can I use the output in automations?

Yes. Results are written to an Apify Dataset and can be consumed by API, webhooks, Make, n8n, Zapier, Slack, Airtable, Sheets, BI tools, or internal workflows.

### Support

If you need a custom version, open an issue or contact the Actor maintainer through Apify.

# Actor input Schema

## `startUrls` (type: `array`):

Public URLs for Competitor Pricing Page Monitor. The Actor stores snapshots and compares future runs against them.

## `snapshotStoreName` (type: `string`):

Named key-value store used to persist previous snapshots across runs. Use a different store per monitoring project.

## `maxItems` (type: `integer`):

Safety limit for how many URLs are processed in one run.

## `maxConcurrency` (type: `integer`):

Maximum number of URLs processed in parallel. Keep low for browser mode to reduce memory and compute cost.

## `extractionMode` (type: `string`):

Choose what should be compared. Visible text is best for most business monitoring. HTML is stricter. Metadata compares title, description, headings, and links.

## `contentSelector` (type: `string`):

Optional CSS selector to monitor only one part of the page, such as main, article, .pricing, or #content. Leave empty to monitor the body.

## `excludeSelectors` (type: `array`):

CSS selectors removed before comparison. Use this for navbars, footers, cookie banners, ads, timestamps, or dynamic widgets.

## `ignoreRegexes` (type: `array`):

Advanced: regex patterns removed from content before comparison. Useful for dates, counters, session IDs, ad slots, or personalization noise.

## `ignoreWhitespace` (type: `boolean`):

Collapse repeated whitespace before comparison so formatting-only changes do not create noisy alerts.

## `ignoreCase` (type: `boolean`):

Convert content to lowercase before comparison so capitalization-only changes are ignored.

## `ignoreNumbers` (type: `boolean`):

Replace numbers with a placeholder before comparison. Keep disabled when monitoring prices, quantities, metrics, or version numbers.

## `ignoreDates` (type: `boolean`):

Replace common date formats with a placeholder before comparison so last-updated timestamps do not create noisy alerts.

## `significantChangeThreshold` (type: `number`):

Minimum changed-content ratio required to mark a change as significant. 0.05 means roughly 5% of comparable text changed.

## `emitMode` (type: `string`):

ALL writes a row for every monitored URL. CHANGES\_ONLY writes first-seen and changed pages. SIGNIFICANT\_ONLY writes only significant changes and errors.

## `saveHtmlSnapshot` (type: `boolean`):

Store raw HTML in the snapshot key-value store. Useful for evidence, but increases storage usage.

## `updateSnapshots` (type: `boolean`):

Disable for dry runs. If disabled, the Actor compares against current stored snapshots without replacing them.

## `maxDiffCharacters` (type: `integer`):

Maximum number of characters kept in addedText and removedText fields to keep dataset rows compact.

## `useBrowser` (type: `boolean`):

Render pages with Playwright for JavaScript-heavy sites. Disabled by default to keep runs fast and cheap.

## `maxRetries` (type: `integer`):

Number of retry attempts for transient network, timeout, 429, or 5xx errors.

## `requestTimeoutSecs` (type: `integer`):

Maximum time in seconds to wait for each page request or browser navigation.

## `maxContentBytes` (type: `integer`):

Maximum response size read per URL. Default supports most modern pricing/docs pages while still stopping very large responses to protect memory and storage costs.

## `allowPrivateUrls` (type: `boolean`):

Allow localhost, private IP ranges, and internal DNS targets. Keep disabled for public scraping to reduce SSRF risk.

## `proxy` (type: `object`):

Optional Apify Proxy configuration. Most public pages do not need proxy.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://example.com/pricing"
    }
  ],
  "snapshotStoreName": "competitor-pricing-page-monitor-snapshots",
  "maxItems": 10,
  "maxConcurrency": 3,
  "extractionMode": "VISIBLE_TEXT",
  "excludeSelectors": [
    "script",
    "style",
    "noscript",
    "svg",
    "iframe",
    "nav",
    "footer",
    "[aria-hidden=\"true\"]",
    ".cookie",
    ".cookies",
    "#cookie",
    "#cookies"
  ],
  "ignoreRegexes": [],
  "ignoreWhitespace": true,
  "ignoreCase": false,
  "ignoreNumbers": false,
  "ignoreDates": true,
  "significantChangeThreshold": 0.05,
  "emitMode": "ALL",
  "saveHtmlSnapshot": false,
  "updateSnapshots": true,
  "maxDiffCharacters": 2000,
  "useBrowser": false,
  "maxRetries": 2,
  "requestTimeoutSecs": 20,
  "maxContentBytes": 2000000,
  "allowPrivateUrls": false,
  "proxy": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `datasetItems` (type: `string`):

Structured change detection results.

## `summary` (type: `string`):

Counts of processed, emitted, changed, significant, unchanged, first-seen, and failed pages.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "startUrls": [
        {
            "url": "https://example.com/pricing"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("joaosbp/competitor-pricing-page-monitor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "startUrls": [{ "url": "https://example.com/pricing" }] }

# Run the Actor and wait for it to finish
run = client.actor("joaosbp/competitor-pricing-page-monitor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "startUrls": [
    {
      "url": "https://example.com/pricing"
    }
  ]
}' |
apify call joaosbp/competitor-pricing-page-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=joaosbp/competitor-pricing-page-monitor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "SaaS Pricing Page Monitor — Competitor Price Change Alerts",
        "description": "Monitor SaaS competitor pricing pages, detect added and removed price points, store snapshots, and export structured price changes and page diffs.",
        "version": "0.2",
        "x-build-id": "ag0ivjJbZhalVXUOs"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/joaosbp~competitor-pricing-page-monitor/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-joaosbp-competitor-pricing-page-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/joaosbp~competitor-pricing-page-monitor/runs": {
            "post": {
                "operationId": "runs-sync-joaosbp-competitor-pricing-page-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/joaosbp~competitor-pricing-page-monitor/run-sync": {
            "post": {
                "operationId": "run-sync-joaosbp-competitor-pricing-page-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "startUrls"
                ],
                "properties": {
                    "startUrls": {
                        "title": "Pages to monitor",
                        "type": "array",
                        "description": "Public URLs for Competitor Pricing Page Monitor. The Actor stores snapshots and compares future runs against them.",
                        "items": {
                            "type": "object",
                            "required": [
                                "url"
                            ],
                            "properties": {
                                "url": {
                                    "type": "string",
                                    "title": "URL of a web page",
                                    "format": "uri"
                                }
                            }
                        }
                    },
                    "snapshotStoreName": {
                        "title": "Snapshot store name",
                        "type": "string",
                        "description": "Named key-value store used to persist previous snapshots across runs. Use a different store per monitoring project.",
                        "default": "competitor-pricing-page-monitor-snapshots"
                    },
                    "maxItems": {
                        "title": "Maximum pages per run",
                        "minimum": 1,
                        "maximum": 5000,
                        "type": "integer",
                        "description": "Safety limit for how many URLs are processed in one run.",
                        "default": 10
                    },
                    "maxConcurrency": {
                        "title": "Max concurrency",
                        "minimum": 1,
                        "maximum": 10,
                        "type": "integer",
                        "description": "Maximum number of URLs processed in parallel. Keep low for browser mode to reduce memory and compute cost.",
                        "default": 3
                    },
                    "extractionMode": {
                        "title": "Extraction mode",
                        "enum": [
                            "VISIBLE_TEXT",
                            "HTML",
                            "METADATA"
                        ],
                        "type": "string",
                        "description": "Choose what should be compared. Visible text is best for most business monitoring. HTML is stricter. Metadata compares title, description, headings, and links.",
                        "default": "VISIBLE_TEXT"
                    },
                    "contentSelector": {
                        "title": "Content CSS selector",
                        "type": "string",
                        "description": "Optional CSS selector to monitor only one part of the page, such as main, article, .pricing, or #content. Leave empty to monitor the body."
                    },
                    "excludeSelectors": {
                        "title": "Exclude CSS selectors",
                        "type": "array",
                        "description": "CSS selectors removed before comparison. Use this for navbars, footers, cookie banners, ads, timestamps, or dynamic widgets.",
                        "default": [
                            "script",
                            "style",
                            "noscript",
                            "svg",
                            "iframe",
                            "nav",
                            "footer",
                            "[aria-hidden=\"true\"]",
                            ".cookie",
                            ".cookies",
                            "#cookie",
                            "#cookies"
                        ],
                        "items": {
                            "type": "string"
                        }
                    },
                    "ignoreRegexes": {
                        "title": "Ignore regex patterns",
                        "type": "array",
                        "description": "Advanced: regex patterns removed from content before comparison. Useful for dates, counters, session IDs, ad slots, or personalization noise.",
                        "default": [],
                        "items": {
                            "type": "string"
                        }
                    },
                    "ignoreWhitespace": {
                        "title": "Ignore whitespace changes",
                        "type": "boolean",
                        "description": "Collapse repeated whitespace before comparison so formatting-only changes do not create noisy alerts.",
                        "default": true
                    },
                    "ignoreCase": {
                        "title": "Ignore letter casing",
                        "type": "boolean",
                        "description": "Convert content to lowercase before comparison so capitalization-only changes are ignored.",
                        "default": false
                    },
                    "ignoreNumbers": {
                        "title": "Ignore number changes",
                        "type": "boolean",
                        "description": "Replace numbers with a placeholder before comparison. Keep disabled when monitoring prices, quantities, metrics, or version numbers.",
                        "default": false
                    },
                    "ignoreDates": {
                        "title": "Ignore date changes",
                        "type": "boolean",
                        "description": "Replace common date formats with a placeholder before comparison so last-updated timestamps do not create noisy alerts.",
                        "default": true
                    },
                    "significantChangeThreshold": {
                        "title": "Significant change threshold",
                        "minimum": 0,
                        "maximum": 1,
                        "type": "number",
                        "description": "Minimum changed-content ratio required to mark a change as significant. 0.05 means roughly 5% of comparable text changed.",
                        "default": 0.05
                    },
                    "emitMode": {
                        "title": "Dataset output mode",
                        "enum": [
                            "ALL",
                            "CHANGES_ONLY",
                            "SIGNIFICANT_ONLY"
                        ],
                        "type": "string",
                        "description": "ALL writes a row for every monitored URL. CHANGES_ONLY writes first-seen and changed pages. SIGNIFICANT_ONLY writes only significant changes and errors.",
                        "default": "ALL"
                    },
                    "saveHtmlSnapshot": {
                        "title": "Save HTML snapshots",
                        "type": "boolean",
                        "description": "Store raw HTML in the snapshot key-value store. Useful for evidence, but increases storage usage.",
                        "default": false
                    },
                    "updateSnapshots": {
                        "title": "Update stored snapshots",
                        "type": "boolean",
                        "description": "Disable for dry runs. If disabled, the Actor compares against current stored snapshots without replacing them.",
                        "default": true
                    },
                    "maxDiffCharacters": {
                        "title": "Maximum diff characters",
                        "minimum": 100,
                        "maximum": 10000,
                        "type": "integer",
                        "description": "Maximum number of characters kept in addedText and removedText fields to keep dataset rows compact.",
                        "default": 2000
                    },
                    "useBrowser": {
                        "title": "Render pages with browser",
                        "type": "boolean",
                        "description": "Render pages with Playwright for JavaScript-heavy sites. Disabled by default to keep runs fast and cheap.",
                        "default": false
                    },
                    "maxRetries": {
                        "title": "Maximum retries",
                        "minimum": 0,
                        "maximum": 5,
                        "type": "integer",
                        "description": "Number of retry attempts for transient network, timeout, 429, or 5xx errors.",
                        "default": 2
                    },
                    "requestTimeoutSecs": {
                        "title": "Request timeout seconds",
                        "minimum": 5,
                        "maximum": 120,
                        "type": "integer",
                        "description": "Maximum time in seconds to wait for each page request or browser navigation.",
                        "default": 20
                    },
                    "maxContentBytes": {
                        "title": "Max content bytes",
                        "minimum": 50000,
                        "maximum": 5000000,
                        "type": "integer",
                        "description": "Maximum response size read per URL. Default supports most modern pricing/docs pages while still stopping very large responses to protect memory and storage costs.",
                        "default": 2000000
                    },
                    "allowPrivateUrls": {
                        "title": "Allow private/internal URLs",
                        "type": "boolean",
                        "description": "Allow localhost, private IP ranges, and internal DNS targets. Keep disabled for public scraping to reduce SSRF risk.",
                        "default": false
                    },
                    "proxy": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Optional Apify Proxy configuration. Most public pages do not need proxy.",
                        "default": {
                            "useApifyProxy": false
                        }
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
