# Sitemap Diff — Added, Removed & Changed URLs (`gertner-data/sitemap-delta`) Actor

Turn sitemap changes into actionable URL events. Detect added, removed and changed pages for crawl queues, SEO monitoring and content-sync workflows. Launch price: $0.0005/URL result plus $0.001 start; platform usage included.

- **URL**: https://apify.com/gertner-data/sitemap-delta.md
- **Developed by:** [Евгений Гертнер](https://apify.com/gertner-data) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 1,000 url results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Sitemap Diff — Added, Removed & Changed URLs

Turn XML sitemap updates into **ready-to-route URL events** for SEO monitoring, crawl queues and incremental RAG updates. Get `added`, `removed`, `changed` and `unchanged` records in structured JSON or CSV.

- **Up to 50,000 matching URLs** and 100 sitemap files per run.
- **Nested indexes, gzip and XML namespaces** supported.
- **Launch price: $0.50 per 1,000 output rows**, plus $0.001 run start; platform usage included.
- **Reusable snapshots** make comparisons reproducible in your API workflow.
- **Incomplete-scan protection** keeps temporary source failures out of removal decisions.

### Start with an inventory

```json
{"sitemapUrls":["https://www.sitemaps.org/sitemap.xml"],"maxUrls":10000,"maxSitemaps":30}
```

Each dataset row contains `url`, `lastmod`, `changefreq`, `priority`, `sourceSitemap`, `change` and `observedAt`. A first run uses `change: "current"`.

Download `SNAPSHOT` from the run's key-value store. Pass that JSON object as `previousSnapshot` on the next call, with the same sitemap URLs and `urlContains` filter. Your workflow owns the snapshot and can automate the entire comparison.

```python
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
actor = client.actor("gertner-data/sitemap-delta")
first = actor.call(run_input={"sitemapUrls": ["https://www.sitemaps.org/sitemap.xml"]})
snapshot = client.key_value_store(first["defaultKeyValueStoreId"]).get_record("SNAPSHOT")["value"]
second = actor.call(run_input={"sitemapUrls": ["https://www.sitemaps.org/sitemap.xml"], "previousSnapshot": snapshot})
for row in client.dataset(second["defaultDatasetId"]).iterate_items():
    if row["change"] != "unchanged":
        print(row["change"], row["url"])
```

### Route the changes

- `added`: enqueue a newly listed URL for crawling or indexing.
- `changed`: re-check a URL with updated `lastmod`, `changefreq` or `priority`.
- `removed`: a URL left the sitemap inventory; both snapshots must be complete and cover the same scope.
- `unchanged`: retain the existing inventory record.

The comparison operates on sitemap membership and metadata. Page availability and page-body changes belong to separate URL checks.

### API coverage and run settings

Supply 1–10 root sitemaps. Configure 1–100 sitemap files and up to 50,000 unique matching URLs. Downloaded or expanded XML is capped at 8 MB per file; inventory output at 6 MB. Nested sitemap hosts must match a supplied root. Use the final host directly when a root redirects between hosts. Supports sources compatible with identity HTTP encoding and explicit `.gz` sitemap files.

`urlContains` is a case-sensitive substring filter. Deduplication removes fragments and preserves exact URL identities. Dates retain the sitemap's original values.

`SUMMARY.complete`, `SUMMARY.errors` and `SUMMARY.removalsEvaluated` describe scan coverage. Source errors, malformed XML, conflicting duplicates and inventory limits suppress removal evaluation. A complete empty inventory can remove every URL from a previous complete inventory. At the spending cap, `SNAPSHOT` is withheld to preserve the last complete baseline.

Inputs and results use your Apify account's retention settings. Logs contain aggregates; snapshots contain the inventory URLs needed for comparison. Use public sources you are authorized to inspect.

### Pricing

**Launch price: $0.001 per run + $0.0005 per emitted URL row**, including unchanged and removed rows. Platform usage is included.

| Output rows | Event price |
| --- | --- |
| 84 | $0.043 |
| 1,000 | $0.501 |

Set a maximum run charge to control output spending. The run-start event applies independently of output count.

### Connect your workflow

Use the Apify API, tasks, schedules, webhooks or MCP integration. Pass the prior snapshot automatically between runs. Default memory: 512 MB. Recommended timeout: 300 seconds. Network failures, 429 and 5xx responses receive bounded retries.

Support: [Evgeny Gertner](https://t.me/evgertner).

# Actor input Schema

## `sitemapUrls` (type: `array`):

One to ten public sitemap or sitemap-index URLs. Nested sitemaps must use the same host as a supplied root.

## `maxUrls` (type: `integer`):

Maximum unique matching URLs. Hitting the cap marks the snapshot incomplete.

## `maxSitemaps` (type: `integer`):

Bound on sitemap downloads, including index files.

## `urlContains` (type: `string`):

Optional case-sensitive substring filter. Use the same filter for snapshot comparisons.

## `previousSnapshot` (type: `object`):

Optional complete SNAPSHOT JSON object from an earlier run. Copy via API for automated comparisons. Omit for an inventory.

## Actor input object example

```json
{
  "sitemapUrls": [
    "https://www.sitemaps.org/sitemap.xml"
  ],
  "maxUrls": 10000,
  "maxSitemaps": 30,
  "urlContains": ""
}
```

# Actor output Schema

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

No description

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

No description

## `snapshot` (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 = {
    "sitemapUrls": [
        "https://www.sitemaps.org/sitemap.xml"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("gertner-data/sitemap-delta").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 = { "sitemapUrls": ["https://www.sitemaps.org/sitemap.xml"] }

# Run the Actor and wait for it to finish
run = client.actor("gertner-data/sitemap-delta").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 '{
  "sitemapUrls": [
    "https://www.sitemaps.org/sitemap.xml"
  ]
}' |
apify call gertner-data/sitemap-delta --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,gertner-data/sitemap-delta"
        }
    }
}
```

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/GY79BxQjGqQj9PyJ3/builds/r5hDxsbHKihzDZsWY/openapi.json
