# Contact Details Extractor (`worshipful_knife/contact-details-extractor`) Actor

The cheapest contact scraper on Apify. Extract emails, phone numbers, company names, addresses & 25+ social profiles at $0.001/page - 50% less than competitors. Smart crawling auto-finds contact pages, bypasses Cloudflare protection, browser mode for JS sites, sitemap discovery.

- **URL**: https://apify.com/worshipful\_knife/contact-details-extractor.md
- **Developed by:** [kata Kuri](https://apify.com/worshipful_knife) (community)
- **Categories:** Lead generation, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, NaN bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.01 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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

## Contact Details Extractor

Extract emails, phone numbers, social media profiles, postal addresses, and company info from any website. Works on plain HTML, JavaScript-rendered SPAs, and Cloudflare-protected pages.

Built for sales teams, recruiters, and lead-gen workflows that need clean contact data ready to drop into a CRM.

### Why this scraper

| | This actor |
|---|---|
| Cleans output | Validates emails (TLD whitelist, blacklist, multi-`@` reject), phones (libphonenumber E.164), and social URLs (rejects share buttons) |
| Per-domain merging | One row per domain instead of one row per page |
| 25+ social platforms | LinkedIn, X/Twitter, Instagram, Facebook, YouTube, TikTok, Pinterest, GitHub, Discord, Telegram, WhatsApp, Reddit, Medium, Substack, Twitch, Snapchat, Threads, Bluesky, Mastodon, Spotify, Vimeo, Dribbble, Behance, SoundCloud, Crunchbase, AngelList |
| JS rendering on demand | Three modes: HTTP-only (cheapest), browser-only (always render), or auto (HTTP first, browser fallback when the page looks like an empty SPA shell) |
| Cloudflare email decoding | Decodes both `data-cfemail` attributes and `/cdn-cgi/l/email-protection#hex` URLs |
| Smart contact-page targeting | Crawl order is ranked by URL relevance — `/contact`, `/about`, `/team`, `/imprint` go first, blog posts last |
| Sitemap discovery | Optional `/sitemap.xml` and `/robots.txt` parsing to find contact-rich pages without crawling |
| Pay-per-event | You pay per record produced, not per page crawled — no charge when nothing useful is found |

### What gets extracted

**Per domain** (when `mergeContacts: true`, default):

```json
{
  "domain": "hubertprocess.com",
  "url": "https://www.hubertprocess.com",
  "companyName": "Hubert Process",
  "companyDescription": "Hubert Process designs optical sorting machines…",
  "logo": "https://www.hubertprocess.com/apple-touch-icon.png",
  "emails": ["admin.si@hubertprocess.com", "contact@hubertprocess.com"],
  "phones": ["+33241487578", "+33243696298", "+41228203544"],
  "phonesUncertain": [],
  "addresses": [
    {
      "full": "1 Market St, San Francisco, CA, 94105, US",
      "street": "1 Market St",
      "city": "San Francisco",
      "region": "CA",
      "postalCode": "94105",
      "country": "US"
    }
  ],
  "linkedin": "https://www.linkedin.com/company/hubert-metal",
  "twitter": null,
  "facebook": "https://www.facebook.com/Hubert-Process-Robotique-102014175737316",
  "instagram": null,
  "youtube": null,
  "github": null,
  "// ... 19 other social platforms": "...",
  "scrapedUrls": ["...12 URLs..."],
  "scrapedAt": "2026-05-03T12:34:34Z"
}
````

### Inputs

| Field | Type | Default | Description |
|---|---|---|---|
| `startUrls` | array | required | Websites to scrape. Plain domains (`example.com`) and full URLs both work. |
| `maxPagesPerStartUrl` | int | 20 | Pages crawled per website. Lower = cheaper, faster. |
| `maxDepth` | int | 2 | Click-depth from the start URL. `1` = homepage only, `2` = homepage + linked pages. |
| `sameDomain` | bool | true | Only follow links on the same registered domain. |
| `useSitemap` | bool | false | Discover pages via `/sitemap.xml`. |
| `browserMode` | enum | `auto` | `off` (HTTP only), `on` (always browser), `auto` (HTTP first, browser fallback for SPAs). |
| `mergeContacts` | bool | true | Combine all pages of a domain into one record. |
| `extractAddresses` | bool | true | Parse postal addresses from schema.org markup. |
| `extractCompanyInfo` | bool | true | Detect company name, description, and logo. |
| `decodeCloudflareEmails` | bool | true | Decode CF-protected emails. |
| `phoneCountryHint` | string | `null` | ISO country code (`US`, `GB`, `FR`, …) for parsing local-format phones. |
| `maxConcurrency` | int | 10 | Parallel page fetches. |
| `proxyConfiguration` | object | `{useApifyProxy: true}` | Datacenter is the default; switch to `RESIDENTIAL` for Cloudflare-blocked sites. |

### How it works

1. Each start URL is normalized (`example.com` → `https://example.com`) and seeded into the HTTP queue.
2. Optionally, `/sitemap.xml` is parsed; the highest-ranking URLs (containing `contact`, `about`, `imprint`, etc.) are added to the queue.
3. The HTTP crawler (Cheerio) fetches pages with realistic headers. For each page:
   - Run all extractors against the HTML and visible text.
   - Extract outbound links, score them by contact-relevance, follow the highest-scoring ones until the per-domain budget is exhausted.
   - In `browserMode: auto`, if the HTML looks like an empty SPA shell (React root with no content, very low text-to-HTML ratio), push the URL into the browser queue instead.
4. After the HTTP pass, the Playwright crawler renders the URLs that were flagged for fallback.
5. Pages are merged per registered domain (so `blog.acme.co.uk` and `www.acme.co.uk` collapse into one `acme.co.uk` record).
6. Each non-empty record fires a `contact-record` charge event (pay-per-event pricing).

#### What makes the extraction reliable

- **Email TLD whitelist.** A naive regex would match `contact@welko.contactez` because `contactez` looks like a TLD. We reject TLDs not on the [IANA root zone list](https://data.iana.org/TLD/tlds-alpha-by-domain.txt). Result: zero false positives from non-English text.
- **Obfuscated email regex requires explicit markers.** `[at]`, `(at)`, or whitespace-isolated `AT` — never bare `at` inside a word. Otherwise `automation` would match as `autom@ion`.
- **Phone validation via libphonenumber.** Phone-shaped digit runs only land in `phones` when libphonenumber confirms they're real. Unverified candidates with separators land in `phonesUncertain`. Pure digit runs (SIRET numbers, tracking IDs, hashes) are dropped.
- **Social URLs reject share buttons.** `twitter.com/intent/tweet`, `linkedin.com/sharing/share-offsite`, `facebook.com/sharer.php` all rejected. Only profile URLs make it through.
- **Cloudflare email decoder.** Both `data-cfemail="..."` and `/cdn-cgi/l/email-protection#...` patterns are XOR-decoded inline.

### Pricing

Pay-per-event — you're billed per successful page extracted, never for failed requests (4xx, timeouts, blocks). Exactly **one** of the page events fires per page, picked by which combination of renderer × proxy was used:

| Event | Suggested price (Free) | Suggested price (Business) | When it fires |
|---|---|---|---|
| `actor-start` | $0.01 / run | $0.005 / run | Once at the start of every run |
| `page-scraped` | $1.00 / 1 000 | $0.69 / 1 000 | Plain HTTP page extracted (cheapest) |
| `page-with-browser` | $2.00 / 1 000 | $1.50 / 1 000 | Playwright-rendered page on datacenter proxy |
| `page-residential-proxy` | $3.00 / 1 000 | $2.30 / 1 000 | Any page fetched via residential proxy (overrides the two above) |

These suggested prices match the competitor (`betterdevsscrape/contact-details-extractor`) so users can switch without re-budgeting.

#### What a typical run costs

Crawling 1 000 small B2B sites with default settings (`maxPagesPerStartUrl: 20`, `browserMode: auto`, datacenter proxy) typically uses:

- 1 × `actor-start` → $0.01
- \~16 000 successful `page-scraped` events (~80% HTTP success) → $16.00
- \~2 000 `page-with-browser` events (~10% needed JS rendering) → $4.00
- **Total: ~$20 per 1 000 sites** — same ballpark as the competitor, with cleaner output.

If you switch to `proxyConfiguration.apifyProxyGroups: ["RESIDENTIAL"]` to bypass Cloudflare-protected sites:

- All page events become `page-residential-proxy` → ~$54 per 1 000 sites
- Still cheaper than running residential through `betterdevsscrape` ($3 / 1 000 there too) and you get more sites unlocked thanks to per-context warm-up.

#### Why this model is better than per-domain billing

The previous version charged once per *domain* with at least one piece of data. That sounds cheap until you realise it heavily penalised small jobs (one site = same cost as 100 pages of one site) and made it impossible to set per-page budgets in tools like Make/n8n. The per-page model is what every other contact-extractor on the Apify Store uses and what your customer is already mentally budgeting against.

### Tips

- **Plain HTML sites** (most B2B sites): keep `browserMode: off` — fastest and cheapest.
- **JS-heavy SPAs** (Webflow, modern React apps): use `browserMode: auto` — it switches to browser only when needed.
- **Cloudflare-blocked sites** (520, 403): switch `proxyConfiguration` to `{ "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }`.
- **For sales/lead-gen**: enable `useSitemap: true` and bump `maxPagesPerStartUrl: 50` — gets you the full team page on most company sites.

### Output formats

The dataset is exportable as JSON, CSV, Excel, or HTML directly from the Apify console. CSV is the fastest path into HubSpot, Salesforce, Pipedrive, or any standard CRM importer.

### Local development

```bash
git clone https://your-repo/contact-details-extractor.git
cd contact-details-extractor
npm install

## Run unit tests (31 cases — extractor logic, regex correctness, regression coverage)
npm test

## Run the actor locally against a test input
echo '{ "startUrls": [{"url": "https://www.apify.com"}], "maxPagesPerStartUrl": 8, "browserMode": "off", "proxyConfiguration": null }' > apify_storage/key_value_stores/default/INPUT.json
APIFY_LOCAL_STORAGE_DIR=$(pwd)/apify_storage node src/main.js
```

### Roadmap

- Smarter address extraction from free-form text (currently relies on schema.org markup)
- Person-level contact extraction (job title + email pairing)
- Optional WhatsApp/Telegram deep-link extraction (`wa.me/<phone>` patterns)

### License

ISC

# Actor input Schema

## `startUrls` (type: `array`):

List of websites to extract contact details from. Plain domains (example.com) and full URLs (https://example.com/about) both work.

## `maxPagesPerStartUrl` (type: `integer`):

Maximum number of pages to crawl per start URL. Lower = cheaper, faster. Higher = more thorough.

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

How many clicks away from the start URL to follow. Depth 1 = only the homepage; depth 2 = homepage + linked pages.

## `sameDomain` (type: `boolean`):

Only follow links that stay on the same registered domain as the start URL.

## `useSitemap` (type: `boolean`):

Discover pages via /sitemap.xml. When enabled, the crawler prioritises pages with /contact, /about, /team, /imprint in the URL.

## `browserMode` (type: `string`):

off = fast HTTP only. on = always render with a real browser (Playwright). auto = HTTP first, fall back to browser if the page looks empty (best balance).

## `mergeContacts` (type: `boolean`):

Combine all data found across pages of the same domain into a single record. Disable to get one record per page.

## `extractAddresses` (type: `boolean`):

Parse postal addresses from schema.org markup, footers, and contact pages.

## `extractCompanyInfo` (type: `boolean`):

Detect company name, description, and logo via og:site\_name, schema.org Organization, and title heuristics.

## `decodeCloudflareEmails` (type: `boolean`):

Decode emails hidden behind Cloudflare's email obfuscation (data-cfemail attribute).

## `phoneCountryHint` (type: `string`):

Default ISO country code (US, GB, FR, DE, etc.) for parsing phone numbers without an international prefix. Leave empty for auto-detection from the page.

## `maxConcurrency` (type: `integer`):

How many pages to crawl in parallel. Higher = faster but more likely to be rate-limited.

## `proxyConfiguration` (type: `object`):

Proxy settings. Datacenter proxy is the default and works for most sites. Switch to RESIDENTIAL for sites that block datacenter IPs.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.shopify.com"
    },
    {
      "url": "https://www.stripe.com"
    }
  ],
  "maxPagesPerStartUrl": 20,
  "maxDepth": 2,
  "sameDomain": true,
  "useSitemap": false,
  "browserMode": "auto",
  "mergeContacts": true,
  "extractAddresses": true,
  "extractCompanyInfo": true,
  "decodeCloudflareEmails": true,
  "maxConcurrency": 10,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `datasetUrl` (type: `string`):

Open the dataset to view, filter, or export the extracted contacts.

## `csvUrl` (type: `string`):

Download the dataset as CSV — ready for CRM import.

## `consoleUrl` (type: `string`):

Browse, filter, and export the dataset in the Apify console.

# 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 = {
    "startUrls": [
        {
            "url": "https://www.shopify.com"
        },
        {
            "url": "https://www.stripe.com"
        }
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("worshipful_knife/contact-details-extractor").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 = {
    "startUrls": [
        { "url": "https://www.shopify.com" },
        { "url": "https://www.stripe.com" },
    ],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("worshipful_knife/contact-details-extractor").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 '{
  "startUrls": [
    {
      "url": "https://www.shopify.com"
    },
    {
      "url": "https://www.stripe.com"
    }
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call worshipful_knife/contact-details-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=worshipful_knife/contact-details-extractor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Contact Details Extractor",
        "description": "The cheapest contact scraper on Apify. Extract emails, phone numbers, company names, addresses & 25+ social profiles at $0.001/page - 50% less than competitors. Smart crawling auto-finds contact pages, bypasses Cloudflare protection, browser mode for JS sites, sitemap discovery.",
        "version": "1.0",
        "x-build-id": "XlOlbhSTPnZBZd5GP"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/worshipful_knife~contact-details-extractor/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-worshipful_knife-contact-details-extractor",
                "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/worshipful_knife~contact-details-extractor/runs": {
            "post": {
                "operationId": "runs-sync-worshipful_knife-contact-details-extractor",
                "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/worshipful_knife~contact-details-extractor/run-sync": {
            "post": {
                "operationId": "run-sync-worshipful_knife-contact-details-extractor",
                "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": [
                    "startUrls"
                ],
                "properties": {
                    "startUrls": {
                        "title": "Start URLs",
                        "type": "array",
                        "description": "List of websites to extract contact details from. Plain domains (example.com) and full URLs (https://example.com/about) both work.",
                        "items": {
                            "type": "object",
                            "required": [
                                "url"
                            ],
                            "properties": {
                                "url": {
                                    "type": "string",
                                    "title": "URL of a web page",
                                    "format": "uri"
                                }
                            }
                        }
                    },
                    "maxPagesPerStartUrl": {
                        "title": "Max pages per website",
                        "minimum": 1,
                        "maximum": 500,
                        "type": "integer",
                        "description": "Maximum number of pages to crawl per start URL. Lower = cheaper, faster. Higher = more thorough.",
                        "default": 20
                    },
                    "maxDepth": {
                        "title": "Max link depth",
                        "minimum": 0,
                        "maximum": 5,
                        "type": "integer",
                        "description": "How many clicks away from the start URL to follow. Depth 1 = only the homepage; depth 2 = homepage + linked pages.",
                        "default": 2
                    },
                    "sameDomain": {
                        "title": "Stay on same domain",
                        "type": "boolean",
                        "description": "Only follow links that stay on the same registered domain as the start URL.",
                        "default": true
                    },
                    "useSitemap": {
                        "title": "Use sitemap.xml",
                        "type": "boolean",
                        "description": "Discover pages via /sitemap.xml. When enabled, the crawler prioritises pages with /contact, /about, /team, /imprint in the URL.",
                        "default": false
                    },
                    "browserMode": {
                        "title": "Browser rendering mode",
                        "enum": [
                            "off",
                            "auto",
                            "on"
                        ],
                        "type": "string",
                        "description": "off = fast HTTP only. on = always render with a real browser (Playwright). auto = HTTP first, fall back to browser if the page looks empty (best balance).",
                        "default": "auto"
                    },
                    "mergeContacts": {
                        "title": "Merge contacts per domain",
                        "type": "boolean",
                        "description": "Combine all data found across pages of the same domain into a single record. Disable to get one record per page.",
                        "default": true
                    },
                    "extractAddresses": {
                        "title": "Extract physical addresses",
                        "type": "boolean",
                        "description": "Parse postal addresses from schema.org markup, footers, and contact pages.",
                        "default": true
                    },
                    "extractCompanyInfo": {
                        "title": "Extract company info",
                        "type": "boolean",
                        "description": "Detect company name, description, and logo via og:site_name, schema.org Organization, and title heuristics.",
                        "default": true
                    },
                    "decodeCloudflareEmails": {
                        "title": "Decode Cloudflare-protected emails",
                        "type": "boolean",
                        "description": "Decode emails hidden behind Cloudflare's email obfuscation (data-cfemail attribute).",
                        "default": true
                    },
                    "phoneCountryHint": {
                        "title": "Phone country hint",
                        "type": "string",
                        "description": "Default ISO country code (US, GB, FR, DE, etc.) for parsing phone numbers without an international prefix. Leave empty for auto-detection from the page."
                    },
                    "maxConcurrency": {
                        "title": "Max concurrency",
                        "minimum": 1,
                        "maximum": 50,
                        "type": "integer",
                        "description": "How many pages to crawl in parallel. Higher = faster but more likely to be rate-limited.",
                        "default": 10
                    },
                    "proxyConfiguration": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Proxy settings. Datacenter proxy is the default and works for most sites. Switch to RESIDENTIAL for sites that block datacenter IPs.",
                        "default": {
                            "useApifyProxy": true
                        }
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
