# Sitemap Snapshot Diff (`ecomopskits/sitemap-snapshot-diff`) Actor

Compare two saved XML sitemaps without hosting the old snapshot. Paste before/after urlset XML; get added, removed and metadata-changed URLs in one JSON report. USD0.005 per completed comparison.

- **URL**: https://apify.com/ecomopskits/sitemap-snapshot-diff.md
- **Developed by:** [Vladimir Oprea](https://apify.com/ecomopskits) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$5.00 / 1,000 complete sitemap comparisons

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 Snapshot Diff

Compare two saved XML sitemaps before and after a site release or migration.
Paste the old and new `urlset` XML into the input form; you do not need to host
an old copy at a public URL. Get one JSON report with added URLs, removed URLs,
metadata changes and unchanged counts. No page or sitemap URLs are fetched.

### When to use it

Use this for two snapshots of the **same sitemap scope**. For example, compare
an exported product sitemap before a release with its export after the release.
A URL missing from the second snapshot is reported as removed **from that
snapshot**, not as a deleted page, a broken link or a search-indexing change.
If one snapshot is incomplete, the Actor cannot know what was omitted.

### Input

- `beforeXml`: complete earlier XML `urlset` text.
- `afterXml`: complete later XML `urlset` text.

Each input is limited to 2,000,000 UTF-8 bytes and 5,000 `<url>` entries.
Standard sitemap namespace or unnamespaced `urlset` files are accepted.
Sitemap indexes, gzip files, DTDs and custom XML entities are rejected.
Unzip files and supply the matching child urlset yourself where applicable.
Invalid input, excessive size, missing/invalid `loc` or conflicting duplicate
URL metadata fails the entire comparison; it is never silently truncated.
Identical duplicates collapse to one URL, with duplicate counts in the report.

### Reading the report

The default dataset contains **one row per completed comparison**, including
when the two snapshots have no differences. Its `changes` array contains one
object per added, removed or metadata-changed URL. Unchanged URLs are counted,
but are not repeated in the array. Export JSON to preserve this nested structure.
`SUMMARY` records completion, input error or an insufficient run budget.

URLs match by exact `loc` text after XML entity decoding and trimming outer
whitespace. HTTP and HTTPS, www and non-www, path case, query strings and trailing
slashes remain different URLs. `lastmod`, `changefreq` and `priority` compare as
trimmed strings: equivalent dates or numeric formats can appear as changes.
Other sitemap extensions, such as image/video/hreflang data, are ignored.
This is a snapshot comparator, not a full sitemap protocol validator.

Synthetic example: an old snapshot lists `/keep` with lastmod `2026-09-01` and
`/old`; a new snapshot lists `/keep` with lastmod `2026-09-02` and `/new`.
The report has `added: 1`, `removed: 1`, `changed: 1`, `unchanged: 0`.
Use the prefilled synthetic example to see that structure before your own data.

### Price and limits

**USD0.005 per completed comparison report** (USD5 per 1,000 reports), including
reports with zero changes. Platform usage is included. There is no start fee,
per-URL fee or extra dataset-item fee. Invalid-input and insufficient-budget
runs store no comparison report and charge no comparison event. Set a run budget
of at least USD0.005 for one report. Each later completed run is a new report
and charges again, even with the same inputs.

This Actor does not crawl, retain cross-run comparison state, set schedules,
send alerts, rewrite sitemaps or determine SEO impact. You provide both snapshots.
Inputs and output are stored in your Apify run storage under its retention and
access settings. Only submit sitemap data you are authorized to process; omit
credentials, private URLs and sensitive query parameters.

Built by EcomOpsKits. See the [Sitemaps protocol](https://www.sitemaps.org/protocol.html)
for the source XML format. A no-change report only means the compared URL and
supported metadata strings agree; it does not establish site health.

# Actor input Schema

## `beforeXml` (type: `string`):

Use snapshots of the same sitemap scope. Complete XML urlset, up to 2,000,000 UTF-8 bytes and 5,000 URL entries. No private/sensitive URLs.

## `afterXml` (type: `string`):

Use snapshots of the same sitemap scope. Complete XML urlset, up to 2,000,000 UTF-8 bytes and 5,000 URL entries. No private/sensitive URLs.

## Actor input object example

```json
{
  "beforeXml": "<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"><url><loc>https://example.com/keep</loc><lastmod>2026-09-01</lastmod></url><url><loc>https://example.com/old</loc></url></urlset>",
  "afterXml": "<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"><url><loc>https://example.com/keep</loc><lastmod>2026-09-02</lastmod></url><url><loc>https://example.com/new</loc></url></urlset>"
}
```

# Actor output Schema

## `report` (type: `string`):

No description

## `summary` (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 = {
    "beforeXml": "<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"><url><loc>https://example.com/keep</loc><lastmod>2026-09-01</lastmod></url><url><loc>https://example.com/old</loc></url></urlset>",
    "afterXml": "<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"><url><loc>https://example.com/keep</loc><lastmod>2026-09-02</lastmod></url><url><loc>https://example.com/new</loc></url></urlset>"
};

// Run the Actor and wait for it to finish
const run = await client.actor("ecomopskits/sitemap-snapshot-diff").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 = {
    "beforeXml": "<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"><url><loc>https://example.com/keep</loc><lastmod>2026-09-01</lastmod></url><url><loc>https://example.com/old</loc></url></urlset>",
    "afterXml": "<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"><url><loc>https://example.com/keep</loc><lastmod>2026-09-02</lastmod></url><url><loc>https://example.com/new</loc></url></urlset>",
}

# Run the Actor and wait for it to finish
run = client.actor("ecomopskits/sitemap-snapshot-diff").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 '{
  "beforeXml": "<urlset xmlns=\\"http://www.sitemaps.org/schemas/sitemap/0.9\\"><url><loc>https://example.com/keep</loc><lastmod>2026-09-01</lastmod></url><url><loc>https://example.com/old</loc></url></urlset>",
  "afterXml": "<urlset xmlns=\\"http://www.sitemaps.org/schemas/sitemap/0.9\\"><url><loc>https://example.com/keep</loc><lastmod>2026-09-02</lastmod></url><url><loc>https://example.com/new</loc></url></urlset>"
}' |
apify call ecomopskits/sitemap-snapshot-diff --silent --output-dataset

```

## MCP server setup

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

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/0drkAMRz8hgOphLAV/builds/xCbJbtn8Wx0cjvFW9/openapi.json
