# JSON Diff Tool (`automation-lab/json-diff-tool`) Actor

Semantically compare two JSON objects or files. Outputs a structured diff with dot-notation paths for every added, removed, changed, and type-changed field. Supports nested objects, arrays, URL fetching, and ignore lists.

- **URL**: https://apify.com/automation-lab/json-diff-tool.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Developer tools, Other
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, NaN bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

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

## JSON Diff Tool

> Semantically compare two JSON objects or JSON files and get a structured, machine-readable diff — showing every added, removed, changed, and type-changed field with its exact dot-notation path.

---

### 🔍 What does it do?

JSON Diff Tool takes two JSON inputs (inline text or URLs to JSON endpoints) and produces a **semantic diff** — a structured list of every difference between them. Unlike text-diff tools that compare line by line, this actor understands JSON structure: it recurses into nested objects, tracks array indices, detects type changes (e.g. number → string), and outputs each change as a clean, queryable dataset row.

Every change is reported with:
- **Change type**: `added`, `removed`, `changed`, or `type-changed`
- **Dot-notation path**: e.g. `address.zip`, `users[2].email`, `config.retries`
- **Value A** (before) and **Value B** (after)
- **Type A** and **Type B** (e.g. `number`, `string`, `boolean`, `object`, `array`, `null`)

---

### 👤 Who is it for?

**Developers and QA engineers** who need to compare API responses between environments (staging vs production) to catch regressions before they reach users.

**Data engineers** who ingest JSON config files or API snapshots and need to audit what changed between two versions.

**DevOps and release engineers** who track changes in JSON configuration files (feature flags, infrastructure manifests, app settings) as part of change management workflows.

**Product managers and analysts** who receive JSON exports from tools (Mixpanel, Amplitude, Salesforce) and need to understand what records changed between two data pulls.

---

### 💡 Why use it?

- **Semantic, not textual** — compares JSON meaning, not raw text. Whitespace and key ordering differences don't create false positives.
- **Structured output** — each change is a dataset row with `changeType`, `path`, `valueA`, `valueB`, `typeA`, `typeB`. Filter, sort, and query with the Apify dataset API.
- **Nested objects and arrays** — recurse arbitrarily deep. Array changes are tracked by index (or by content if you enable unordered comparison).
- **Type-change detection** — flags when a value changes type (e.g. `"42"` → `42`), which breaks APIs silently.
- **Flexible inputs** — inline JSON text or any HTTPS URL serving JSON (APIs, S3 buckets, GitHub raw files, CDN endpoints).
- **Ignore keys** — exclude volatile fields like `updatedAt`, `requestId`, or `sessionToken` from comparison.
- **Two output modes** — `flat` (one row per change, great for Apify tables) or `summary` (single row with all changes grouped, great for webhook payloads).
- **No proxy, no scraping** — pure utility. No bandwidth costs beyond a simple HTTP fetch.

---

### 📊 Data you get

| Field | Type | Description |
|-------|------|-------------|
| `changeType` | string | `added`, `removed`, `changed`, `type-changed`, or `identical` |
| `path` | string | Dot-notation path to the changed field (e.g. `user.address.zip`) |
| `valueA` | string | Serialized value from JSON A (before/left), or `null` if added |
| `valueB` | string | Serialized value from JSON B (after/right), or `null` if removed |
| `typeA` | string | JSON type of value A: `string`, `number`, `boolean`, `object`, `array`, `null` |
| `typeB` | string | JSON type of value B |

In `summary` mode, a single record also includes `totalChanges`, `added`, `removed`, `changed`, `typeChanged`, and `identical` (boolean).

---

### 💰 How much does it cost to diff two JSON files?

Pricing is per-run (pay-per-event):

| Event | FREE tier | DIAMOND tier |
|-------|-----------|--------------|
| Run start | $0.005 | $0.0025 |
| Diff computed | $0.001 | $0.0005 |

**Typical cost per comparison:** $0.006 (FREE tier) — less than $0.01 per diff regardless of JSON size or depth.

There is no per-item charge based on number of differences found. You pay a flat fee per comparison run. For high-volume automated workflows (hundreds of diffs per day), DIAMOND tier pricing applies automatically.

**Free plan:** Apify's free tier includes enough credits to run dozens of comparisons per month at no cost.

---

### 🚀 How to use it

#### Step 1: Open the actor

Go to [JSON Diff Tool on Apify Store](https://apify.com/automation-lab/json-diff-tool) and click **Try for free**.

#### Step 2: Provide your two JSON sources

You have four options:
- Paste JSON A directly into the **JSON A (inline)** field
- Enter a URL in **URL A** (fetched at runtime — ideal for API endpoints)
- Mix: inline for one, URL for the other

#### Step 3: Choose output mode

- **Flat** (default): one dataset row per change — easiest to filter in Apify Console
- **Summary**: single row with all changes grouped — ideal for webhook integration

#### Step 4: Configure options (optional)

- **Ignore array order**: enable to compare arrays as sets (useful for tags, permissions lists)
- **Ignore keys**: exclude volatile keys like `updatedAt`, `requestId`, `etag`
- **Max depth**: limit recursion for very large deeply nested objects

#### Step 5: Run and inspect results

Results appear in the **Dataset** tab. Use the Apify API or export to JSON, CSV, or Excel.

---

### ⚙️ Input parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `jsonA` | string | One of jsonA/urlA | — | First JSON object as inline text |
| `urlA` | string | One of jsonA/urlA | — | URL to fetch first JSON from |
| `jsonB` | string | One of jsonB/urlB | — | Second JSON object as inline text |
| `urlB` | string | One of jsonB/urlB | — | URL to fetch second JSON from |
| `outputMode` | select | No | `flat` | `flat` (one row/change) or `summary` (grouped) |
| `ignoreArrayOrder` | boolean | No | `false` | Treat arrays as unordered sets |
| `ignoreKeys` | array | No | `[]` | Dot-notation paths to ignore (e.g. `meta.updatedAt`) |
| `maxDepth` | integer | No | `0` (unlimited) | Max recursion depth (0 = unlimited) |

---

### 📤 Output examples

#### Flat mode (default)

```json
[
  { "changeType": "removed", "path": "active", "valueA": "true", "valueB": null, "typeA": "boolean", "typeB": null },
  { "changeType": "added", "path": "score", "valueA": null, "valueB": "42", "typeA": null, "typeB": "number" },
  { "changeType": "changed", "path": "age", "valueA": "30", "valueB": "31", "typeA": "number", "typeB": "number" },
  { "changeType": "added", "path": "address.country", "valueA": null, "valueB": "UK", "typeA": null, "typeB": "string" },
  { "changeType": "changed", "path": "address.zip", "valueA": "SW1A", "valueB": "SW1B", "typeA": "string", "typeB": "string" },
  { "changeType": "changed", "path": "tags[1]", "valueA": "user", "valueB": "superuser", "typeA": "string", "typeB": "string" }
]
````

#### Summary mode

```json
{
  "totalChanges": 6,
  "added": 2,
  "removed": 1,
  "changed": 3,
  "typeChanged": 0,
  "identical": false,
  "changes": [ ... ]
}
```

#### Identical JSON

When both inputs are identical, flat mode outputs a single row with `changeType: "identical"` so your downstream integrations always receive at least one row.

***

### 💡 Tips and tricks

**Comparing API staging vs production**: Enter your staging endpoint in URL A and production in URL B. Schedule daily runs and use webhooks to alert on unexpected changes.

**Ignoring timestamps**: Add `updatedAt`, `meta.requestId`, and `_etag` to the **Ignore keys** list to avoid noise from auto-updated fields.

**Detecting type regressions**: Type-changed entries (e.g. `price` changing from `number` to `string`) are your highest-priority changes — they silently break downstream consumers.

**Large JSON objects**: Use `maxDepth: 3` to get a shallow diff of top-level and second-level changes first, then drill down to specific paths if needed.

**Array order sensitivity**: Enable **Ignore array order** for tags, roles, or permission lists where order doesn't matter. Keep it disabled for ordered lists like steps, timelines, or ranked results.

***

### 🔗 Integrations

**Slack alerts for API drift**: Connect to Zapier or Make (Integromat) — when `totalChanges > 0` in the dataset, trigger a Slack message listing the changed paths.

**GitHub Actions CI/CD**: Call this actor via the Apify API in your deployment pipeline to diff your API's response schema between the new build and main branch before merging.

**Webhook-driven monitoring**: Set a webhook on actor completion, receive the summary payload, and route to PagerDuty if any `type-changed` events are detected.

**Data pipeline validation**: In your ETL, call this actor to diff two JSON exports before writing to your data warehouse, catching upstream schema drift early.

**Configuration change auditing**: Store your app's JSON config in S3 or GitHub. Point URL A to the previous version and URL B to the latest — run nightly to produce a change log.

***

### 🤖 API usage

#### Node.js

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

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });

const run = await client.actor('automation-lab/json-diff-tool').call({
    jsonA: JSON.stringify({ name: 'Alice', age: 30, active: true }),
    jsonB: JSON.stringify({ name: 'Alice', age: 31, active: false }),
    outputMode: 'flat',
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log('Changes:', items);
```

#### Python

```python
from apify_client import ApifyClient
import json

client = ApifyClient(token='YOUR_APIFY_TOKEN')

run = client.actor('automation-lab/json-diff-tool').call(run_input={
    'jsonA': json.dumps({'name': 'Alice', 'age': 30, 'active': True}),
    'jsonB': json.dumps({'name': 'Alice', 'age': 31, 'active': False}),
    'outputMode': 'flat',
})

items = client.dataset(run['defaultDatasetId']).list_items().items
for change in items:
    print(f"{change['changeType']}: {change['path']} — {change['valueA']} → {change['valueB']}")
```

#### cURL

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~json-diff-tool/runs?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonA": "{\"name\": \"Alice\", \"age\": 30}",
    "jsonB": "{\"name\": \"Alice\", \"age\": 31}",
    "outputMode": "flat"
  }'
```

***

### 🧩 Use with Claude and MCP

Connect JSON Diff Tool to Claude for conversational JSON comparison and analysis.

#### Claude Code (terminal)

```bash
claude mcp add --transport http apify "https://mcp.apify.com?tools=automation-lab/json-diff-tool"
```

#### Claude Desktop / Cursor / VS Code

Add to your MCP configuration JSON:

```json
{
  "mcpServers": {
    "apify": {
      "type": "http",
      "url": "https://mcp.apify.com?tools=automation-lab/json-diff-tool",
      "headers": { "Authorization": "Bearer YOUR_APIFY_TOKEN" }
    }
  }
}
```

#### Example prompts for Claude

- *"Diff these two JSON configs and tell me which keys changed type"*
- *"Compare the API response from staging vs production at these two URLs"*
- *"Run a JSON diff ignoring the `updatedAt` and `requestId` fields"*
- *"Summarize the differences between these two JSON objects in plain English"*

***

### ⚖️ Legality and data handling

This actor processes only the JSON data you provide — either inline or via URLs you specify. It does not scrape websites, bypass authentication, or access any systems without explicit permission.

- Inline JSON is processed in memory and never persisted beyond the run dataset.
- URL-fetched JSON is retrieved with a standard HTTP GET request from Apify's infrastructure. Only fetch URLs you are authorized to access.
- No login credentials, cookies, or session tokens are used.
- No proxy is used. All HTTP requests are direct datacenter-originated calls.

This actor is intended for comparing JSON you own or have permission to access. Use it responsibly.

***

### ❓ FAQ

**Does it support JSON arrays at the top level?**
Yes. If your JSON is a top-level array (e.g. a list of objects), the actor compares by array index by default. Use `ignoreArrayOrder: true` for content-based comparison.

**What happens if a URL is not reachable?**
The run will fail with a clear error message showing the URL and HTTP status code. Check that the URL is publicly accessible and returns `Content-Type: application/json` or plain JSON text.

**How does it handle very large JSON (megabytes)?**
The actor loads both JSON objects into memory at 256 MB. Very large JSON files (> 50 MB) may cause memory issues — use `maxDepth` to limit recursion for oversized payloads. For datasets with thousands of records, consider splitting your comparison.

**What does `type-changed` mean vs `changed`?**
`changed` means the value changed but remained the same type (e.g. `30` → `31`). `type-changed` means both the value AND the type changed (e.g. `42` → `"42"` = number to string). Type changes are particularly important to catch because they silently break downstream consumers.

**My arrays have the same items but in different order — is that a change?**
By default yes — array order is significant. Enable `ignoreArrayOrder` to treat arrays as unordered sets. Note: this uses serialization-based matching, so it works best for primitive arrays (strings, numbers). Object arrays use exact-match semantics.

**Why does flat mode output an "identical" row when there are no differences?**
To ensure your downstream integrations always receive at least one row in the dataset. An empty dataset can be ambiguous — the `identical` row makes the "no differences" case explicit and queryable.

***

### 🔗 Related tools

- [JSON Schema Generator](https://apify.com/automation-lab/json-schema-generator) — automatically generate a JSON Schema from any JSON sample
- [Color Contrast Checker](https://apify.com/automation-lab/color-contrast-checker) — validate WCAG 2.1 color contrast for UI accessibility

# Actor input Schema

## `jsonA` (type: `string`):

First JSON object as a raw string. Either provide this or <code>urlA</code> — inline takes priority.

## `urlA` (type: `string`):

URL to fetch the first JSON from. Used only if <code>jsonA</code> is empty.

## `jsonB` (type: `string`):

Second JSON object as a raw string. Either provide this or <code>urlB</code>.

## `urlB` (type: `string`):

URL to fetch the second JSON from. Used only if <code>jsonB</code> is empty.

## `outputMode` (type: `string`):

Controls what to include in the dataset output. <code>flat</code> = one row per changed path (easiest to analyze). <code>summary</code> = single row with all changes grouped by type.

## `ignoreArrayOrder` (type: `boolean`):

When enabled, arrays are compared by content regardless of item order (uses set-based matching for primitive arrays). Disable to treat array order as significant.

## `ignoreKeys` (type: `array`):

List of dot-notation key paths to exclude from comparison. Example: <code>meta.timestamp</code> or <code>updatedAt</code>. Supports exact paths only (no wildcards).

## `maxDepth` (type: `integer`):

Maximum nesting depth to recurse into. Set to 0 for unlimited. Shallow diffs of very large objects are faster.

## Actor input object example

```json
{
  "jsonA": "{\"name\":\"Alice\",\"age\":30,\"role\":\"admin\",\"tags\":[\"a\",\"b\"]}",
  "jsonB": "{\"name\":\"Alice\",\"age\":31,\"role\":\"superadmin\",\"tags\":[\"a\",\"b\",\"c\"]}",
  "outputMode": "flat",
  "ignoreArrayOrder": false,
  "maxDepth": 0
}
```

# Actor output Schema

## `overview` (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 = {
    "jsonA": "{\"name\":\"Alice\",\"age\":30,\"role\":\"admin\",\"tags\":[\"a\",\"b\"]}",
    "jsonB": "{\"name\":\"Alice\",\"age\":31,\"role\":\"superadmin\",\"tags\":[\"a\",\"b\",\"c\"]}",
    "outputMode": "flat",
    "ignoreArrayOrder": false,
    "maxDepth": 0
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/json-diff-tool").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 = {
    "jsonA": "{\"name\":\"Alice\",\"age\":30,\"role\":\"admin\",\"tags\":[\"a\",\"b\"]}",
    "jsonB": "{\"name\":\"Alice\",\"age\":31,\"role\":\"superadmin\",\"tags\":[\"a\",\"b\",\"c\"]}",
    "outputMode": "flat",
    "ignoreArrayOrder": False,
    "maxDepth": 0,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/json-diff-tool").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 '{
  "jsonA": "{\\"name\\":\\"Alice\\",\\"age\\":30,\\"role\\":\\"admin\\",\\"tags\\":[\\"a\\",\\"b\\"]}",
  "jsonB": "{\\"name\\":\\"Alice\\",\\"age\\":31,\\"role\\":\\"superadmin\\",\\"tags\\":[\\"a\\",\\"b\\",\\"c\\"]}",
  "outputMode": "flat",
  "ignoreArrayOrder": false,
  "maxDepth": 0
}' |
apify call automation-lab/json-diff-tool --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=automation-lab/json-diff-tool",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "JSON Diff Tool",
        "description": "Semantically compare two JSON objects or files. Outputs a structured diff with dot-notation paths for every added, removed, changed, and type-changed field. Supports nested objects, arrays, URL fetching, and ignore lists.",
        "version": "0.1",
        "x-build-id": "Qk9iWjNzRSXCnTdem"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/automation-lab~json-diff-tool/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-automation-lab-json-diff-tool",
                "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/automation-lab~json-diff-tool/runs": {
            "post": {
                "operationId": "runs-sync-automation-lab-json-diff-tool",
                "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/automation-lab~json-diff-tool/run-sync": {
            "post": {
                "operationId": "run-sync-automation-lab-json-diff-tool",
                "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",
                "properties": {
                    "jsonA": {
                        "title": "📄 JSON A (inline)",
                        "type": "string",
                        "description": "First JSON object as a raw string. Either provide this or <code>urlA</code> — inline takes priority."
                    },
                    "urlA": {
                        "title": "🔗 URL A",
                        "type": "string",
                        "description": "URL to fetch the first JSON from. Used only if <code>jsonA</code> is empty."
                    },
                    "jsonB": {
                        "title": "📄 JSON B (inline)",
                        "type": "string",
                        "description": "Second JSON object as a raw string. Either provide this or <code>urlB</code>."
                    },
                    "urlB": {
                        "title": "🔗 URL B",
                        "type": "string",
                        "description": "URL to fetch the second JSON from. Used only if <code>jsonB</code> is empty."
                    },
                    "outputMode": {
                        "title": "📊 Output mode",
                        "enum": [
                            "flat",
                            "summary"
                        ],
                        "type": "string",
                        "description": "Controls what to include in the dataset output. <code>flat</code> = one row per changed path (easiest to analyze). <code>summary</code> = single row with all changes grouped by type.",
                        "default": "flat"
                    },
                    "ignoreArrayOrder": {
                        "title": "🔃 Ignore array item order",
                        "type": "boolean",
                        "description": "When enabled, arrays are compared by content regardless of item order (uses set-based matching for primitive arrays). Disable to treat array order as significant.",
                        "default": false
                    },
                    "ignoreKeys": {
                        "title": "🚫 Ignore keys (dot-notation)",
                        "type": "array",
                        "description": "List of dot-notation key paths to exclude from comparison. Example: <code>meta.timestamp</code> or <code>updatedAt</code>. Supports exact paths only (no wildcards).",
                        "items": {
                            "type": "string"
                        }
                    },
                    "maxDepth": {
                        "title": "🔢 Max depth",
                        "minimum": 0,
                        "maximum": 100,
                        "type": "integer",
                        "description": "Maximum nesting depth to recurse into. Set to 0 for unlimited. Shallow diffs of very large objects are faster.",
                        "default": 0
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
