{
  "data": {
    "id": "Dawm0G9OaKftgReSB",
    "actId": "qozsOy4Z8clHa7QIw",
    "userId": "NL4ThgItAwaoBlffQ",
    "startedAt": "2026-11-03T21:41:16.427Z",
    "finishedAt": "2026-11-03T21:41:43.296Z",
    "status": "SUCCEEDED",
    "meta": {
      "origin": "CLI"
    },
    "stats": {
      "durationMillis": 26792,
      "runTimeSecs": 26.792,
      "computeUnits": 0.02976888888888889,
      "imageSizeBytes": 3104987136
    },
    "options": {
      "useCache": true,
      "betaPackages": false,
      "memoryMbytes": 4096,
      "diskMbytes": 8192
    },
    "createdByOrganizationMemberUserId": "zifX0mkAFMHe8CatY",
    "exitCode": 0,
    "inputSchema": "{\n  \"title\": \"TikTok Playlist & Collection Scraper Input\",\n  \"description\": \"Scrape TikTok playlists and public collections by URL, numeric ID, profile URL or @username.\",\n  \"type\": \"object\",\n  \"schemaVersion\": 1,\n  \"properties\": {\n    \"playlistUrls\": {\n      \"title\": \"Playlist URLs\",\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"string\"\n      },\n      \"description\": \"Playlist URLs, e.g. https://www.tiktok.com/@natgeo/playlist/Cinematic-7509464647364283178. Collection URLs pasted here are detected automatically.\",\n      \"editor\": \"stringList\",\n      \"prefill\": [\n        \"https://www.tiktok.com/@natgeo/playlist/Cinematic-7509464647364283178\"\n      ]\n    },\n    \"playlistIds\": {\n      \"title\": \"Playlist IDs\",\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"string\"\n      },\n      \"description\": \"Numeric TikTok playlist IDs (15–20 digits). If an ID belongs to a public collection, the collection route is tried automatically.\",\n      \"editor\": \"stringList\"\n    },\n    \"collectionUrls\": {\n      \"title\": \"Collection URLs\",\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"string\"\n      },\n      \"description\": \"Public collection URLs, e.g. https://www.tiktok.com/@user/collection/places-to-go-7154034669288196891.\",\n      \"editor\": \"stringList\"\n    },\n    \"collectionIds\": {\n      \"title\": \"Collection IDs\",\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"string\"\n      },\n      \"description\": \"Numeric TikTok collection IDs (15–20 digits).\",\n      \"editor\": \"stringList\"\n    },\n    \"profileUrls\": {\n      \"title\": \"Profile URLs\",\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"string\"\n      },\n      \"description\": \"TikTok profile URLs. Every public playlist on each profile is discovered, up to the per-profile limit.\",\n      \"editor\": \"stringList\"\n    },\n    \"usernames\": {\n      \"title\": \"Usernames\",\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"string\"\n      },\n      \"description\": \"TikTok handles with or without @. Every public playlist on each profile is discovered.\",\n      \"editor\": \"stringList\"\n    },\n    \"mode\": {\n      \"title\": \"What to Return\",\n      \"type\": \"string\",\n      \"editor\": \"select\",\n      \"description\": \"Return playlist/collection metadata rows, video rows, or both.\",\n      \"enum\": [\n        \"metadata\",\n        \"posts\",\n        \"both\"\n      ],\n      \"enumTitles\": [\n        \"Playlist metadata only\",\n        \"Videos only\",\n        \"Metadata and videos\"\n      ],\n      \"default\": \"both\",\n      \"prefill\": \"metadata\"\n    },\n    \"maxPostsPerPlaylist\": {\n      \"title\": \"Max Videos Per Playlist\",\n      \"type\": \"integer\",\n      \"description\": \"Maximum videos to return from each playlist or collection. Set high enough to cover the full list.\",\n      \"default\": 100,\n      \"minimum\": 1,\n      \"maximum\": 5000,\n      \"prefill\": 1\n    },\n    \"maxPlaylistsPerProfile\": {\n      \"title\": \"Max Playlists Per Profile\",\n      \"type\": \"integer\",\n      \"description\": \"Maximum playlists to process for each profile or username target.\",\n      \"default\": 20,\n      \"minimum\": 1,\n      \"maximum\": 100,\n      \"prefill\": 1\n    },\n    \"maxItems\": {\n      \"title\": \"Max Rows (Global)\",\n      \"type\": \"integer\",\n      \"description\": \"Stop after this many dataset rows across all targets, including status rows. Use 0 for no global limit.\",\n      \"default\": 0,\n      \"minimum\": 0,\n      \"maximum\": 100000,\n      \"prefill\": 1\n    }\n  },\n  \"required\": []\n}",
    "readme": "# TikTok Playlist & Collection Scraper\n\nCollect every public video in a TikTok playlist or collection, in the creator's order, plus the playlist details that make the data usable: cover image, owner, owner stats, view/like/comment counts, sound metadata, media URLs, hashtags, mentions and slideshow images.\n\nGive it a playlist URL, a collection URL, a numeric ID, a profile URL or a plain `@handle`. It returns one row per playlist or collection, one row per video, and clear status rows when a target cannot be read. No login, cookies or proxy setup are needed.\n\n## What this actor does\n\n- Scrapes **playlists** (`/@user/playlist/...`) and **public collections** (`/@user/collection/...`)\n- Accepts full URLs, numeric playlist/collection IDs, profile URLs and handles — mix them in one run\n- Returns the **full ordered video list**, not just the first visible page\n- Discovers every public playlist on a profile, up to a limit you set\n- Adds the playlist cover, creator identity, creator stats, `shareMeta` for collections and a `scrapedAt` timestamp\n- Captures slideshow posts as slideshows with their ordered image URLs\n- Reports invalid, private, empty, blocked and partial targets as `rowType: \"status\"` rows\n- Deduplicates videos by post ID and omits empty fields at every depth\n\n## Input\n\n| Field | Type | Default | Description |\n|---|---|---|---|\n| `playlistUrls` | string[] | – | Playlist URLs. Collection URLs pasted here are detected automatically. |\n| `playlistIds` | string[] | — | Numeric playlist IDs (15–20 digits). A collection ID is retried on the collection route. |\n| `collectionUrls` | string[] | — | Public collection URLs. |\n| `collectionIds` | string[] | — | Numeric collection IDs. |\n| `profileUrls` | string[] | — | Profile URLs; every public playlist on the profile is discovered. |\n| `usernames` | string[] | — | Handles with or without `@`. |\n| `mode` | select | `both` | `metadata`, `posts` or `both`. |\n| `maxPostsPerPlaylist` | integer | 100 | Videos per playlist/collection (1–5000). Raise it for large playlists. |\n| `maxPlaylistsPerProfile` | integer | 20 | Playlists processed per profile (1–100). |\n| `maxItems` | integer | 0 | Global row cap across all targets and status rows. `0` means no cap. |\n\n### Example: one playlist, metadata only\n\n```json\n{\n  \"playlistUrls\": [\"https://www.tiktok.com/@natgeo/playlist/Cinematic-7509464647364283178\"],\n  \"mode\": \"metadata\",\n  \"maxPostsPerPlaylist\": 1\n}\n```\n\n### Example: full playlist in creator order\n\n```json\n{\n  \"playlistUrls\": [\"https://www.tiktok.com/@natgeo/playlist/Cinematic-7509464647364283178\"],\n  \"mode\": \"posts\",\n  \"maxPostsPerPlaylist\": 500\n}\n```\n\n### Example: a public collection by URL or ID\n\n```json\n{\n  \"collectionUrls\": [\"https://www.tiktok.com/@aubreyisamess/collection/places%20to%20go-7154034669288196891\"],\n  \"mode\": \"both\",\n  \"maxPostsPerPlaylist\": 1000\n}\n```\n\n### Example: discover a profile's playlists\n\n```json\n{\n  \"usernames\": [\"natgeo\"],\n  \"mode\": \"metadata\",\n  \"maxPlaylistsPerProfile\": 20\n}\n```\n\n### Example: mixed targets with a global cap\n\n```json\n{\n  \"playlistIds\": [\"7509464647364283178\"],\n  \"collectionIds\": [\"7154034669288196891\"],\n  \"usernames\": [\"natgeo\"],\n  \"mode\": \"both\",\n  \"maxPostsPerPlaylist\": 500,\n  \"maxPlaylistsPerProfile\": 5,\n  \"maxItems\": 250\n}\n```\n\n## Output\n\nAll rows share `rowType`, `scrapedAt` and (when applicable) `playlistId`, `playlistName`, `playlistType` and `playlistUrl`.\n\n### Playlist / collection row (`rowType: \"playlist\"`)\n\n- `playlistType` — `\"playlist\"` or `\"collection\"`\n- `playlistId`, `playlistName`, `videoCount`\n- `playlistUrl` — canonical TikTok URL\n- `playlistCoverUrl` and `coverThumbnailUrl` — cover image (signed, expiring)\n- `coverPostId` — only when TikTok names a cover video\n- `creatorId`, `creatorUsername`, `creatorDisplayName`, `creatorVerified`, `creatorAvatarUrl`\n- `creatorStats` — `followerCount`, `followingCount`, `heartCount`, `videoCount`\n- `shareMeta` — `title` and `desc` for public collections\n- `scrapedAt` — ISO 8601 UTC timestamp\n\n### Video row (`rowType: \"post\"`)\n\n- `playlistId`, `playlistName`, `playlistType`, `playlistUrl`, `positionInPlaylist` (zero-based, source order)\n- `postId`, `postType` (`video` or `slideshow`), `postUrl`\n- `caption`, `textLanguage`, `createTime`, `createdAt`\n- `playCount`, `likeCount`, `commentCount`, `shareCount`, `collectCount`, `repostCount`\n- `commentStatus`, `shareEnabled`, `duetEnabled`, `stitchEnabled`\n- `isAd`, `isECVideo`, `privateItem`, `forFriend`, `originalItem`, `isAigc`, `AIGCDescription`\n- `author` — ID, secure ID, username, display name, bio, verified, avatar, follower/following/heart/video counts\n- `music` — ID, title, author, duration, original flag, cover URL and play URL when TikTok exposes it\n- `video` — dimensions, duration, ratio, definition, codec, bitrate info, play/download/cover URLs\n- `images` — ordered slideshow images with width, height and URL list\n- `hashtags`, `mentions`\n- `mediaUrlExpiresAt` — when signed video/cover URLs expire\n- `scrapedAt`\n\n### Status row (`rowType: \"status\"`)\n\n- `status` — `invalid`, `not_found`, `private`, `empty`, `blocked` or `partial`\n- `input` — the URL, ID or handle that produced the row\n- `playlistId`, `playlistName`, `playlistType` when known\n- `message` — plain-language explanation\n- `scrapedAt`\n\n## Ordering and completeness\n\n`positionInPlaylist` follows the order TikTok serves for that playlist or collection. It is not sorted by publish date, because creators deliberately order series, tutorials and trip lists. Every page is read until the source reports no more videos or your `maxPostsPerPlaylist` / `maxItems` limit is reached.\n\nCollections can report more videos than are publicly accessible (deleted, private or region-locked items are still counted). The actor returns every accessible video once and never invents filler rows.\n\n## Use cases\n\n- Archiving a creator's series before videos disappear\n- Researching how publishers group content into themed playlists\n- Auditing collection-based campaigns and their engagement\n- Building ordered video libraries from travel, education or recipe collections\n- Tracking creator output, follower growth and playlist size over time\n- Feeding ordered short-form video datasets into a CMS, dashboard or model\n\n## FAQ\n\n**Do I need cookies or a login?**\nNo. The actor reads public pages without credentials.\n\n**Do I need to configure a proxy?**\nNo. The actor chooses its own connection automatically.\n\n**Why is `positionInPlaylist` not sorted by date?**\nPlaylists and collections have a creator-defined order. The position preserves that order, which is usually the point of scraping a playlist.\n\n**How many videos will I get?**\nAll publicly accessible videos, up to `maxPostsPerPlaylist` per target and `maxItems` overall. A playlist reported as 34 videos with 34 public items returns 34 rows.\n\n**Why does a collection say 651 videos but return fewer?**\nTikTok counts unavailable entries in the collection total. Only publicly accessible videos can be returned.\n\n**What happens with a bad or private target?**\nThe run finishes successfully and emits a status row explaining the outcome instead of a fake playlist row.\n\n**Are the video and image URLs permanent?**\nNo. TikTok's CDN URLs are signed and expire after a few hours. Use `postUrl` as the stable reference and re-run when you need fresh media URLs.\n\n**Can I combine playlists, collections and profiles in one run?**\nYes. Add any mix of the input arrays. Duplicate targets are processed once.\n\n**What does `maxItems` count?**\nEvery dataset row, including playlist, video and status rows.\n",
    "actorDefinition": {
      "actorSpecification": 1,
      "name": "tiktok-playlist-discovery-and-video-order-scraper",
      "title": "TikTok Playlist & Collection Scraper",
      "description": "Scrape TikTok playlists and public collections in creator order — full video lists with engagement, creator stats, covers, music, media URLs, hashtags, slideshow images and explicit status rows. No cookies or proxy setup.",
      "version": "1.0",
      "buildTag": "latest",
      "defaultMemoryMbytes": 2048,
      "minMemoryMbytes": 1024,
      "meta": {
        "templateId": "python-playwright"
      },
      "input": {
        "title": "TikTok Playlist & Collection Scraper Input",
        "description": "Scrape TikTok playlists and public collections by URL, numeric ID, profile URL or @username.",
        "type": "object",
        "schemaVersion": 1,
        "properties": {
          "playlistUrls": {
            "title": "Playlist URLs",
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Playlist URLs, e.g. https://www.tiktok.com/@natgeo/playlist/Cinematic-7509464647364283178. Collection URLs pasted here are detected automatically.",
            "editor": "stringList",
            "prefill": [
              "https://www.tiktok.com/@natgeo/playlist/Cinematic-7509464647364283178"
            ]
          },
          "playlistIds": {
            "title": "Playlist IDs",
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Numeric TikTok playlist IDs (15–20 digits). If an ID belongs to a public collection, the collection route is tried automatically.",
            "editor": "stringList"
          },
          "collectionUrls": {
            "title": "Collection URLs",
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Public collection URLs, e.g. https://www.tiktok.com/@user/collection/places-to-go-7154034669288196891.",
            "editor": "stringList"
          },
          "collectionIds": {
            "title": "Collection IDs",
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Numeric TikTok collection IDs (15–20 digits).",
            "editor": "stringList"
          },
          "profileUrls": {
            "title": "Profile URLs",
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "TikTok profile URLs. Every public playlist on each profile is discovered, up to the per-profile limit.",
            "editor": "stringList"
          },
          "usernames": {
            "title": "Usernames",
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "TikTok handles with or without @. Every public playlist on each profile is discovered.",
            "editor": "stringList"
          },
          "mode": {
            "title": "What to Return",
            "type": "string",
            "editor": "select",
            "description": "Return playlist/collection metadata rows, video rows, or both.",
            "enum": [
              "metadata",
              "posts",
              "both"
            ],
            "enumTitles": [
              "Playlist metadata only",
              "Videos only",
              "Metadata and videos"
            ],
            "default": "both",
            "prefill": "metadata"
          },
          "maxPostsPerPlaylist": {
            "title": "Max Videos Per Playlist",
            "type": "integer",
            "description": "Maximum videos to return from each playlist or collection. Set high enough to cover the full list.",
            "default": 100,
            "minimum": 1,
            "maximum": 5000,
            "prefill": 1
          },
          "maxPlaylistsPerProfile": {
            "title": "Max Playlists Per Profile",
            "type": "integer",
            "description": "Maximum playlists to process for each profile or username target.",
            "default": 20,
            "minimum": 1,
            "maximum": 100,
            "prefill": 1
          },
          "maxItems": {
            "title": "Max Rows (Global)",
            "type": "integer",
            "description": "Stop after this many dataset rows across all targets, including status rows. Use 0 for no global limit.",
            "default": 0,
            "minimum": 0,
            "maximum": 100000,
            "prefill": 1
          }
        },
        "required": []
      },
      "output": {
        "actorOutputSchemaVersion": 1,
        "title": "TikTok Playlist & Collection Scraper Output",
        "description": "Playlist and collection metadata rows, ordered video rows with engagement and media fields, and visible status rows.",
        "properties": {
          "playlistsAndVideos": {
            "title": "Playlists, collections & videos",
            "type": "string",
            "description": "Dataset containing playlist/collection rows, ordered video rows and status rows.",
            "template": "{{links.apiDefaultDatasetUrl}}/items"
          }
        }
      },
      "dockerfile": "./Dockerfile",
      "readme": "# TikTok Playlist & Collection Scraper\n\nCollect every public video in a TikTok playlist or collection, in the creator's order, plus the playlist details that make the data usable: cover image, owner, owner stats, view/like/comment counts, sound metadata, media URLs, hashtags, mentions and slideshow images.\n\nGive it a playlist URL, a collection URL, a numeric ID, a profile URL or a plain `@handle`. It returns one row per playlist or collection, one row per video, and clear status rows when a target cannot be read. No login, cookies or proxy setup are needed.\n\n## What this actor does\n\n- Scrapes **playlists** (`/@user/playlist/...`) and **public collections** (`/@user/collection/...`)\n- Accepts full URLs, numeric playlist/collection IDs, profile URLs and handles — mix them in one run\n- Returns the **full ordered video list**, not just the first visible page\n- Discovers every public playlist on a profile, up to a limit you set\n- Adds the playlist cover, creator identity, creator stats, `shareMeta` for collections and a `scrapedAt` timestamp\n- Captures slideshow posts as slideshows with their ordered image URLs\n- Reports invalid, private, empty, blocked and partial targets as `rowType: \"status\"` rows\n- Deduplicates videos by post ID and omits empty fields at every depth\n\n## Input\n\n| Field | Type | Default | Description |\n|---|---|---|---|\n| `playlistUrls` | string[] | – | Playlist URLs. Collection URLs pasted here are detected automatically. |\n| `playlistIds` | string[] | — | Numeric playlist IDs (15–20 digits). A collection ID is retried on the collection route. |\n| `collectionUrls` | string[] | — | Public collection URLs. |\n| `collectionIds` | string[] | — | Numeric collection IDs. |\n| `profileUrls` | string[] | — | Profile URLs; every public playlist on the profile is discovered. |\n| `usernames` | string[] | — | Handles with or without `@`. |\n| `mode` | select | `both` | `metadata`, `posts` or `both`. |\n| `maxPostsPerPlaylist` | integer | 100 | Videos per playlist/collection (1–5000). Raise it for large playlists. |\n| `maxPlaylistsPerProfile` | integer | 20 | Playlists processed per profile (1–100). |\n| `maxItems` | integer | 0 | Global row cap across all targets and status rows. `0` means no cap. |\n\n### Example: one playlist, metadata only\n\n```json\n{\n  \"playlistUrls\": [\"https://www.tiktok.com/@natgeo/playlist/Cinematic-7509464647364283178\"],\n  \"mode\": \"metadata\",\n  \"maxPostsPerPlaylist\": 1\n}\n```\n\n### Example: full playlist in creator order\n\n```json\n{\n  \"playlistUrls\": [\"https://www.tiktok.com/@natgeo/playlist/Cinematic-7509464647364283178\"],\n  \"mode\": \"posts\",\n  \"maxPostsPerPlaylist\": 500\n}\n```\n\n### Example: a public collection by URL or ID\n\n```json\n{\n  \"collectionUrls\": [\"https://www.tiktok.com/@aubreyisamess/collection/places%20to%20go-7154034669288196891\"],\n  \"mode\": \"both\",\n  \"maxPostsPerPlaylist\": 1000\n}\n```\n\n### Example: discover a profile's playlists\n\n```json\n{\n  \"usernames\": [\"natgeo\"],\n  \"mode\": \"metadata\",\n  \"maxPlaylistsPerProfile\": 20\n}\n```\n\n### Example: mixed targets with a global cap\n\n```json\n{\n  \"playlistIds\": [\"7509464647364283178\"],\n  \"collectionIds\": [\"7154034669288196891\"],\n  \"usernames\": [\"natgeo\"],\n  \"mode\": \"both\",\n  \"maxPostsPerPlaylist\": 500,\n  \"maxPlaylistsPerProfile\": 5,\n  \"maxItems\": 250\n}\n```\n\n## Output\n\nAll rows share `rowType`, `scrapedAt` and (when applicable) `playlistId`, `playlistName`, `playlistType` and `playlistUrl`.\n\n### Playlist / collection row (`rowType: \"playlist\"`)\n\n- `playlistType` — `\"playlist\"` or `\"collection\"`\n- `playlistId`, `playlistName`, `videoCount`\n- `playlistUrl` — canonical TikTok URL\n- `playlistCoverUrl` and `coverThumbnailUrl` — cover image (signed, expiring)\n- `coverPostId` — only when TikTok names a cover video\n- `creatorId`, `creatorUsername`, `creatorDisplayName`, `creatorVerified`, `creatorAvatarUrl`\n- `creatorStats` — `followerCount`, `followingCount`, `heartCount`, `videoCount`\n- `shareMeta` — `title` and `desc` for public collections\n- `scrapedAt` — ISO 8601 UTC timestamp\n\n### Video row (`rowType: \"post\"`)\n\n- `playlistId`, `playlistName`, `playlistType`, `playlistUrl`, `positionInPlaylist` (zero-based, source order)\n- `postId`, `postType` (`video` or `slideshow`), `postUrl`\n- `caption`, `textLanguage`, `createTime`, `createdAt`\n- `playCount`, `likeCount`, `commentCount`, `shareCount`, `collectCount`, `repostCount`\n- `commentStatus`, `shareEnabled`, `duetEnabled`, `stitchEnabled`\n- `isAd`, `isECVideo`, `privateItem`, `forFriend`, `originalItem`, `isAigc`, `AIGCDescription`\n- `author` — ID, secure ID, username, display name, bio, verified, avatar, follower/following/heart/video counts\n- `music` — ID, title, author, duration, original flag, cover URL and play URL when TikTok exposes it\n- `video` — dimensions, duration, ratio, definition, codec, bitrate info, play/download/cover URLs\n- `images` — ordered slideshow images with width, height and URL list\n- `hashtags`, `mentions`\n- `mediaUrlExpiresAt` — when signed video/cover URLs expire\n- `scrapedAt`\n\n### Status row (`rowType: \"status\"`)\n\n- `status` — `invalid`, `not_found`, `private`, `empty`, `blocked` or `partial`\n- `input` — the URL, ID or handle that produced the row\n- `playlistId`, `playlistName`, `playlistType` when known\n- `message` — plain-language explanation\n- `scrapedAt`\n\n## Ordering and completeness\n\n`positionInPlaylist` follows the order TikTok serves for that playlist or collection. It is not sorted by publish date, because creators deliberately order series, tutorials and trip lists. Every page is read until the source reports no more videos or your `maxPostsPerPlaylist` / `maxItems` limit is reached.\n\nCollections can report more videos than are publicly accessible (deleted, private or region-locked items are still counted). The actor returns every accessible video once and never invents filler rows.\n\n## Use cases\n\n- Archiving a creator's series before videos disappear\n- Researching how publishers group content into themed playlists\n- Auditing collection-based campaigns and their engagement\n- Building ordered video libraries from travel, education or recipe collections\n- Tracking creator output, follower growth and playlist size over time\n- Feeding ordered short-form video datasets into a CMS, dashboard or model\n\n## FAQ\n\n**Do I need cookies or a login?**\nNo. The actor reads public pages without credentials.\n\n**Do I need to configure a proxy?**\nNo. The actor chooses its own connection automatically.\n\n**Why is `positionInPlaylist` not sorted by date?**\nPlaylists and collections have a creator-defined order. The position preserves that order, which is usually the point of scraping a playlist.\n\n**How many videos will I get?**\nAll publicly accessible videos, up to `maxPostsPerPlaylist` per target and `maxItems` overall. A playlist reported as 34 videos with 34 public items returns 34 rows.\n\n**Why does a collection say 651 videos but return fewer?**\nTikTok counts unavailable entries in the collection total. Only publicly accessible videos can be returned.\n\n**What happens with a bad or private target?**\nThe run finishes successfully and emits a status row explaining the outcome instead of a fake playlist row.\n\n**Are the video and image URLs permanent?**\nNo. TikTok's CDN URLs are signed and expire after a few hours. Use `postUrl` as the stable reference and re-run when you need fresh media URLs.\n\n**Can I combine playlists, collections and profiles in one run?**\nYes. Add any mix of the input arrays. Duplicate targets are processed once.\n\n**What does `maxItems` count?**\nEvery dataset row, including playlist, video and status rows.\n",
      "storages": {
        "dataset": {
          "actorSpecification": 1,
          "title": "TikTok Playlists, Collections & Videos",
          "views": {
            "overview": {
              "title": "Playlists & Posts Overview",
              "description": "Mixed dataset with playlist, post and status rows. Use rowType to distinguish them.",
              "transformation": {
                "fields": [
                  "rowType",
                  "playlistType",
                  "playlistId",
                  "playlistName",
                  "videoCount",
                  "creatorUsername",
                  "positionInPlaylist",
                  "postId",
                  "caption",
                  "playCount",
                  "likeCount",
                  "postUrl",
                  "playlistUrl",
                  "scrapedAt"
                ]
              },
              "display": {
                "component": "table",
                "properties": {
                  "rowType": {
                    "label": "Type",
                    "format": "text"
                  },
                  "playlistId": {
                    "label": "Playlist ID",
                    "format": "text"
                  },
                  "playlistName": {
                    "label": "Playlist Name",
                    "format": "text"
                  },
                  "videoCount": {
                    "label": "Video Count",
                    "format": "number"
                  },
                  "creatorUsername": {
                    "label": "Creator",
                    "format": "text"
                  },
                  "positionInPlaylist": {
                    "label": "Position",
                    "format": "number"
                  },
                  "postId": {
                    "label": "Post ID",
                    "format": "text"
                  },
                  "caption": {
                    "label": "Caption",
                    "format": "text"
                  },
                  "playCount": {
                    "label": "Views",
                    "format": "number"
                  },
                  "likeCount": {
                    "label": "Likes",
                    "format": "number"
                  },
                  "postUrl": {
                    "label": "Post URL",
                    "format": "link"
                  },
                  "playlistUrl": {
                    "label": "Playlist URL",
                    "format": "link"
                  },
                  "scrapedAt": {
                    "label": "Scraped At",
                    "format": "text"
                  },
                  "playlistType": {
                    "label": "Playlist Type",
                    "format": "text"
                  }
                }
              }
            },
            "status": {
              "title": "Status Rows",
              "description": "Visible outcomes for invalid, empty, private, blocked or partially fetched targets.",
              "transformation": {
                "fields": [
                  "rowType",
                  "status",
                  "playlistType",
                  "playlistId",
                  "playlistName",
                  "input",
                  "message",
                  "scrapedAt"
                ]
              },
              "display": {
                "component": "table",
                "properties": {
                  "rowType": {
                    "label": "Type",
                    "format": "text"
                  },
                  "status": {
                    "label": "Status",
                    "format": "text"
                  },
                  "playlistType": {
                    "label": "Target Type",
                    "format": "text"
                  },
                  "playlistId": {
                    "label": "Playlist ID",
                    "format": "text"
                  },
                  "playlistName": {
                    "label": "Playlist Name",
                    "format": "text"
                  },
                  "input": {
                    "label": "Input",
                    "format": "text"
                  },
                  "message": {
                    "label": "Message",
                    "format": "text"
                  },
                  "scrapedAt": {
                    "label": "Scraped At",
                    "format": "text"
                  }
                }
              }
            }
          },
          "fields": {
            "rowType": {
              "type": "string",
              "title": "Row Type",
              "description": "Discriminator: 'playlist', 'post' or 'status'."
            },
            "playlistType": {
              "type": "string",
              "title": "Playlist Type",
              "description": "Whether this row describes a playlist or a public collection (playlist and post rows)."
            },
            "playlistId": {
              "type": "string",
              "title": "Playlist ID",
              "description": "TikTok playlist or collection ID (playlist and post rows)."
            },
            "playlistName": {
              "type": "string",
              "title": "Playlist Name",
              "description": "Display name of the playlist or collection (playlist and post rows)."
            },
            "playlistUrl": {
              "type": "string",
              "title": "Playlist URL",
              "description": "Canonical URL of the playlist or collection (playlist and post rows)."
            },
            "playlistCoverUrl": {
              "type": "string",
              "title": "Playlist Cover URL",
              "description": "Cover image URL for the playlist or collection (playlist rows only; signed and expiring)."
            },
            "videoCount": {
              "type": "integer",
              "title": "Video Count",
              "description": "Total number of videos in the playlist as reported by TikTok (playlist rows only)"
            },
            "creatorId": {
              "type": "string",
              "title": "Creator ID",
              "description": "TikTok user ID of the playlist creator (playlist rows only)"
            },
            "creatorUsername": {
              "type": "string",
              "title": "Creator Username",
              "description": "TikTok @username of the playlist creator (playlist rows only)"
            },
            "creatorDisplayName": {
              "type": "string",
              "title": "Creator Display Name",
              "description": "Display name (nickname) of the playlist creator (playlist rows only)"
            },
            "creatorVerified": {
              "type": "boolean",
              "title": "Creator Verified",
              "description": "Whether the playlist creator has a verified badge (playlist rows only)"
            },
            "creatorAvatarUrl": {
              "type": "string",
              "title": "Creator Avatar URL",
              "description": "Avatar image URL of the playlist creator (playlist rows only)"
            },
            "creatorStats": {
              "type": "object",
              "title": "Creator Stats",
              "description": "Creator profile counters at scrape time (playlist rows only, when available).",
              "properties": {
                "followerCount": {
                  "type": "integer",
                  "title": "Followers"
                },
                "followingCount": {
                  "type": "integer",
                  "title": "Following"
                },
                "heartCount": {
                  "type": "integer",
                  "title": "Hearts/Likes"
                },
                "videoCount": {
                  "type": "integer",
                  "title": "Videos"
                }
              }
            },
            "coverPostId": {
              "type": "string",
              "title": "Cover Post ID",
              "description": "Post ID used as the playlist cover thumbnail (playlist rows only)"
            },
            "coverThumbnailUrl": {
              "type": "string",
              "title": "Cover Thumbnail URL",
              "description": "Thumbnail image URL of the playlist cover (playlist rows only)"
            },
            "scrapedAt": {
              "type": "string",
              "title": "Scraped At",
              "description": "ISO 8601 UTC datetime when this row was generated (all row types)."
            },
            "shareMeta": {
              "type": "object",
              "title": "Share Meta",
              "description": "TikTok's share title and description for a public collection (collection rows only).",
              "properties": {
                "title": {
                  "type": "string",
                  "title": "Share Title"
                },
                "desc": {
                  "type": "string",
                  "title": "Share Description"
                }
              }
            },
            "positionInPlaylist": {
              "type": "integer",
              "title": "Position In Playlist",
              "description": "0-based position of the video within the playlist (post rows only)"
            },
            "postId": {
              "type": "string",
              "title": "Post ID",
              "description": "TikTok's unique post/video ID (post rows only)"
            },
            "postUrl": {
              "type": "string",
              "title": "Post URL",
              "description": "Direct URL to the TikTok post (post rows only)"
            },
            "postType": {
              "type": "string",
              "title": "Post Type",
              "description": "Either 'video' or 'slideshow' (post rows only)"
            },
            "caption": {
              "type": "string",
              "title": "Caption",
              "description": "Post caption/description text including hashtags and mentions (post rows only)"
            },
            "textLanguage": {
              "type": "string",
              "title": "Text Language",
              "description": "Detected language code of the caption text (post rows only)"
            },
            "locationCreated": {
              "type": "string",
              "title": "Location Created",
              "description": "ISO country code where the post was created (post rows only)"
            },
            "createTime": {
              "type": "integer",
              "title": "Create Time (Unix)",
              "description": "Unix timestamp (seconds) when the post was created (post rows only)"
            },
            "createdAt": {
              "type": "string",
              "title": "Created At",
              "description": "ISO 8601 UTC datetime when the post was created (post rows only)"
            },
            "playCount": {
              "type": "integer",
              "title": "Play Count",
              "description": "Number of video plays (post rows only)"
            },
            "likeCount": {
              "type": "integer",
              "title": "Like Count",
              "description": "Number of likes/diggs (post rows only)"
            },
            "commentCount": {
              "type": "integer",
              "title": "Comment Count",
              "description": "Number of comments (post rows only)"
            },
            "shareCount": {
              "type": "integer",
              "title": "Share Count",
              "description": "Number of shares (post rows only)"
            },
            "collectCount": {
              "type": "integer",
              "title": "Collect Count",
              "description": "Number of times post was bookmarked/collected (post rows only)"
            },
            "repostCount": {
              "type": "integer",
              "title": "Repost Count",
              "description": "Number of reposts (post rows only)"
            },
            "stitchEnabled": {
              "type": "boolean",
              "title": "Stitch Enabled",
              "description": "Whether the creator allows stitching this video (post rows only)"
            },
            "shareEnabled": {
              "type": "boolean",
              "title": "Share Enabled",
              "description": "Whether sharing is enabled for this post (post rows only)"
            },
            "duetEnabled": {
              "type": "boolean",
              "title": "Duet Enabled",
              "description": "Whether the creator allows duets with this video (post rows only)"
            },
            "commentStatus": {
              "type": "integer",
              "title": "Comment Status",
              "description": "Comment permission setting (0=all, 1=friends, 2=none) (post rows only)"
            },
            "isAd": {
              "type": "boolean",
              "title": "Is Ad",
              "description": "Whether this post is a paid advertisement (post rows only)"
            },
            "privateItem": {
              "type": "boolean",
              "title": "Private Item",
              "description": "Whether the post is set to private (post rows only)"
            },
            "forFriend": {
              "type": "boolean",
              "title": "For Friend",
              "description": "Whether the post is restricted to friends only (post rows only)"
            },
            "originalItem": {
              "type": "boolean",
              "title": "Original Item",
              "description": "Whether this post is an original (non-duet, non-stitch) creation (post rows only)"
            },
            "isAigc": {
              "type": "boolean",
              "title": "Is AI Generated Content",
              "description": "Whether TikTok labels this as AI-generated content (post rows only)"
            },
            "AIGCDescription": {
              "type": "string",
              "title": "AIGC Description",
              "description": "Description for AI-generated content label (post rows only)"
            },
            "isECVideo": {
              "type": "boolean",
              "title": "Is E-Commerce Video",
              "description": "Whether this is a shopping/e-commerce video (post rows only)"
            },
            "adLabelVersion": {
              "type": "integer",
              "title": "Ad Label Version",
              "description": "Ad label version; non-zero when the post is a sponsored ad (post rows only)"
            },
            "viewerRegion": {
              "type": "string",
              "title": "Viewer Region",
              "description": "ISO country code of the inferred viewer region (post rows only)"
            },
            "mediaUrlExpiresAt": {
              "type": "string",
              "title": "Media URL Expires At",
              "description": "ISO 8601 UTC datetime when signed media URLs expire (post rows only)"
            },
            "author": {
              "type": "object",
              "title": "Author",
              "description": "Author/creator information at time of scraping (post rows only)",
              "properties": {
                "id": {
                  "type": "string",
                  "title": "User ID"
                },
                "secUid": {
                  "type": "string",
                  "title": "Secure UID"
                },
                "username": {
                  "type": "string",
                  "title": "Username"
                },
                "displayName": {
                  "type": "string",
                  "title": "Display Name"
                },
                "bio": {
                  "type": "string",
                  "title": "Bio"
                },
                "verified": {
                  "type": "boolean",
                  "title": "Verified"
                },
                "privateAccount": {
                  "type": "boolean",
                  "title": "Private Account"
                },
                "roomId": {
                  "type": "string",
                  "title": "Live Room ID (non-empty when live)"
                },
                "avatarUrl": {
                  "type": "string",
                  "title": "Avatar URL"
                },
                "followerCount": {
                  "type": "integer",
                  "title": "Followers"
                },
                "followingCount": {
                  "type": "integer",
                  "title": "Following"
                },
                "heartCount": {
                  "type": "integer",
                  "title": "Hearts/Likes"
                },
                "videoCount": {
                  "type": "integer",
                  "title": "Videos"
                }
              }
            },
            "music": {
              "type": "object",
              "title": "Music",
              "description": "Sound/music used in the post (post rows only)",
              "properties": {
                "id": {
                  "type": "string",
                  "title": "Music ID"
                },
                "title": {
                  "type": "string",
                  "title": "Title"
                },
                "authorName": {
                  "type": "string",
                  "title": "Author"
                },
                "original": {
                  "type": "boolean",
                  "title": "Original Sound"
                },
                "duration": {
                  "type": "integer",
                  "title": "Duration (s)"
                },
                "isCopyrighted": {
                  "type": "boolean",
                  "title": "Is Copyrighted"
                },
                "isCommerceMusic": {
                  "type": "boolean",
                  "title": "Is Commerce Music"
                },
                "isUnlimitedMusic": {
                  "type": "boolean",
                  "title": "Is Unlimited Music"
                },
                "isPrivate": {
                  "type": "boolean",
                  "title": "Is Private Sound"
                },
                "shootDuration": {
                  "type": "number",
                  "title": "Shoot Duration (s)"
                },
                "album": {
                  "type": "string",
                  "title": "Album"
                },
                "dspLinks": {
                  "type": "array",
                  "title": "DSP Links (Spotify, Apple Music, etc.)"
                },
                "playUrl": {
                  "type": "string",
                  "title": "Play URL"
                },
                "coverUrl": {
                  "type": "string",
                  "title": "Cover URL"
                }
              }
            },
            "video": {
              "type": "object",
              "title": "Video",
              "description": "Video technical metadata and signed play/cover URLs (post rows only)",
              "properties": {
                "width": {
                  "type": "integer",
                  "title": "Width (px)"
                },
                "height": {
                  "type": "integer",
                  "title": "Height (px)"
                },
                "duration": {
                  "type": "integer",
                  "title": "Duration (s)"
                },
                "ratio": {
                  "type": "string",
                  "title": "Aspect Ratio"
                },
                "definition": {
                  "type": "string",
                  "title": "Definition"
                },
                "bitrate": {
                  "type": "integer",
                  "title": "Bitrate"
                },
                "codecType": {
                  "type": "string",
                  "title": "Codec"
                },
                "format": {
                  "type": "string",
                  "title": "Format"
                },
                "size": {
                  "type": "integer",
                  "title": "File Size (bytes)"
                },
                "playUrl": {
                  "type": "string",
                  "title": "Play URL"
                },
                "downloadAddr": {
                  "type": "string",
                  "title": "Download URL"
                },
                "cover": {
                  "type": "string",
                  "title": "Cover Image URL"
                },
                "originCover": {
                  "type": "string",
                  "title": "Original Cover URL"
                },
                "dynamicCover": {
                  "type": "string",
                  "title": "Dynamic Cover URL"
                },
                "videoQuality": {
                  "type": "string",
                  "title": "Video Quality Label"
                },
                "bitrateInfo": {
                  "type": "array",
                  "title": "Bitrate Info",
                  "description": "All available quality/bitrate variants with play URLs (post rows only)"
                },
                "volumeInfo": {
                  "type": "object",
                  "title": "Volume Info",
                  "description": "Audio loudness and peak level metadata (post rows only)"
                }
              }
            },
            "images": {
              "type": "array",
              "title": "Slideshow Images",
              "description": "Images for slideshow posts (postType='slideshow') (post rows only)",
              "items": {
                "type": "object",
                "properties": {
                  "ordinal": {
                    "type": "integer",
                    "title": "Index"
                  },
                  "width": {
                    "type": "integer",
                    "title": "Width"
                  },
                  "height": {
                    "type": "integer",
                    "title": "Height"
                  },
                  "urlList": {
                    "type": "array",
                    "title": "Image URLs"
                  }
                }
              }
            },
            "hashtags": {
              "type": "array",
              "title": "Hashtags",
              "description": "Hashtags used in the post caption (post rows only)",
              "items": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "title": "Hashtag ID"
                  },
                  "name": {
                    "type": "string",
                    "title": "Hashtag Name"
                  },
                  "isCommerce": {
                    "type": "boolean",
                    "title": "Is Commerce"
                  }
                }
              }
            },
            "mentions": {
              "type": "array",
              "title": "Mentions",
              "description": "@mentions in the post caption with text offsets (post rows only)",
              "items": {
                "type": "object",
                "properties": {
                  "username": {
                    "type": "string",
                    "title": "Username"
                  },
                  "start": {
                    "type": "integer",
                    "title": "Start Offset"
                  },
                  "end": {
                    "type": "integer",
                    "title": "End Offset"
                  },
                  "awemeId": {
                    "type": "string",
                    "title": "Mentioned Post ID (if any)"
                  }
                }
              }
            },
            "status": {
              "type": "string",
              "title": "Status",
              "description": "Outcome for a failed or partial target: invalid, not_found, private, empty, blocked or partial (status rows only)."
            },
            "input": {
              "type": "string",
              "title": "Input",
              "description": "The original URL, ID or handle that produced this status row (status rows only)."
            },
            "message": {
              "type": "string",
              "title": "Message",
              "description": "Human-readable explanation of the status outcome (status rows only)."
            },
            "poi": {
              "type": "object",
              "title": "Point of Interest",
              "description": "TikTok POI/location attachment when the video carries one (post rows only)."
            },
            "diversificationLabels": {
              "type": "array",
              "title": "Diversification Labels",
              "description": "TikTok topic labels attached to the video when present (post rows only)."
            }
          }
        }
      }
    },
    "buildNumber": "1.0.3",
    "imageDigest": "5fa15cc4b86ab4bd72aafbf472debbc15b15c325ea3509142186913ab56564d9",
    "actVersion": {
      "sourceType": "SOURCE_FILES",
      "buildTag": "latest",
      "versionNumber": "1.0"
    },
    "usage": {
      "ACTOR_COMPUTE_UNITS": 0.02976888888888889
    }
  }
}