# Visual Regression Monitor — Website Screenshot Comparison (`perryay/visual-regression-monitor`) Actor

Monitor websites for visual regressions. Capture baseline screenshots, compare against new captures, and generate pixel-accurate diff reports with highlighted changes.

- **URL**: https://apify.com/perryay/visual-regression-monitor.md
- **Developed by:** [Perry AY](https://apify.com/perryay) (community)
- **Categories:** Developer tools, AI
- **Stats:** 2 total users, 1 monthly users, 50.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.01 / actor start

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/platform/actors/running/actors-in-store#pay-per-event

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

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.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/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

## Visual Regression Monitor 🎯 — Detect Website Changes with Pixel-Perfect Diff Analysis

Capture website screenshots and compare them pixel-by-pixel to detect visual regressions. Generate annotated diff images, monitor pages on a schedule, and receive webhook alerts when changes are detected. Uses a headless Chromium browser for accurate, real-world screenshots.

---

### What does it do?

The Visual Regression Monitor automates visual quality assurance for web pages. It takes full-page or viewport screenshots using headless Chromium, stores them as baselines in Apify's Key-Value Store, and then compares subsequent captures against those baselines pixel-by-pixel. When differences are found, it generates three-panel annotated diff images showing the baseline, current state, and highlighted changes.

**Key capabilities:**
- **Baseline capture** — Take screenshots of any URL and save them as reference images
- **Visual comparison** — Compare live pages against stored baselines with pixel-level diff reporting
- **Batch processing** — Compare multiple URLs concurrently for efficient monitoring
- **Annotated diff reports** — Generate HTML summary reports with per-URL match/mismatch status
- **Webhook alerts** — Send JSON alert payloads when visual mismatches are detected (ideal for CI/CD pipelines)
- **Configurable thresholds** — Set a diff percentage tolerance to ignore minor rendering differences
- **Custom viewport** — Control browser width, height, and full-page capture

---

### Who is it for?

| Persona | Use Case |
|---------|----------|
| QA Engineer | Automate visual regression testing in CI/CD pipelines |
| Front-End Developer | Catch unintended UI changes before deployment |
| Site Reliability Engineer | Monitor production pages for unexpected visual drift |
| Product Manager | Verify visual consistency across environments |
| Web Agency | Scale visual QA across multiple client sites |

---

### Input Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `mode` | string | `capture-baseline` | Operation mode: `capture-baseline`, `compare-baseline`, `batch-compare`, or `generate-diff-report` |
| `url` | string | — | A single URL to process (ignored if `urls` is provided) |
| `urls` | array | — | One or more URLs to process (up to 50) |
| `viewportWidth` | integer | 1280 | Browser viewport width in pixels |
| `viewportHeight` | integer | 720 | Browser viewport height in pixels |
| `fullPage` | boolean | false | Capture the entire scrollable page |
| `waitAfterLoadMs` | integer | 2000 | Milliseconds to wait after page load before screenshot |
| `diffThreshold` | number | 0.0 | Allowed diff percentage before flagging a mismatch |
| `timeoutSecs` | integer | 60 | Max seconds to wait for page navigation |
| `webhookUrl` | string | — | URL for POST alerts when mismatches are detected |

---

### Quick Start

#### Capture Baselines

Start by capturing reference screenshots for the pages you want to monitor:

```json
{
  "mode": "capture-baseline",
  "urls": ["https://example.com", "https://httpbin.org"],
  "viewportWidth": 1280,
  "viewportHeight": 720,
  "fullPage": false
}
````

Baseline images are stored in your run's Key-Value Store under keys like `baseline-example.com___` and `baseline-httpbin.org___`.

#### Compare to Baseline

After baselines are stored, compare the live pages:

```json
{
  "mode": "compare-baseline",
  "urls": ["https://example.com", "https://httpbin.org"],
  "diffThreshold": 2.0,
  "webhookUrl": "https://hooks.example.com/visual-alerts"
}
```

This captures new screenshots, compares them pixel-by-pixel against the stored baselines, and generates annotated diff images in KVS. If the diff percentage exceeds the threshold, the URL is flagged as a mismatch.

#### Batch Compare

For larger workloads, use batch mode to compare multiple URLs concurrently:

```json
{
  "mode": "batch-compare",
  "urls": [
    "https://example.com",
    "https://httpbin.org",
    "https://www.google.com",
    "https://github.com"
  ],
  "diffThreshold": 1.0
}
```

All comparisons run concurrently via `asyncio.gather` with `return_exceptions=True`, so a failure on one URL does not affect others.

#### Generate Diff Report

After comparisons, generate an HTML report summarising all results:

```json
{
  "mode": "generate-diff-report"
}
```

The report is stored in KVS as `report-latest.html` and as a timestamped key. Open the KVS URL in your browser to view the dark-themed annotated report with per-URL match/mismatch status, diff percentages, and pixel counts.

***

### Output

Each run pushes individual results to the default dataset. For comparison modes, each item contains:

| Field | Type | Description |
|-------|------|-------------|
| `url` | string | The URL that was processed |
| `match` | boolean | Whether the screenshot matched the baseline |
| `diff_percent` | number | Percentage of differing pixels |
| `pixels_different` | integer | Raw count of differing pixels |
| `total_pixels` | integer | Total pixels in the screenshot |
| `diff_kvs_key` | string | KVS key for the annotated diff PNG |
| `baseline_kvs_key` | string | KVS key for the stored baseline image |
| `compared_at` | string | ISO 8601 comparison timestamp |

For baseline captures, each item contains:

| Field | Type | Description |
|-------|------|-------------|
| `url` | string | The captured URL |
| `success` | boolean | Whether capture succeeded |
| `image_size_bytes` | integer | Size of the PNG in bytes |
| `taken_at` | string | ISO 8601 capture timestamp |
| `error` | string | Error message if capture failed |

***

### API Usage

#### cURL

```bash
curl -X POST "https://api.apify.com/v2/acts/perryay~visual-regression-monitor/runs" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_APIFY_TOKEN" \
  -d '{
    "mode": "compare-baseline",
    "urls": ["https://example.com"],
    "diffThreshold": 2.0
  }'
```

#### Python

```python
import requests

response = requests.post(
    "https://api.apify.com/v2/acts/perryay~visual-regression-monitor/runs",
    headers={
        "Content-Type": "application/json",
        "Authorization": "Bearer YOUR_APIFY_TOKEN"
    },
    json={
        "mode": "compare-baseline",
        "urls": ["https://example.com"],
        "diffThreshold": 2.0
    }
)
print(response.json())
```

#### Node.js

```javascript
const response = await fetch(
  "https://api.apify.com/v2/acts/perryay~visual-regression-monitor/runs",
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": "Bearer YOUR_APIFY_TOKEN"
    },
    body: JSON.stringify({
      mode: "compare-baseline",
      urls: ["https://example.com"],
      diffThreshold: 2.0
    })
  }
);
const data = await response.json();
console.log(data);
```

***

### Use Cases

- **CI/CD visual regression testing** — Run `compare-baseline` after deployments to catch unintended UI changes
- **Scheduled page monitoring** — Use Apify's scheduler to run comparisons hourly/daily and get webhook alerts on mismatches
- **Multi-environment comparison** — Capture baselines from staging, compare against production
- **Content verification** — Detect unexpected changes to critical pages (pricing, landing pages, legal pages)
- **Cross-browser QA** — Run the same URLs at different viewport sizes

***

### FAQ

#### General

**What is visual regression testing?**
Visual regression testing compares screenshots of a web page taken at different times to detect unintended visual changes. It catches layout shifts, missing elements, font changes, and styling regressions that functional tests might miss.

**Do I need to run capture-baseline first?**
Yes. The `compare-baseline` and `batch-compare` modes require baseline images to exist in KVS. Run `capture-baseline` first to create them.

**How are baselines stored?**
Baseline images are stored in your run's Key-Value Store under keys prefixed with `baseline-`. They persist between runs and are accessible via the Apify Console or API.

**What happens if the viewport dimensions change?**
If a comparison detects that the baseline and current screenshot have different dimensions, the baseline is automatically resized to match the current image using Lanczos resampling. A warning is logged.

**Can I use this for responsive design testing?**
Yes. Run the same URLs with different `viewportWidth` and `viewportHeight` settings to capture baselines for each breakpoint, then compare against the matching breakpoint.

**What file format are the diff images?**
All diff images are generated as PNG with a three-panel layout: baseline (left), current (middle), and changes highlighted in red (right). A status bar at the bottom shows the URL, diff percentage, and pixel counts.

#### Webhooks

**What does the webhook payload look like?**

```json
{
  "event": "visual-regression-alert",
  "mode": "compare-baseline",
  "timestamp": "2026-07-27T12:00:00.000Z",
  "results": {
    "total_urls": 5,
    "failures": 2,
    "successes": 3
  }
}
```

**How do I set up scheduled monitoring?**
Use Apify's built-in scheduler: create a task with `mode: compare-baseline`, set the desired URLs and threshold, and configure a daily or hourly schedule with a `webhookUrl` to receive alerts.

#### Technical

**What browser engine is used?**
Headless Chromium via Playwright. The Docker image (`apify/actor-python-playwright`) includes the Chromium browser binary pre-installed.

**How accurate is the pixel comparison?**
It uses Pillow's `ImageChops.difference()` for exact pixel-level comparison. Each pixel channel is compared independently. The `diffThreshold` parameter lets you relax strictness: 0% = pixel-perfect, 5% = tolerant to minor antialiasing or font rendering differences.

**How many URLs can I process in a single run?**
Up to 50 URLs per run. For larger workloads, split across multiple scheduled runs or tasks.

**Does it support authentication-protected pages?**
Currently the actor does not include cookie/session management. You can use Apify's Proxy or custom headers for basic auth scenarios.

**What happens if the page fails to load?**
The actor retries up to 3 times with exponential backoff (2s, 4s, 8s). If all attempts fail, the URL is reported with an error and no charge is applied for that item.

**How are the annotated diff images generated?**
A three-panel composite is created using Pillow. Differing pixels are highlighted with a semi-transparent red overlay on the current screenshot. A dark-themed stats bar at the bottom shows the URL, diff percentage, total pixels, and match/mismatch status.

***

### MCP Integration

Connect this actor to any AI assistant via the **Apify MCP Server**:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com"
    }
  }
}
```

> **Bearer token alternative** (for headless clients like Cursor or VS Code):
>
> ```json
> {
>   "mcpServers": {
>     "apify": {
>       "url": "https://mcp.apify.com",
>       "headers": {
>         "Authorization": "Bearer YOUR_APIFY_TOKEN"
>       }
>     }
>   }
> }
> ```

On first connection, your browser opens to sign in to Apify and authorise access.

**Example prompts for your AI assistant:**

- "Run visual regression monitoring on https://example.com and https://httpbin.org — compare them against their baselines"
- "Capture baseline screenshots of https://example.com at 1920×1080 viewport"
- "Generate a diff report of all URLs that have been compared so far"

***

### Related Tools

- [**Website Screenshot Generator**](https://apify.com/perryay/website-screenshot-generator) — Take full-page or viewport screenshots of any website
- [**OG Preview Generator**](https://apify.com/perryay/og-preview-generator) — Generate Open Graph preview images for URLs
- [**Image Metadata Analyzer**](https://apify.com/perryay/image-metadata-analyzer) — Extract EXIF and metadata from images
- [**All perryay actors**](https://apify.com/perryay) — Browse the full collection

***

### SEO Keywords

Visual regression testing, screenshot diff tool, pixel comparison, visual QA automation, CI/CD visual testing, website monitoring, UI regression detection, automated screenshot comparison, web page change detection, headless browser testing, visual regression monitor, Apify actor visual testing, front-end testing tool, visual diff report, cross-browser screenshot comparison, annotated diff images, webhook visual alerts, batch URL comparison, baseline screenshot capture, pixel-perfect comparison.

# Actor input Schema

## `mode` (type: `string`):

Choose what the actor should do. 'capture-baseline': take screenshots and store as baselines. 'compare-baseline': compare live screenshots to stored baselines. 'batch-compare': compare multiple URLs concurrently. 'generate-diff-report': produce HTML summary of all stored diffs.

## `url` (type: `string`):

A single URL to screenshot. Use this for one-off captures or comparisons. If 'urls' array is also provided, this is ignored.

## `urls` (type: `array`):

One or more URLs to screenshot or compare. Accepts up to 50 URLs per run.

## `viewportWidth` (type: `integer`):

Browser viewport width in pixels.

## `viewportHeight` (type: `integer`):

Browser viewport height in pixels.

## `fullPage` (type: `boolean`):

If true, capture the entire scrollable page instead of just the viewport.

## `waitAfterLoadMs` (type: `integer`):

Milliseconds to wait after the page loads before taking the screenshot. Helps capture dynamic content.

## `diffThreshold` (type: `number`):

Percentage of differing pixels allowed before a comparison is flagged as a mismatch. Set to 0 for strict pixel-perfect matching, or higher (e.g. 5.0) to tolerate minor rendering differences.

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

Maximum seconds to wait for page navigation and screenshots.

## `webhookUrl` (type: `string`):

Optional URL to receive POST alerts when visual mismatches are detected. The payload contains a JSON summary of all comparison results. Use with scheduled runs for continuous monitoring.

## Actor input object example

```json
{
  "mode": "capture-baseline",
  "url": "https://example.com",
  "urls": [
    "https://example.com",
    "https://httpbin.org"
  ],
  "viewportWidth": 1280,
  "viewportHeight": 720,
  "fullPage": false,
  "waitAfterLoadMs": 2000,
  "diffThreshold": 0,
  "timeoutSecs": 60
}
```

# Actor output Schema

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

Processed results from the dataset

## `report_kvs_key` (type: `string`):

KVS key for generated diff report

# 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 = {
    "mode": "capture-baseline",
    "url": "https://example.com",
    "urls": [
        "https://example.com",
        "https://httpbin.org"
    ],
    "webhookUrl": ""
};

// Run the Actor and wait for it to finish
const run = await client.actor("perryay/visual-regression-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 = {
    "mode": "capture-baseline",
    "url": "https://example.com",
    "urls": [
        "https://example.com",
        "https://httpbin.org",
    ],
    "webhookUrl": "",
}

# Run the Actor and wait for it to finish
run = client.actor("perryay/visual-regression-monitor").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 '{
  "mode": "capture-baseline",
  "url": "https://example.com",
  "urls": [
    "https://example.com",
    "https://httpbin.org"
  ],
  "webhookUrl": ""
}' |
apify call perryay/visual-regression-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=perryay/visual-regression-monitor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Visual Regression Monitor — Website Screenshot Comparison",
        "description": "Monitor websites for visual regressions. Capture baseline screenshots, compare against new captures, and generate pixel-accurate diff reports with highlighted changes.",
        "version": "1.0",
        "x-build-id": "6NQckMIRzXZYeuqOV"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/perryay~visual-regression-monitor/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-perryay-visual-regression-monitor",
                "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/perryay~visual-regression-monitor/runs": {
            "post": {
                "operationId": "runs-sync-perryay-visual-regression-monitor",
                "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/perryay~visual-regression-monitor/run-sync": {
            "post": {
                "operationId": "run-sync-perryay-visual-regression-monitor",
                "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",
                "required": [
                    "mode"
                ],
                "properties": {
                    "mode": {
                        "title": "Operation Mode",
                        "enum": [
                            "capture-baseline",
                            "compare-baseline",
                            "batch-compare",
                            "generate-diff-report"
                        ],
                        "type": "string",
                        "description": "Choose what the actor should do. 'capture-baseline': take screenshots and store as baselines. 'compare-baseline': compare live screenshots to stored baselines. 'batch-compare': compare multiple URLs concurrently. 'generate-diff-report': produce HTML summary of all stored diffs.",
                        "default": "capture-baseline"
                    },
                    "url": {
                        "title": "Single URL",
                        "type": "string",
                        "description": "A single URL to screenshot. Use this for one-off captures or comparisons. If 'urls' array is also provided, this is ignored."
                    },
                    "urls": {
                        "title": "URLs",
                        "maxItems": 50,
                        "type": "array",
                        "description": "One or more URLs to screenshot or compare. Accepts up to 50 URLs per run.",
                        "items": {
                            "type": "string",
                            "maxLength": 2048
                        }
                    },
                    "viewportWidth": {
                        "title": "Viewport Width",
                        "minimum": 320,
                        "maximum": 3840,
                        "type": "integer",
                        "description": "Browser viewport width in pixels.",
                        "default": 1280
                    },
                    "viewportHeight": {
                        "title": "Viewport Height",
                        "minimum": 240,
                        "maximum": 2160,
                        "type": "integer",
                        "description": "Browser viewport height in pixels.",
                        "default": 720
                    },
                    "fullPage": {
                        "title": "Full Page Screenshot",
                        "type": "boolean",
                        "description": "If true, capture the entire scrollable page instead of just the viewport.",
                        "default": false
                    },
                    "waitAfterLoadMs": {
                        "title": "Wait After Load (ms)",
                        "minimum": 0,
                        "maximum": 30000,
                        "type": "integer",
                        "description": "Milliseconds to wait after the page loads before taking the screenshot. Helps capture dynamic content.",
                        "default": 2000
                    },
                    "diffThreshold": {
                        "title": "Diff Threshold (%)",
                        "minimum": 0,
                        "maximum": 100,
                        "type": "number",
                        "description": "Percentage of differing pixels allowed before a comparison is flagged as a mismatch. Set to 0 for strict pixel-perfect matching, or higher (e.g. 5.0) to tolerate minor rendering differences.",
                        "default": 0
                    },
                    "timeoutSecs": {
                        "title": "Navigation Timeout (seconds)",
                        "minimum": 10,
                        "maximum": 300,
                        "type": "integer",
                        "description": "Maximum seconds to wait for page navigation and screenshots.",
                        "default": 60
                    },
                    "webhookUrl": {
                        "title": "Webhook URL",
                        "type": "string",
                        "description": "Optional URL to receive POST alerts when visual mismatches are detected. The payload contains a JSON summary of all comparison results. Use with scheduled runs for continuous monitoring."
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
