# TikTok Scraper — Profiles, Videos, Hashtags, Search (`funny_ground/tiktok-scraper`) Actor

Scrape TikTok profiles, videos, hashtags, and search results. Returns structured JSON with video metadata, engagement stats, music, hashtags, mentions, and optional MP4 / cover downloads. Pay-per-result pricing ($1.20 / 1K). Works as an Apify MCP tool callable by Claude / Cursor / ChatGPT.

- **URL**: https://apify.com/funny\_ground/tiktok-scraper.md
- **Developed by:** [Coor Yu](https://apify.com/funny_ground) (community)
- **Categories:** Videos, Social media
- **Stats:** 1 total users, 1 monthly users, 0.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

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

## TikTok Scraper · Apify Actor

Scrape TikTok **profiles, videos, hashtags, and search results** at scale. Returns
structured JSON with full video metadata, engagement stats, music, hashtags, mentions,
and optional MP4 / cover downloads.

Pay-per-result pricing. Residential-proxy ready. Built with **TypeScript + Crawlee +
Playwright** on the official Apify Node 20 base image.

---

### Why this actor

| Feature | This actor | Typical alternatives |
| --- | --- | --- |
| Inputs | profiles + hashtags + search + direct URLs | profiles only |
| Output | 27 fields (incl. music, hashtags, mentions, downloads) | 10-15 fields |
| Pricing | $1.20 / 1,000 results (PPR) | $1.70 - $2.50 / 1K |
| Extraction surface | Inline `SIGI_STATE` + `Universal Data` (survives redesigns) | Private API (breaks weekly) |
| Proxy | DATACENTER default + auto-fallback to RESIDENTIAL if 0 results | Always datacenter (gets blocked) **or** always residential (8× cost) |
| Asset download | Optional MP4 + cover JPG → Key-Value Store | Not supported |

#### Smart proxy fallback (saves you money)

| Pass | Proxy | Cost | When it runs |
| --- | --- | --- | --- |
| 1 | DATACENTER (AUTO) | $1 / GB | Always |
| 2 | RESIDENTIAL | $8 / GB | Only for the specific seeds that returned **0 results** in pass 1, and only if `fallbackToResidential` is on (default) |

So 80–90% of seeds run on cheap datacenter IPs, and only the handful TikTok happens to block on this hour get the expensive residential treatment. You can flip `fallbackToResidential: false` for a hard cost cap.

---

### Input

All fields optional — provide **at least one** of `profiles`, `hashtags`, `searchKeywords`, or `videoUrls`.

```json
{
  "profiles": ["khaby.lame", "https://www.tiktok.com/@charlidamelio"],
  "hashtags": ["fyp", "comedy"],
  "searchKeywords": ["summer fashion 2026"],
  "videoUrls": [
    "https://www.tiktok.com/@khaby.lame/video/7321234567890123456"
  ],
  "resultsPerInput": 50,
  "hashtagPostedAfter": "2026-05-01",
  "hashtagPostedBefore": "2026-05-19",
  "shouldDownloadVideos": false,
  "shouldDownloadCovers": false,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["AUTO"]
  },
  "fallbackToResidential": true,
  "maxConcurrency": 5
}
````

Full schema: see [`.actor/input_schema.json`](./.actor/input_schema.json).

#### Hashtag time window

`hashtagPostedAfter` / `hashtagPostedBefore` filter hashtag-sourced videos by their TikTok `createTime`. Accepts ISO 8601:

- Date-only — `"2026-05-01"` — anchored to 00:00:00 **UTC**.
- Date-time — `"2026-05-01T14:30:00Z"` — used as-is.

The filter runs **inside** the XHR sniffer, so out-of-window videos are dropped before billing — you only pay for what you keep.

> ⚠️ Hashtag feeds aren't strictly chronological — TikTok mixes viral-old and fresh content. If you need 50 recent results, set `resultsPerInput` to ~150-250 so the filter has enough room to find them. The scroller is given 2× patience (stagnant-threshold 8 vs the default 4) when the filter is active.

The filter is **scoped to `hashtags`** — `profiles`, `searchKeywords`, and `videoUrls` ignore both fields.

***

### Output (one row per video)

```json
{
  "videoId": "7321234567890123456",
  "webVideoUrl": "https://www.tiktok.com/@khaby.lame/video/7321234567890123456",
  "text": "When you finally fix the bug 🐛",
  "createTimeISO": "2026-05-12T14:32:11.000Z",
  "duration": 18,
  "videoDownloadUrl": "https://v16-webapp-prime.tiktok.com/.../play.mp4",
  "coverUrl": "https://p16-sign-va.tiktokcdn.com/.../cover.jpeg",
  "author": {
    "id": "6748834234567",
    "uniqueId": "khaby.lame",
    "nickname": "Khaby Lame",
    "verified": true,
    "avatar": "https://...",
    "followers": 162500000
  },
  "music": {
    "id": "7012345678",
    "title": "Original Sound",
    "author": "khaby.lame",
    "playUrl": "https://..."
  },
  "stats": {
    "playCount": 12500000,
    "diggCount": 1850000,
    "commentCount": 23400,
    "shareCount": 156000,
    "collectCount": 78000
  },
  "hashtags": ["fyp", "comedy"],
  "mentions": [],
  "sourceType": "profile",
  "sourceInput": "khaby.lame",
  "scrapedAt": "2026-05-19T07:23:11.234Z"
}
```

If `shouldDownloadVideos` / `shouldDownloadCovers` is enabled, additional fields
`storedVideoKey` / `storedCoverKey` point to entries in the run's Key-Value Store.

***

### Pricing — Pay per result

| Event | Charge |
| --- | --- |
| `video-scraped` | $1.20 / 1,000 videos |

Failed requests and retries are **free**. You only pay for rows that land in the dataset.

***

### Local development

```bash
## 1) Install deps
npm install

## 2) Set an INPUT.json under storage/key_value_stores/default/
mkdir -p storage/key_value_stores/default
cat > storage/key_value_stores/default/INPUT.json <<'JSON'
{
  "profiles": ["khaby.lame"],
  "resultsPerInput": 10
}
JSON

## 3) Run locally (uses Apify CLI if installed, otherwise raw node)
npm start
```

Output lands in `storage/datasets/default/*.json`.

***

### Deploy to Apify

```bash
## Install Apify CLI once
npm install -g apify-cli

## Login
apify login

## Push from this folder
cd apify-tiktok-scraper
apify push
```

The actor builds on Apify's servers; first build takes 3-5 minutes.

To enable **pay-per-result** pricing after publishing, open the actor on
[apify.com](https://apify.com/) → **Monetization** → set `$1.20 / 1,000 results`
linked to the `video-scraped` event.

***

### Architecture

```
src/main.ts          ─ Actor.init → input validation → spawn crawler
src/routes.ts        ─ Crawlee router: LIST + DETAIL handlers
src/extractors.ts    ─ SIGI_STATE parser + auto-scroll harvester
src/utils.ts         ─ URL builders, normalisers
src/types.ts         ─ TypeScript types for input/output/internal shapes
.actor/actor.json    ─ Actor manifest
.actor/input_schema.json    ─ UI form schema
.actor/dataset_schema.json  ─ Dataset views (powers Apify Store preview table)
.actor/Dockerfile    ─ Build (apify/actor-node-playwright-chrome:20)
```

Extraction strategy:

1. Navigate the page with Playwright + fingerprint randomisation.
2. Read the embedded `SIGI_STATE` (legacy) or `__UNIVERSAL_DATA_FOR_REHYDRATION__`
   (modern Universal Data) JSON blob — this is TikTok's own server-rendered Redux state.
3. Map each item to our canonical schema.
4. Auto-scroll until limit hit or 3 stagnant iterations detected.

Why this approach: TikTok's private REST endpoints (`/api/post/item_list`, etc.) rotate
signatures roughly weekly. The inline state blob is what TikTok's own UI consumes on
first paint — far more stable across redesigns.

***

### Using this actor via MCP (Claude / Cursor / ChatGPT)

The actor is auto-exposed as a tool by **Apify MCP Server** at `https://mcp.apify.com/`.
Apify reads `input_schema.json` to build the tool definition and `dataset_schema.json`
to advertise the **output shape** so LLMs know what fields to expect.

#### Cursor / Claude Desktop config

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com/",
      "transport": "streamable-http",
      "headers": {
        "Authorization": "Bearer apify_api_xxxxxxxx"
      }
    }
  }
}
```

Then prompt your agent:

> "Use the tiktok-scraper actor to fetch the latest 30 videos from @khaby.lame
> and the top 50 results for hashtag #fyp."

Pair this with the `tiktok-comments-scraper` actor for a complete pipeline:
profile → videos → comments → sentiment analysis.

***

### Reliability tips

| Symptom | Fix |
| --- | --- |
| `SIGI_STATE` not found | TikTok occasionally serves an interstitial. Increase `requestTimeoutSecs` to 120. |
| Empty results on hashtags | TikTok geo-filters tags; set `apifyProxyCountry: "US"`. |
| 429 / 403 bursts | Lower `maxConcurrency` to 2; the residential pool will rotate. |
| Slow scrolling on huge profiles | Set `resultsPerInput` to a finite cap (e.g. 200). |

***

### License & disclaimer

MIT. Scrape only public data and respect TikTok's terms. You are responsible for
compliance with applicable laws and platform policies.

# Actor input Schema

## `profiles` (type: `array`):

TikTok usernames (without @) or full profile URLs.

## `hashtags` (type: `array`):

Hashtags without #.

## `hashtagPostedAfter` (type: `string`):

Only return hashtag videos posted on or after this date/time (inclusive). Accepts ISO 8601 — date-only (e.g. 2026-05-01) is anchored to 00:00:00 UTC; date-time (e.g. 2026-05-01T00:00:00Z) is used as-is. Leave empty to disable. Only applies to videos from the `hashtags` input — profiles / search / direct URLs ignore this filter.

## `hashtagPostedBefore` (type: `string`):

Only return hashtag videos posted strictly before this date/time (exclusive). Same format as `hashtagPostedAfter`. Leave empty for no upper bound. Tip: hashtag feeds aren't strictly chronological, so set `resultsPerInput` ~3-5× the count you actually need — the rest will be filtered out.

## `searchKeywords` (type: `array`):

Free-text search queries.

## `videoUrls` (type: `array`):

Direct TikTok video URLs to scrape. Skips listing and goes straight to detail page — fastest path when you already know the video IDs.

## `resultsPerInput` (type: `integer`):

Max videos to return for each profile / hashtag / keyword. Set to 0 for unlimited (until end of feed).

## `shouldDownloadVideos` (type: `boolean`):

If true, store video MP4 files in Apify Key-Value Store. WARNING: significantly increases cost & runtime.

## `shouldDownloadCovers` (type: `boolean`):

If true, store video thumbnail JPGs in Apify Key-Value Store.

## `proxy` (type: `object`):

Proxy settings. DATACENTER (AUTO) is the recommended default — ~8x cheaper than RESIDENTIAL ($1/GB vs $8/GB) and handles light-to-medium TikTok scraping volume well. If `fallbackToResidential` is on (default) and any seed returns 0 results on this proxy, the actor will automatically retry just that seed on RESIDENTIAL — so you get cheap-by-default with a safety net.

## `fallbackToResidential` (type: `boolean`):

If a seed returns 0 records on the primary proxy (typically DATACENTER), automatically retry that seed once on RESIDENTIAL ($8/GB). Recommended ON: keeps cost low by default while protecting against TikTok blocking datacenter IPs. Turn OFF if you want a strict cost cap and never want residential billing.

## `headless` (type: `boolean`):

Run Playwright in headless mode. Set false only when debugging locally.

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

Max simultaneous browser pages. Higher = faster but more rate-limit risk.

## `requestTimeoutSecs` (type: `integer`):

Page load timeout in seconds.

## Actor input object example

```json
{
  "profiles": [
    "khaby.lame",
    "https://www.tiktok.com/@charlidamelio"
  ],
  "hashtags": [
    "fyp",
    "comedy"
  ],
  "hashtagPostedAfter": "2026-05-01",
  "hashtagPostedBefore": "2026-05-19",
  "searchKeywords": [
    "summer fashion 2026",
    "AI tools"
  ],
  "videoUrls": [
    "https://www.tiktok.com/@khaby.lame/video/7321234567890123456"
  ],
  "resultsPerInput": 50,
  "shouldDownloadVideos": false,
  "shouldDownloadCovers": false,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "AUTO"
    ]
  },
  "fallbackToResidential": true,
  "headless": true,
  "maxConcurrency": 5,
  "requestTimeoutSecs": 60
}
```

# 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 = {
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "AUTO"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("funny_ground/tiktok-scraper").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 = { "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["AUTO"],
    } }

# Run the Actor and wait for it to finish
run = client.actor("funny_ground/tiktok-scraper").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 '{
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "AUTO"
    ]
  }
}' |
apify call funny_ground/tiktok-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "TikTok Scraper — Profiles, Videos, Hashtags, Search",
        "description": "Scrape TikTok profiles, videos, hashtags, and search results. Returns structured JSON with video metadata, engagement stats, music, hashtags, mentions, and optional MP4 / cover downloads. Pay-per-result pricing ($1.20 / 1K). Works as an Apify MCP tool callable by Claude / Cursor / ChatGPT.",
        "version": "1.0",
        "x-build-id": "eTkkhinlgsIaBffLg"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/funny_ground~tiktok-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-funny_ground-tiktok-scraper",
                "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/funny_ground~tiktok-scraper/runs": {
            "post": {
                "operationId": "runs-sync-funny_ground-tiktok-scraper",
                "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/funny_ground~tiktok-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-funny_ground-tiktok-scraper",
                "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": {
                    "profiles": {
                        "title": "Profiles",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "TikTok usernames (without @) or full profile URLs.",
                        "default": [],
                        "items": {
                            "type": "string"
                        }
                    },
                    "hashtags": {
                        "title": "Hashtags",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Hashtags without #.",
                        "default": [],
                        "items": {
                            "type": "string"
                        }
                    },
                    "hashtagPostedAfter": {
                        "title": "Hashtag: posted after",
                        "type": "string",
                        "description": "Only return hashtag videos posted on or after this date/time (inclusive). Accepts ISO 8601 — date-only (e.g. 2026-05-01) is anchored to 00:00:00 UTC; date-time (e.g. 2026-05-01T00:00:00Z) is used as-is. Leave empty to disable. Only applies to videos from the `hashtags` input — profiles / search / direct URLs ignore this filter."
                    },
                    "hashtagPostedBefore": {
                        "title": "Hashtag: posted before",
                        "type": "string",
                        "description": "Only return hashtag videos posted strictly before this date/time (exclusive). Same format as `hashtagPostedAfter`. Leave empty for no upper bound. Tip: hashtag feeds aren't strictly chronological, so set `resultsPerInput` ~3-5× the count you actually need — the rest will be filtered out."
                    },
                    "searchKeywords": {
                        "title": "Search keywords",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Free-text search queries.",
                        "default": [],
                        "items": {
                            "type": "string"
                        }
                    },
                    "videoUrls": {
                        "title": "Video URLs",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Direct TikTok video URLs to scrape. Skips listing and goes straight to detail page — fastest path when you already know the video IDs.",
                        "default": [],
                        "items": {
                            "type": "string"
                        }
                    },
                    "resultsPerInput": {
                        "title": "Results per input",
                        "minimum": 0,
                        "maximum": 1000,
                        "type": "integer",
                        "description": "Max videos to return for each profile / hashtag / keyword. Set to 0 for unlimited (until end of feed).",
                        "default": 50
                    },
                    "shouldDownloadVideos": {
                        "title": "Download video files",
                        "type": "boolean",
                        "description": "If true, store video MP4 files in Apify Key-Value Store. WARNING: significantly increases cost & runtime.",
                        "default": false
                    },
                    "shouldDownloadCovers": {
                        "title": "Download cover images",
                        "type": "boolean",
                        "description": "If true, store video thumbnail JPGs in Apify Key-Value Store.",
                        "default": false
                    },
                    "proxy": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Proxy settings. DATACENTER (AUTO) is the recommended default — ~8x cheaper than RESIDENTIAL ($1/GB vs $8/GB) and handles light-to-medium TikTok scraping volume well. If `fallbackToResidential` is on (default) and any seed returns 0 results on this proxy, the actor will automatically retry just that seed on RESIDENTIAL — so you get cheap-by-default with a safety net."
                    },
                    "fallbackToResidential": {
                        "title": "Auto-fallback to RESIDENTIAL on zero results",
                        "type": "boolean",
                        "description": "If a seed returns 0 records on the primary proxy (typically DATACENTER), automatically retry that seed once on RESIDENTIAL ($8/GB). Recommended ON: keeps cost low by default while protecting against TikTok blocking datacenter IPs. Turn OFF if you want a strict cost cap and never want residential billing.",
                        "default": true
                    },
                    "headless": {
                        "title": "Headless browser",
                        "type": "boolean",
                        "description": "Run Playwright in headless mode. Set false only when debugging locally.",
                        "default": true
                    },
                    "maxConcurrency": {
                        "title": "Max concurrency",
                        "minimum": 1,
                        "maximum": 30,
                        "type": "integer",
                        "description": "Max simultaneous browser pages. Higher = faster but more rate-limit risk.",
                        "default": 5
                    },
                    "requestTimeoutSecs": {
                        "title": "Request timeout (s)",
                        "minimum": 10,
                        "maximum": 300,
                        "type": "integer",
                        "description": "Page load timeout in seconds.",
                        "default": 60
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
