# Ecommerce Policy Change Monitor (`dabooti/product-policy-monitor`) Actor

Compare shipping, return, warranty and related policy text over time.

- **URL**: https://apify.com/dabooti/product-policy-monitor.md
- **Developed by:** [Danial Maqbool](https://apify.com/dabooti) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 policy checks

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Ecommerce Policy Change Monitor

Compare shipping, return, warranty and related policy text over time.

Example.com inputs are placeholders, not verified compatible content. Replace them with your permitted source. Run npm run smoke for an account-free deterministic example. JSON Feed, RSS and table examples use the separately recorded small live-test sources; they do not imply compatibility with every site.

### What it does

Produces **policy-check** records for merchants tracking competitor policies. Values are extracted deterministically from public pages; unavailable fields remain null.

### Common use cases

Compare shipping, return, warranty and related policy text over time. Use the resulting dataset in scheduled tasks, API pipelines, spreadsheets, or agent workflows.

### Input

| Field | Type | Description |
|---|---|---|
| pageUrls | array | Public HTTP(S) URLs. No credentials or local-network targets. |
| maxPages | integer | Maximum pages scheduled in this bounded run. |
| renderJavaScript | boolean | Opt into Chromium for JavaScript content. More expensive; no access-control bypass. |
| respectRobotsTxt | boolean | Honor robots rules and supported crawl delays. Unavailable rules fail closed. |
| previousContent | object | Baseline map keyed by full URL. Values are previous text snapshots. |
| stateStoreName | string | Optional named key-value store for snapshots shared across sequential runs. Use a separate name per task. |
| policyType | string | Explicit policy classification; otherwise a URL keyword is reported with its source. |
| changeSensitivity | number | Minimum character-based policy change percentage. |
| ignoreSelectors | array | CSS selectors removed before text extraction. |
| onlySelectors | array | Extract text only from these CSS selectors. |
| concurrency | integer | Maximum concurrent page handlers. Per-origin delays still apply. |
| requestDelayMs | integer | Minimum spacing between request starts to the same origin. |
| timeoutSecs | integer | Maximum individual request duration in seconds. |
| retries | integer | Retries for page handlers. Access blocks are not retried. |
| proxyConfiguration | object | Optional Apify or public custom proxy. Direct connections are the default. |

### Output

| Field | Type |
|---|---|
| url | string or null |
| policyType | string or null |
| policyTypeSource | string or null |
| title | string or null |
| currentText | string or null |
| currentContentHash | string or null |
| previousContentHash | string or null |
| changed | boolean or null |
| changePercent | number or null |
| addedTextSummary | string or null |
| removedTextSummary | string or null |
| baselineInitialized | boolean or null |
| diffTruncated | boolean or null |
| checkedAt | string or null |

Results are in the default Dataset. RUN\_SUMMARY, FAILURES and DIAGNOSTICS are available in the default key-value store. Diagnostics are not billed entity events. JSON, CSV and spreadsheet exports use Apify Dataset.

### Example

Replace example.com with a public source relevant to this Actor. Plain example.com has no products, jobs or opportunities; an empty feed there is expected. Run the included local smoke test for a deterministic working example.

```json
{
  "pageUrls": [
    "https://example.com/"
  ],
  "maxPages": 1,
  "renderJavaScript": false
}
```

### Example output

The following records come from synthetic local fixtures, not a live website or claimed customer data.

```json
[
  {
    "url": "https://fixture.example/index",
    "policyType": null,
    "policyTypeSource": null,
    "title": "Fixture catalog",
    "currentText": "Fixture catalogUseful public contentShipping takes five business days. Returns are accepted for thirty days.Free shipping on orders over USD 50.PlanPriceBasic10const fixture = true;Second pageMissing pageRedirected pageTender documentData report",
    "currentContentHash": "21ef5b582ba17ce22612b8db40dfe1587e44cf0dbef863eeeac6618cc523b216",
    "previousContentHash": null,
    "changed": false,
    "changePercent": null,
    "addedTextSummary": "",
    "removedTextSummary": "",
    "baselineInitialized": true,
    "diffTruncated": false,
    "checkedAt": "2026-09-29T23:33:01.078Z"
  }
]
```

### Pricing model

One `policy-check` event per visible result record. Event prices are configured in Apify Console, never in extraction code. The SDK enforces the run's maxTotalChargeUsd. Failed pages and diagnostic-only messages are not billed. Do not configure an additional automatic default-dataset-item event.

### How it works

Crawlee BasicCrawler manages bounded requests and retries. Cheerio parses HTTP HTML. A DNS-pinned transport validates every redirect and checks robots rules. Chromium is opt-in and its page requests pass through the same transport. No external paid API is required.

### Limits

- Summaries are deterministic excerpts of additions and removals, not legal analysis.
- Public GET/HEAD content only; no login, form submission, CAPTCHA solving or browser stealth.
- Responses are capped at 2 MiB decoded. Browser mode caps requests per page and blocks media, fonts, downloads, service workers and WebSockets.
- Missing/blocked robots rules fail closed. Robots crawl delays above 60 seconds are not supported.
- Start at 512 MB for static runs; use 2 GB for browser runs and measure representative targets.

### Responsible use

Use only public content you are authorized to access. Respect source terms, licenses and applicable law. No private-account extraction, personal-data enrichment, credential input or access-control bypass is provided. Cookie values are never returned.

### Local development

Requires Node.js 24 LTS. All commands below run from this Actor directory.

```bash
npm ci --ignore-scripts
npm run input:example
## Edit storage/key_value_stores/default/INPUT.json with your public URLs.
npm run start:dev
npm test
npm run typecheck
npm run lint
npm run validate
npm run build
npm start
npm run smoke
npx apify run
docker build -t product-policy-monitor .
```

Browser testing: set PLAYWRIGHT\_BROWSERS\_PATH to an Actor-local .cache/browsers directory, then run npx playwright install chromium. Docker installs its own matching browser.

### Deployment

Deploy only after validating the Docker build and a representative target. Deployment is not performed by installation or tests.

```bash
npx apify login
npx apify push
```

Then configure the exact event in Console, set pricing and spending limits, test a private run, complete PUBLICATION\_CHECKLIST.md, and deliberately enable Store visibility.

### API usage

Replace YOUR\_USERNAME with your Apify account name. Keep the token in an environment variable rather than input JSON.

```bash
curl -X POST "https://api.apify.com/v2/acts/YOUR_USERNAME~product-policy-monitor/runs?maxTotalChargeUsd=1" -H "Authorization: Bearer $APIFY_TOKEN" -H "Content-Type: application/json" --data-binary @examples/basic-input.json
```

Monitor the returned run ID and read its default Dataset. Store/API names and price configuration are account-side settings.

### Verified platform example

The saved Console input performs a bounded HTTP run with one page and at most two result records. It fetches an explicitly synthetic demonstration fixture from a public Apify key-value store maintained for these examples. These records demonstrate extraction and billing, and are not live commercial data or evidence of compatibility with blocked sites.

Use the saved default input in Apify Console, or the repository examples/basic-input.json. Replace its source with your own permitted URL and keep limits small for the first run.

The following unmodified record was returned by a successful Apify platform run on 2026-09-30:

```json
[
  {
    "url": "https://api.apify.com/v2/key-value-stores/oa2wsF7nVnW6shckK/records/demo-62e50a4884d15159e0b9",
    "policyType": null,
    "policyTypeSource": null,
    "title": "Public synthetic extraction demonstration",
    "currentText": "Synthetic store policiesFree shipping on orders over USD 50. Delivery takes five business days.Returns accepted within 30 days. Contact support for refund conditions.",
    "currentContentHash": "0618b442f8638f4f421a9d9a066b1ed37438ed4409c492f69686129bae2a8ad1",
    "previousContentHash": null,
    "changed": false,
    "changePercent": null,
    "addedTextSummary": "",
    "removedTextSummary": "",
    "baselineInitialized": true,
    "diffTruncated": false,
    "checkedAt": "2026-09-30T13:14:07.956Z"
  }
]
```

Introductory pricing: $2.00 per 1,000 policy-check results, plus Apify platform usage. The standard Actor start event costs $0.00005 per GB (minimum one event). Empty output and duplicate records incur no primary result event; the start fee and any platform usage still apply. The SDK enforces the event spending limit; platform usage is billed separately.

# Actor input Schema

## `pageUrls` (type: `array`):

Public HTTP(S) URLs. No credentials or local-network targets.

## `maxPages` (type: `integer`):

Maximum pages scheduled in this bounded run.

## `renderJavaScript` (type: `boolean`):

Opt into Chromium for JavaScript content. More expensive; no access-control bypass.

## `respectRobotsTxt` (type: `boolean`):

Honor robots rules and supported crawl delays. Unavailable rules fail closed.

## `previousContent` (type: `object`):

Baseline map keyed by full URL. Values are previous text snapshots.

## `stateStoreName` (type: `string`):

Optional named key-value store for snapshots shared across sequential runs. Use a separate name per task.

## `policyType` (type: `string`):

Explicit policy classification; otherwise a URL keyword is reported with its source.

## `changeSensitivity` (type: `number`):

Minimum character-based policy change percentage.

## `ignoreSelectors` (type: `array`):

CSS selectors removed before text extraction.

## `onlySelectors` (type: `array`):

Extract text only from these CSS selectors.

## `concurrency` (type: `integer`):

Maximum concurrent page handlers. Per-origin delays still apply.

## `requestDelayMs` (type: `integer`):

Minimum spacing between request starts to the same origin.

## `timeoutSecs` (type: `integer`):

Maximum individual request duration in seconds.

## `retries` (type: `integer`):

Retries for page handlers. Access blocks are not retried.

## `proxyConfiguration` (type: `object`):

Optional Apify or public custom proxy. Direct connections are the default.

## Actor input object example

```json
{
  "pageUrls": [
    "https://api.apify.com/v2/key-value-stores/oa2wsF7nVnW6shckK/records/demo-62e50a4884d15159e0b9"
  ],
  "maxPages": 1,
  "renderJavaScript": false,
  "respectRobotsTxt": true,
  "changeSensitivity": 0,
  "concurrency": 1,
  "requestDelayMs": 250,
  "timeoutSecs": 20,
  "retries": 2,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

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

No description

## `failures` (type: `string`):

No description

## `diagnostics` (type: `string`):

No description

# 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 = {
    "pageUrls": [
        "https://api.apify.com/v2/key-value-stores/oa2wsF7nVnW6shckK/records/demo-62e50a4884d15159e0b9"
    ],
    "maxPages": 1,
    "renderJavaScript": false,
    "respectRobotsTxt": true,
    "concurrency": 1,
    "timeoutSecs": 20,
    "retries": 0
};

// Run the Actor and wait for it to finish
const run = await client.actor("dabooti/product-policy-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 = {
    "pageUrls": ["https://api.apify.com/v2/key-value-stores/oa2wsF7nVnW6shckK/records/demo-62e50a4884d15159e0b9"],
    "maxPages": 1,
    "renderJavaScript": False,
    "respectRobotsTxt": True,
    "concurrency": 1,
    "timeoutSecs": 20,
    "retries": 0,
}

# Run the Actor and wait for it to finish
run = client.actor("dabooti/product-policy-monitor").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "pageUrls": [
    "https://api.apify.com/v2/key-value-stores/oa2wsF7nVnW6shckK/records/demo-62e50a4884d15159e0b9"
  ],
  "maxPages": 1,
  "renderJavaScript": false,
  "respectRobotsTxt": true,
  "concurrency": 1,
  "timeoutSecs": 20,
  "retries": 0
}' |
apify call dabooti/product-policy-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dabooti/product-policy-monitor"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/GYQfFlMcZDk45SbeX/builds/jKZMgIjEjPG9Pz3ah/openapi.json
