# Structured API & Web Change Feed (`api_web_change_monitor/structured-api-web-change-feed`) Actor

Detect typed JSON, XML, HTML, and text changes with paths, before/after values, type changes, numeric deltas, and automation-ready events.

- **URL**: https://apify.com/api\_web\_change\_monitor/structured-api-web-change-feed.md
- **Developed by:** [API & Web Change Monitor](https://apify.com/api_web_change_monitor) (community)
- **Categories:** Developer tools, Automation
- **Stats:** 1 total users, 0 monthly users, 0.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 web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — 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

### Typed changes, not screenshots

Structured API & Web Change Feed turns JSON, XML, HTML, and text changes into deterministic events that automation can consume directly. Track exactly what changed, where it changed, whether a value changed type, and how far a numeric value moved—without parsing screenshots or natural-language summaries.

Use it for API contract monitoring, competitor pricing, catalog changes, XML feeds, automation pipelines, MCP tools, and scheduled checks.

#### What this Actor produces

- Exact `ADD`, `REMOVE`, and `REPLACE` operations with stable paths.
- Typed `before` and `after` values with `beforeType`, `afterType`, and `typeChanged`.
- Exact decimal `delta` and `percentChange` metadata for numeric changes.
- Identity-aware JSON array comparison that ignores item reordering.
- JSON Pointer, XPath, and CSS selector scoping.
- A versioned event contract with `schemaVersion: 1`.

### Quick start

Run the Actor with one or more public HTTP targets:

```json
{
  "monitorId": "competitor-pricing",
  "targets": [
    {
      "id": "products-api",
      "url": "https://example.com/api/products",
      "type": "JSON",
      "ignoreJsonPointers": ["/generatedAt", "/requestId"],
      "arrayIdentityKeys": {
        "/products": "id"
      }
    }
  ]
}
```

The first successful run creates a baseline and emits `BASELINE_CREATED` with `changed=false`. Run the same monitor again to receive `UNCHANGED` or a typed change event.

#### Example numeric change

```json
{
  "path": "/products/@id=pro/price",
  "operation": "REPLACE",
  "before": 19,
  "after": 25,
  "beforeType": "NUMBER",
  "afterType": "NUMBER",
  "typeChanged": false,
  "numeric": {
    "delta": 6,
    "percentChange": 31.578947
  }
}
```

#### Example API type change

```json
{
  "path": "/id",
  "operation": "REPLACE",
  "before": 123,
  "after": "123",
  "beforeType": "NUMBER",
  "afterType": "STRING",
  "typeChanged": true,
  "numeric": null
}
```

### JSON change detection

Object keys and decimal values are canonicalized before comparison, so formatting and key order do not create false positives. Use `jsonPointer` to monitor a subtree and `ignoreJsonPointers` to exclude volatile fields.

For arrays of entities, map an array path to a direct identity field:

```json
{
  "arrayIdentityKeys": {
    "/products": "id"
  }
}
```

Product order changes then remain `UNCHANGED`, while a product update is reported under a stable path such as `/products/@id=42/price`. Duplicate or missing identities produce explicit error events rather than silently falling back to index comparison.

### XML, HTML, and text

- **XML:** scope content with XPath. The parser removes comments, sorts attributes deterministically, and blocks DOCTYPE, external entities, external DTDs, and external schemas.
- **HTML:** select visible content with `cssSelector` and remove volatile elements with `ignoreSelectors`. Scripts, styles, templates, and comments are excluded by default.
- **Text:** normalize line endings and trailing whitespace while preserving meaningful line structure.

### Automation on Apify

Each target produces exactly one item in the run's default Dataset. Baselines are stored across runs in the named Key-Value Store `structured-api-web-change-feed-state-v1`.

Use Apify schedules for recurring checks, access events through the Dataset API, or connect runs to integrations and automation platforms. Stable event fields mean downstream systems do not need to parse prose.

### Reliability and security

- Supports `ETag`, `Last-Modified`, and HTTP 304 responses.
- Revalidates SSRF rules after every redirect.
- Limits redirects, request duration, retries, concurrency, and decompressed body size.
- Blocks private, loopback, link-local, and metadata addresses, URL credentials, and binary content.
- HTTP and network errors never overwrite the last successful content baseline.
- Logs never include query strings, response bodies, cookies, authorization headers, or Apify tokens.

### Pricing and resource use

The Actor has no additional developer charge. Standard Apify platform usage may apply to runs according to your Apify plan. It is designed for 256 MB memory and uses no browser, proxy, LLM, paid API, or external database.

### Limits

- Public HTTP and HTTPS URLs only.
- Up to 100 targets per run.
- Maximum decompressed response body: 2 MiB per target.
- No JavaScript execution, authenticated pages, screenshots, CAPTCHA handling, or anti-bot bypass.
- JSON identity keys must be direct scalar fields: string, number, or boolean.

### Local development

Without `ACTOR_RUN_ID`, the application starts in local mode:

```bash
cp examples/api-price.json input.json
mvn clean test
mvn package
java -jar target/app.jar
```

Set `APP_INPUT_FILE` to use another input file. Local state is stored under `local-data/state/`, and events are appended to `local-data/results.jsonl`.

```bash
docker build -t structured-api-web-change-feed .
docker run --rm \
  -v "$PWD/input.json:/app/input.json:ro" \
  -v "$PWD/local-data:/app/local-data" \
  structured-api-web-change-feed
```

### FAQ

#### Is this a screenshot monitor?

No. It produces deterministic structured events for APIs, XML, selected HTML text, and plain text.

#### Can it detect breaking API type changes?

Yes. A change such as JSON Number `123` to String `"123"` emits `typeChanged=true`.

#### Will reordered JSON arrays create false positives?

Not when `arrayIdentityKeys` is configured. Items are matched by identity before comparison.

#### Can it calculate price changes?

Yes. Number-to-Number replacements include an exact decimal delta and percentage change. A zero baseline produces `percentChange=null` instead of infinity.

#### Does it support XML?

Yes. It supports XPath scoping, deterministic normalization, and XXE protection.

#### Does it use AI?

No. Normalization and diff results are deterministic.

# Actor input Schema

## `monitorId` (type: `string`):

Stable identifier for a group of baselines across Actor runs.

## `targets` (type: `array`):

Public HTTP targets to check. Maximum 100 targets per run.

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

Maximum number of targets processed at the same time.

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

Timeout for each HTTP request, in seconds.

## `maxResponseBytes` (type: `integer`):

Hard limit for the decompressed response body.

## `resetBaseline` (type: `boolean`):

Replace the baseline after a successful fetch without emitting a diff.

## Actor input object example

```json
{
  "monitorId": "default",
  "concurrency": 5,
  "timeoutSecs": 15,
  "maxResponseBytes": 1048576,
  "resetBaseline": false
}
```

# Actor output Schema

## `results` (type: `string`):

Typed change events stored in the default Dataset.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("api_web_change_monitor/structured-api-web-change-feed").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("api_web_change_monitor/structured-api-web-change-feed").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 '{}' |
apify call api_web_change_monitor/structured-api-web-change-feed --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,api_web_change_monitor/structured-api-web-change-feed"
        }
    }
}

```

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/FzNFeNI2n8Ghg3If9/builds/GtHfPUkR4votqj2ZZ/openapi.json
