{
  "data": {
    "id": "2UQXiXaxsuYUu84NM",
    "actId": "K3oXPDtelCgqk16MF",
    "userId": "IYgBDiXtHOijAaUel",
    "startedAt": "2026-11-09T12:59:31.948Z",
    "finishedAt": "2026-11-09T13:00:01.896Z",
    "status": "SUCCEEDED",
    "meta": {
      "origin": "CLI"
    },
    "stats": {
      "durationMillis": 29886,
      "runTimeSecs": 29.886,
      "computeUnits": 0.03320666666666667,
      "imageSizeBytes": 3113403392
    },
    "options": {
      "useCache": true,
      "betaPackages": false,
      "memoryMbytes": 4096,
      "diskMbytes": 8192
    },
    "createdByOrganizationMemberUserId": "QYo53EZkJk0prePWY",
    "exitCode": 0,
    "inputSchema": "{\n  \"title\": \"YouTube Channel Scraper Input\",\n  \"type\": \"object\",\n  \"schemaVersion\": 1,\n  \"required\": [\n    \"channelUrls\"\n  ],\n  \"properties\": {\n    \"channelUrls\": {\n      \"title\": \"Channel URLs\",\n      \"type\": \"array\",\n      \"description\": \"YouTube channel URLs, handles (@username), or channel IDs (UCxxx). Accepts any format.\",\n      \"editor\": \"stringList\",\n      \"prefill\": [\n        \"https://www.youtube.com/@Apify\"\n      ],\n      \"items\": {\n        \"type\": \"string\"\n      },\n      \"minItems\": 1\n    },\n    \"maxVideos\": {\n      \"title\": \"Max Videos Per Channel\",\n      \"type\": \"integer\",\n      \"description\": \"Maximum number of videos to scrape per channel. Set to 0 to get only channel info without videos. The 10,000 cap is an intentional policy limit for a bounded run. Exact player metadata refresh has a 900-second budget per actor run; if that budget is reached, remaining rows keep the listing metadata (title, view text, relative date) and the run still emits the full dataset.\",\n      \"default\": 50,\n      \"minimum\": 0,\n      \"maximum\": 10000,\n      \"editor\": \"number\",\n      \"prefill\": 3\n    },\n    \"videoSource\": {\n      \"title\": \"Video Source\",\n      \"type\": \"string\",\n      \"description\": \"Where to read the video list from. The uploads playlist is a complete chronological feed that also includes Shorts and uploads the Videos tab omits. 'Both' merges the two sources, de-duplicated by video ID, then applies the chosen sort.\",\n      \"default\": \"videosTab\",\n      \"prefill\": \"videosTab\",\n      \"enum\": [\n        \"videosTab\",\n        \"uploadsPlaylist\",\n        \"both\"\n      ],\n      \"enumTitles\": [\n        \"Videos tab (default)\",\n        \"Uploads playlist (catches Shorts and omissions)\",\n        \"Both (Videos tab first, then uploads-only videos)\"\n      ],\n      \"editor\": \"select\",\n      \"sectionCaption\": \"Video source, sorting & details\",\n      \"sectionDescription\": \"Choose where the video list comes from, how it is ordered, and whether exact comment counts are fetched. The uploads playlist uses the channel's UU playlist ID and returns 100 videos per page.\"\n    },\n    \"sortVideosBy\": {\n      \"title\": \"Sort Videos By\",\n      \"type\": \"string\",\n      \"description\": \"How to order the channel's videos. The uploads playlist is already newest-first; Popular/Oldest are applied client-side to a scan window of max(maxVideos, min(2 * maxVideos, 60)) videos. The Videos tab uses YouTube's native sort chips across its full history.\",\n      \"default\": \"newest\",\n      \"prefill\": \"newest\",\n      \"enum\": [\n        \"newest\",\n        \"popular\",\n        \"oldest\"\n      ],\n      \"enumTitles\": [\n        \"Newest first\",\n        \"Most popular\",\n        \"Oldest first\"\n      ],\n      \"editor\": \"select\"\n    },\n    \"sortShortsBy\": {\n      \"title\": \"Sort Shorts By\",\n      \"type\": \"string\",\n      \"description\": \"Order of the Shorts tab when 'Include Channel Shorts' is on. The Shorts tab exposes Latest, Popular and Oldest filters.\",\n      \"default\": \"latest\",\n      \"prefill\": \"latest\",\n      \"enum\": [\n        \"latest\",\n        \"popular\",\n        \"oldest\"\n      ],\n      \"enumTitles\": [\n        \"Latest first\",\n        \"Most popular\",\n        \"Oldest first\"\n      ],\n      \"editor\": \"select\"\n    },\n    \"includeCommentCounts\": {\n      \"title\": \"Include Exact Comment Counts\",\n      \"type\": \"boolean\",\n      \"default\": false,\n      \"prefill\": false,\n      \"description\": \"Fetch the exact public comment count for every video. Costs up to two extra requests per video: a /next seed (reused from the description-enrichment call when that already ran) plus a comments-continuation request when the count is not in the seed. The field is skipped for videos with comments disabled.\"\n    },\n    \"onlyNewVideos\": {\n      \"title\": \"Only New Videos Since Last Run\",\n      \"type\": \"boolean\",\n      \"default\": false,\n      \"prefill\": false,\n      \"description\": \"Monitor mode: return only videos not returned by an earlier run for the same channel. State is kept in the actor's named key-value store, which persists across runs. Only emitted rows are marked seen, so maxVideos pauses the remainder instead of skipping it.\"\n    },\n    \"includeAbout\": {\n      \"title\": \"Include About Page Data\",\n      \"type\": \"boolean\",\n      \"default\": true,\n      \"prefill\": true,\n      \"description\": \"Extract total views, join date, location, external links and channel analytics from the channel About page and video sample.\",\n      \"sectionCaption\": \"Channel sections\",\n      \"sectionDescription\": \"Optional extra channel tabs. Toggle off for the fastest run.\"\n    },\n    \"includePlaylists\": {\n      \"title\": \"Include Channel Playlists\",\n      \"type\": \"boolean\",\n      \"default\": false,\n      \"prefill\": false,\n      \"description\": \"Scrape the channel Playlists tab and include playlist metadata in the output.\"\n    },\n    \"maxPlaylists\": {\n      \"title\": \"Max Playlists\",\n      \"type\": \"integer\",\n      \"default\": 20,\n      \"prefill\": 20,\n      \"minimum\": 1,\n      \"maximum\": 500,\n      \"description\": \"Maximum number of playlists to scrape (when includePlaylists is enabled).\"\n    },\n    \"includeShorts\": {\n      \"title\": \"Include Channel Shorts\",\n      \"type\": \"boolean\",\n      \"default\": false,\n      \"prefill\": false,\n      \"description\": \"Scrape the channel Shorts tab and include Shorts in the output. Also marks matching uploads-playlist videos with isShort.\"\n    },\n    \"maxShorts\": {\n      \"title\": \"Max Shorts\",\n      \"type\": \"integer\",\n      \"default\": 20,\n      \"prefill\": 20,\n      \"minimum\": 1,\n      \"maximum\": 2000,\n      \"description\": \"Maximum number of Shorts to return (when includeShorts is enabled).\"\n    },\n    \"includeLiveVideos\": {\n      \"title\": \"Include Live/Stream Videos\",\n      \"type\": \"boolean\",\n      \"default\": false,\n      \"prefill\": false,\n      \"description\": \"Scrape the channel Live/Streams tab and include live/archived streams.\"\n    },\n    \"maxLiveVideos\": {\n      \"title\": \"Max Live Videos\",\n      \"type\": \"integer\",\n      \"default\": 20,\n      \"prefill\": 20,\n      \"minimum\": 1,\n      \"maximum\": 500,\n      \"description\": \"Maximum live/stream videos to return.\"\n    },\n    \"market\": {\n      \"title\": \"Market / Region\",\n      \"type\": \"string\",\n      \"default\": \"US\",\n      \"prefill\": \"US\",\n      \"enum\": [\n        \"US\",\n        \"GB\",\n        \"CA\",\n        \"AU\",\n        \"DE\",\n        \"FR\",\n        \"JP\",\n        \"KR\",\n        \"BR\",\n        \"IN\",\n        \"MX\",\n        \"IT\",\n        \"ES\",\n        \"NL\",\n        \"PL\",\n        \"RU\",\n        \"SE\",\n        \"NO\",\n        \"DK\",\n        \"FI\",\n        \"ZA\",\n        \"SG\",\n        \"HK\",\n        \"TW\",\n        \"ID\",\n        \"MY\",\n        \"TH\",\n        \"PH\",\n        \"AR\",\n        \"CO\",\n        \"CL\"\n      ],\n      \"enumTitles\": [\n        \"United States\",\n        \"United Kingdom\",\n        \"Canada\",\n        \"Australia\",\n        \"Germany\",\n        \"France\",\n        \"Japan\",\n        \"South Korea\",\n        \"Brazil\",\n        \"India\",\n        \"Mexico\",\n        \"Italy\",\n        \"Spain\",\n        \"Netherlands\",\n        \"Poland\",\n        \"Russia\",\n        \"Sweden\",\n        \"Norway\",\n        \"Denmark\",\n        \"Finland\",\n        \"South Africa\",\n        \"Singapore\",\n        \"Hong Kong\",\n        \"Taiwan\",\n        \"Indonesia\",\n        \"Malaysia\",\n        \"Thailand\",\n        \"Philippines\",\n        \"Argentina\",\n        \"Colombia\",\n        \"Chile\"\n      ],\n      \"description\": \"Country context (gl) applied to every page and InnerTube request, including pagination, player and comment endpoints.\",\n      \"editor\": \"select\",\n      \"sectionCaption\": \"Localization\",\n      \"sectionDescription\": \"Country and language context sent to YouTube for every request.\"\n    },\n    \"language\": {\n      \"title\": \"Language\",\n      \"type\": \"string\",\n      \"default\": \"en\",\n      \"prefill\": \"en\",\n      \"enum\": [\n        \"en\",\n        \"es\",\n        \"fr\",\n        \"de\",\n        \"pt\",\n        \"it\",\n        \"nl\",\n        \"pl\",\n        \"ru\",\n        \"ja\",\n        \"ko\",\n        \"zh\",\n        \"hi\",\n        \"ar\",\n        \"tr\",\n        \"id\",\n        \"th\",\n        \"vi\",\n        \"sv\",\n        \"no\",\n        \"da\",\n        \"fi\",\n        \"cs\",\n        \"el\",\n        \"he\",\n        \"uk\",\n        \"ro\",\n        \"hu\",\n        \"ms\",\n        \"bn\"\n      ],\n      \"enumTitles\": [\n        \"English\",\n        \"Spanish\",\n        \"French\",\n        \"German\",\n        \"Portuguese\",\n        \"Italian\",\n        \"Dutch\",\n        \"Polish\",\n        \"Russian\",\n        \"Japanese\",\n        \"Korean\",\n        \"Chinese\",\n        \"Hindi\",\n        \"Arabic\",\n        \"Turkish\",\n        \"Indonesian\",\n        \"Thai\",\n        \"Vietnamese\",\n        \"Swedish\",\n        \"Norwegian\",\n        \"Danish\",\n        \"Finnish\",\n        \"Czech\",\n        \"Greek\",\n        \"Hebrew\",\n        \"Ukrainian\",\n        \"Romanian\",\n        \"Hungarian\",\n        \"Malay\",\n        \"Bengali\"\n      ],\n      \"description\": \"Interface language (hl) for labels and relative dates. Titles and descriptions stay in the creator's language.\",\n      \"editor\": \"select\"\n    }\n  }\n}",
    "readme": "# YouTube Channel Video Feed Quick Scraper\r\n\r\nPoint this actor at one or more YouTube channels and get back their video list — newest, most popular or oldest first — with exact publish dates, exact like counts, categories, tags and a full channel profile. It reads YouTube's own public pages, so there is no API key and no login.\r\n\r\n## What this actor does\r\n\r\n- Accepts any mix of channel handles (`@name`), full channel URLs, or raw channel IDs across a single run\r\n- Reads the Videos tab, the channel's uploads playlist (`UU{channelId}`), or both; the uploads playlist is a complete chronological feed that also includes Shorts and uploads the Videos tab omits. \"Both\" merges the sources, de-duplicated by video ID, then applies the chosen sort\r\n- Returns exact `publishDate`, `likeCount`, `category` and `tags` for each video from YouTube's player response\r\n- Optionally resolves exact public comment counts per video\r\n- Sorts videos newest, most popular, or oldest first; Shorts have their own Latest/Popular/Oldest filter\r\n- Can emit only videos that are new since the previous monitor run\r\n- Adds derived channel analytics: last upload date, average views, upload gap in days and sample size\r\n- Optionally pulls the channel's About-page data (total views, join date, location, social links), Shorts, Playlists, and Live/Streams tabs\r\n- Returns a channel-info-only row (no video fields) when `maxVideos` is set to `0`\r\n- Applies a country and interface language to every request, including pagination and player endpoints\r\n- Omits any field YouTube did not expose for that video or channel — it never fills a gap with an empty string or a made-up value\r\n\r\n## Output per video row\r\n\r\nEvery video row has `recordType: \"video\"` and `sourceUrl` set to its watch URL, plus the full `authorMetadata` object for its channel. A channel-info-only row (`maxVideos: 0` or a channel with no listed videos) has `recordType: \"channel\"` and `sourceUrl` set to the channel URL. A failed channel emits `recordType: \"error\"`.\r\n\r\n- `recordType`, `sourceUrl`, `videoId`, `title`, `url`\r\n- `viewCount` — only when YouTube's own data exposes an exact integer; a rounded label like \"93K views\" stays in `viewCountText` and is never converted into a fake exact number\r\n- `viewCountText`, `publishedTimeText` — the relative label exactly as YouTube displays it\r\n- `likeCount` — exact integer from the player response, when YouTube exposes it\r\n- `commentCount` — exact integer, only when `includeCommentCounts` is on and the video has a public comment section\r\n- `publishDate` — exact ISO 8601 publish timestamp with YouTube's original UTC offset\r\n- `uploadDate` — only when it differs from `publishDate`\r\n- `category` — YouTube's category label, e.g. `\"Science & Technology\"`\r\n- `tags` — the creator's video tags, when any were set\r\n- `duration` — may be the literal string `\"LIVE\"` for an ongoing stream; `durationSeconds` is only present once YouTube reports a finite length\r\n- `thumbnailUrl`, `description`\r\n- `isLive`, `isShort`\r\n- `badges` — labels shown on the video tile, e.g. `[\"LIVE\"]` or `[\"NEW\"]`, when any apply\r\n- `shorts[]`, `playlists[]`, `liveVideos[]` — only present when the matching `include...` input is on\r\n- `scrapedAt`\r\n\r\n### `authorMetadata` fields\r\n\r\n- `channelId`, `channelName`, `handle`, `channelUrl`\r\n- `description` — the channel's short header description\r\n- `aboutDescription` — the longer description shown on the channel's About page, when `includeAbout` is on\r\n- `subscriberCount` — only when YouTube's source data gives an exact integer; `subscriberCountText` always carries the displayed label (e.g. \"466M subscribers\")\r\n- `videoCount`, `videoCountText` — same exact-vs-rounded distinction as subscribers\r\n- `country`, `location` — `location` and `totalViews`/`totalViewsText`/`joinedDateText` come from the About page (`includeAbout`)\r\n- `joinedDateText`, `totalViews`, `totalViewsText`\r\n- `externalLinks[]` — links listed on the About page (`includeAbout`); `channelLinks[]` — links shown directly on the channel header\r\n- `lastUploadDate`, `averageViews`, `uploadFrequencyDays`, `videosAnalyzed` — channel analytics derived from the exact rows returned by this run\r\n- `rssUrl`, `avatarUrl`, `bannerUrl`\r\n- `isVerified`, `isFamilySafe`\r\n- `isOfficialArtistChannel` — only present when the channel carries YouTube's official-artist badge\r\n- `keywords[]`\r\n\r\n## Input\r\n\r\n| Field | Type | Default | Description |\r\n|---|---|---|---|\r\n| `channelUrls` | array | – | Channel URLs, handles or channel IDs, any mix |\r\n| `maxVideos` | integer | `50` | Max videos per channel (0–10000; 10,000 is a policy cap, `0` returns channel info only). Exact player metadata refresh has a 900-second budget per run; beyond it rows keep listing metadata |\r\n| `videoSource` | string | `videosTab` | `videosTab`, `uploadsPlaylist` (catches Shorts and omissions) or `both` |\r\n| `sortVideosBy` | string | `newest` | `newest`, `popular` or `oldest` |\r\n| `sortShortsBy` | string | `latest` | `latest`, `popular` or `oldest` for the Shorts tab |\r\n| `includeCommentCounts` | boolean | `false` | Fetch exact comment counts (up to two extra requests per video; the description `/next` response is reused when available) |\r\n| `onlyNewVideos` | boolean | `false` | Monitor mode: emit only videos not seen by a previous run |\r\n| `includeAbout` | boolean | `true` | Pull total views, join date, location, links and analytics |\r\n| `includePlaylists` | boolean | `false` | Include the channel's Playlists tab |\r\n| `maxPlaylists` | integer | `20` | Max playlists to return when `includePlaylists` is on (1–500) |\r\n| `includeShorts` | boolean | `false` | Include the channel's Shorts tab and mark matching videos with `isShort` |\r\n| `maxShorts` | integer | `20` | Max Shorts to return when `includeShorts` is on (1–2000) |\r\n| `includeLiveVideos` | boolean | `false` | Include the channel's Live/Streams tab |\r\n| `maxLiveVideos` | integer | `20` | Max live/stream videos to return (1–500) |\r\n| `market` | string | `US` | Country code (`gl`) applied to every request (31 supported) |\r\n| `language` | string | `en` | Interface language (`hl`), 30 supported |\r\n\r\n### Example: a few channels' latest uploads\r\n\r\n```json\r\n{\r\n  \"channelUrls\": [\"@Apify\", \"@mkbhd\"],\r\n  \"maxVideos\": 10,\r\n  \"sortVideosBy\": \"newest\"\r\n}\r\n```\r\n\r\n### Example: uploads playlist to include Shorts and omitted uploads\r\n\r\n```json\r\n{\r\n  \"channelUrls\": [\"@mkbhd\"],\r\n  \"maxVideos\": 100,\r\n  \"videoSource\": \"both\",\r\n  \"includeShorts\": true,\r\n  \"sortShortsBy\": \"popular\"\r\n}\r\n```\r\n\r\n### Example: recent videos with exact engagement metrics\r\n\r\n```json\r\n{\r\n  \"channelUrls\": [\"@MrBeast\"],\r\n  \"maxVideos\": 20,\r\n  \"includeCommentCounts\": true\r\n}\r\n```\r\n\r\n### Example: monitor a channel for new uploads\r\n\r\n```json\r\n{\r\n  \"channelUrls\": [\"@Fireship\"],\r\n  \"maxVideos\": 10,\r\n  \"onlyNewVideos\": true,\r\n  \"videoSource\": \"uploadsPlaylist\"\r\n}\r\n```\r\n\r\n### Example: channel profile only, no videos\r\n\r\n```json\r\n{\r\n  \"channelUrls\": [\"@mrbeast\"],\r\n  \"maxVideos\": 0\r\n}\r\n```\r\n\r\n## Use cases\r\n\r\n- **Bulk channel monitoring** — track upload activity across a long list of channels on a recurring schedule\r\n- **New-upload alerts** — `onlyNewVideos` emits just the videos published since the previous run\r\n- **Competitor benchmarking** — compare exact view/like counts and posting cadence across several creators in a niche\r\n- **Influencer shortlisting** — pull subscriber counts, verification status and social links for a batch of candidate channels\r\n- **Content inventory** — build a catalog of a channel's videos, Shorts and playlists, including uploads the Videos tab hides\r\n- **Engagement analysis** — export exact like/comment counts and category/tag metadata for a published date range\r\n- **Growth tracking** — re-run on a schedule to watch subscriber and view counts change over time\r\n\r\n## FAQ\r\n\r\n**Is a YouTube API key needed?**\r\nNo — this actor reads YouTube's own public channel and video pages and needs no API key or login.\r\n\r\n**Which channel reference formats work?**\r\nA `@handle`, a full `/channel/UC...` URL, a full `@handle` URL, or a raw channel ID all resolve to the same channel.\r\n\r\n**What is the difference between the Videos tab and the uploads playlist?**\r\nThe Videos tab is a curated 30-per-page list. The uploads playlist (`UU` + the channel ID without its `UC` prefix) is the complete chronological feed and returns 100 videos per page. It also includes Shorts and other uploads the Videos tab omits. Use `videoSource: \"uploadsPlaylist\"` when coverage matters.\r\n\r\n**Are like counts exact?**\r\nYes. `likeCount` comes from YouTube's player response as an exact integer. The rounded label YouTube shows in the interface is not used.\r\n\r\n**Why is `commentCount` missing?**\r\nComment counts are opt-in (`includeCommentCounts`). They cost up to two extra requests per video: a `/next` seed request and, when the seed does not already contain the count, a comments-continuation request. When the actor already fetched `/next` for the description, that response is reused so no second seed request is made. The field is omitted when the video has comments disabled or no public comment section. A count of `0` is a real value and is kept.\r\n\r\n**Why is `viewCount` sometimes missing even though `viewCountText` shows a number?**\r\nYouTube's video-card label is often rounded (e.g. \"93K views\"). This actor only fills `viewCount` when the underlying data gives an exact figure, rather than reverse-engineering an approximate one.\r\n\r\n**Why would `duration` show `\"LIVE\"` with no `durationSeconds`?**\r\nThat's an ongoing live stream — its length isn't final yet, so there's nothing finite to report until the broadcast ends.\r\n\r\n**Does \"popular\" or \"oldest\" sort the whole uploads playlist?**\r\nNo. The uploads playlist has no server-side sort menu, so those orders are applied client-side to a scan window of `max(maxVideos, min(2 × maxVideos, 60))` videos. For a full-history Popular/Oldest sort, use `videoSource: \"videosTab\"`, which has YouTube's native sort chips.\r\n\r\n**Can I filter by exact publish date?**\r\nNot in this version. Exact dates come from YouTube's player response, which is frequently unavailable to guest requests; exposing a date filter would silently return 0 videos. Use the channel's video list and filter downstream by `publishDate` when it is present, or use `onlyNewVideos` for ongoing monitoring.\r\n\r\n**How does monitor mode store what it has seen?**\r\n`onlyNewVideos` keeps a per-channel list of video IDs in the actor's named `youtube-channel-monitor` key-value store, which persists across runs. The first run returns the normal window; later runs emit only new IDs. Only the rows actually returned are marked as seen, so a `maxVideos` cap pauses the remaining new videos instead of skipping them permanently.\r\n\r\n**Does `market` or `language` change which videos are returned?**\r\n`market` sends the country context (`gl`) and `language` sends the interface language (`hl`) on every page and InnerTube request, including pagination, player and comment calls. They affect localized labels, relative dates, and regionally restricted content. Neither changes which channel you look up.\r\n\r\n**Can I fetch 5,000+ videos from one channel?**\r\nYes — `maxVideos` goes up to 10,000. With `videoSource: \"uploadsPlaylist\"` the actor pages 100 videos at a time until it reaches your cap or the channel's uploads run out. The 10,000 cap is an intentional policy limit, and the exact player-metadata pass has a 900-second budget per run: if that budget runs out on a very large request, the remaining rows keep their listing data (title, view label, relative date) and the run still completes with the full dataset.\r\n\r\n**What about members-only, age-restricted or private videos?**\r\nPublic listing cards for members-only and age-restricted videos can still be returned, but YouTube gates their playback to signed-in viewers, so playback-only fields (exact metrics, description) may be missing for those rows. Private and deleted videos cannot be fetched at all.\r\n\r\n**What is `recordType`?**\r\nIt tells rows apart without inspecting which fields are present: `video` for normal video rows, `channel` for the channel-info-only row, and `error` for a channel that could not be fetched.\r\n\r\n**Can I get the channel's public business email?**\r\nNo. YouTube only reveals a business email after a Google sign-in and shows a \"Sign in to see email address\" gate to logged-out visitors. Public social and website links are still returned in `externalLinks`.\r\n\r\n**Why are subscriber counts sometimes rounded?**\r\nYouTube displays subscriber and video counts as rounded labels (e.g. \"21.4M subscribers\"). The actor keeps that text in `subscriberCountText`/`videoCountText` and only fills the integer when YouTube exposes an exact value.\r\n",
    "actorDefinition": {
      "actorSpecification": 1,
      "name": "youtube-channel-video-feed-quick-scraper",
      "title": "YouTube Channel Video Feed Quick Scraper",
      "description": "List any YouTube channel's videos from the Videos tab or complete uploads playlist with exact dates, likes, categories and tags, optional comments, monitoring, analytics, Shorts, playlists and live streams.",
      "version": "1.0",
      "buildTag": "latest",
      "environmentVariables": {},
      "dockerfile": "../Dockerfile",
      "input": {
        "title": "YouTube Channel Scraper Input",
        "type": "object",
        "schemaVersion": 1,
        "required": [
          "channelUrls"
        ],
        "properties": {
          "channelUrls": {
            "title": "Channel URLs",
            "type": "array",
            "description": "YouTube channel URLs, handles (@username), or channel IDs (UCxxx). Accepts any format.",
            "editor": "stringList",
            "prefill": [
              "https://www.youtube.com/@Apify"
            ],
            "items": {
              "type": "string"
            },
            "minItems": 1
          },
          "maxVideos": {
            "title": "Max Videos Per Channel",
            "type": "integer",
            "description": "Maximum number of videos to scrape per channel. Set to 0 to get only channel info without videos. The 10,000 cap is an intentional policy limit for a bounded run. Exact player metadata refresh has a 900-second budget per actor run; if that budget is reached, remaining rows keep the listing metadata (title, view text, relative date) and the run still emits the full dataset.",
            "default": 50,
            "minimum": 0,
            "maximum": 10000,
            "editor": "number",
            "prefill": 3
          },
          "videoSource": {
            "title": "Video Source",
            "type": "string",
            "description": "Where to read the video list from. The uploads playlist is a complete chronological feed that also includes Shorts and uploads the Videos tab omits. 'Both' merges the two sources, de-duplicated by video ID, then applies the chosen sort.",
            "default": "videosTab",
            "prefill": "videosTab",
            "enum": [
              "videosTab",
              "uploadsPlaylist",
              "both"
            ],
            "enumTitles": [
              "Videos tab (default)",
              "Uploads playlist (catches Shorts and omissions)",
              "Both (Videos tab first, then uploads-only videos)"
            ],
            "editor": "select",
            "sectionCaption": "Video source, sorting & details",
            "sectionDescription": "Choose where the video list comes from, how it is ordered, and whether exact comment counts are fetched. The uploads playlist uses the channel's UU playlist ID and returns 100 videos per page."
          },
          "sortVideosBy": {
            "title": "Sort Videos By",
            "type": "string",
            "description": "How to order the channel's videos. The uploads playlist is already newest-first; Popular/Oldest are applied client-side to a scan window of max(maxVideos, min(2 * maxVideos, 60)) videos. The Videos tab uses YouTube's native sort chips across its full history.",
            "default": "newest",
            "prefill": "newest",
            "enum": [
              "newest",
              "popular",
              "oldest"
            ],
            "enumTitles": [
              "Newest first",
              "Most popular",
              "Oldest first"
            ],
            "editor": "select"
          },
          "sortShortsBy": {
            "title": "Sort Shorts By",
            "type": "string",
            "description": "Order of the Shorts tab when 'Include Channel Shorts' is on. The Shorts tab exposes Latest, Popular and Oldest filters.",
            "default": "latest",
            "prefill": "latest",
            "enum": [
              "latest",
              "popular",
              "oldest"
            ],
            "enumTitles": [
              "Latest first",
              "Most popular",
              "Oldest first"
            ],
            "editor": "select"
          },
          "includeCommentCounts": {
            "title": "Include Exact Comment Counts",
            "type": "boolean",
            "default": false,
            "prefill": false,
            "description": "Fetch the exact public comment count for every video. Costs up to two extra requests per video: a /next seed (reused from the description-enrichment call when that already ran) plus a comments-continuation request when the count is not in the seed. The field is skipped for videos with comments disabled."
          },
          "onlyNewVideos": {
            "title": "Only New Videos Since Last Run",
            "type": "boolean",
            "default": false,
            "prefill": false,
            "description": "Monitor mode: return only videos not returned by an earlier run for the same channel. State is kept in the actor's named key-value store, which persists across runs. Only emitted rows are marked seen, so maxVideos pauses the remainder instead of skipping it."
          },
          "includeAbout": {
            "title": "Include About Page Data",
            "type": "boolean",
            "default": true,
            "prefill": true,
            "description": "Extract total views, join date, location, external links and channel analytics from the channel About page and video sample.",
            "sectionCaption": "Channel sections",
            "sectionDescription": "Optional extra channel tabs. Toggle off for the fastest run."
          },
          "includePlaylists": {
            "title": "Include Channel Playlists",
            "type": "boolean",
            "default": false,
            "prefill": false,
            "description": "Scrape the channel Playlists tab and include playlist metadata in the output."
          },
          "maxPlaylists": {
            "title": "Max Playlists",
            "type": "integer",
            "default": 20,
            "prefill": 20,
            "minimum": 1,
            "maximum": 500,
            "description": "Maximum number of playlists to scrape (when includePlaylists is enabled)."
          },
          "includeShorts": {
            "title": "Include Channel Shorts",
            "type": "boolean",
            "default": false,
            "prefill": false,
            "description": "Scrape the channel Shorts tab and include Shorts in the output. Also marks matching uploads-playlist videos with isShort."
          },
          "maxShorts": {
            "title": "Max Shorts",
            "type": "integer",
            "default": 20,
            "prefill": 20,
            "minimum": 1,
            "maximum": 2000,
            "description": "Maximum number of Shorts to return (when includeShorts is enabled)."
          },
          "includeLiveVideos": {
            "title": "Include Live/Stream Videos",
            "type": "boolean",
            "default": false,
            "prefill": false,
            "description": "Scrape the channel Live/Streams tab and include live/archived streams."
          },
          "maxLiveVideos": {
            "title": "Max Live Videos",
            "type": "integer",
            "default": 20,
            "prefill": 20,
            "minimum": 1,
            "maximum": 500,
            "description": "Maximum live/stream videos to return."
          },
          "market": {
            "title": "Market / Region",
            "type": "string",
            "default": "US",
            "prefill": "US",
            "enum": [
              "US",
              "GB",
              "CA",
              "AU",
              "DE",
              "FR",
              "JP",
              "KR",
              "BR",
              "IN",
              "MX",
              "IT",
              "ES",
              "NL",
              "PL",
              "RU",
              "SE",
              "NO",
              "DK",
              "FI",
              "ZA",
              "SG",
              "HK",
              "TW",
              "ID",
              "MY",
              "TH",
              "PH",
              "AR",
              "CO",
              "CL"
            ],
            "enumTitles": [
              "United States",
              "United Kingdom",
              "Canada",
              "Australia",
              "Germany",
              "France",
              "Japan",
              "South Korea",
              "Brazil",
              "India",
              "Mexico",
              "Italy",
              "Spain",
              "Netherlands",
              "Poland",
              "Russia",
              "Sweden",
              "Norway",
              "Denmark",
              "Finland",
              "South Africa",
              "Singapore",
              "Hong Kong",
              "Taiwan",
              "Indonesia",
              "Malaysia",
              "Thailand",
              "Philippines",
              "Argentina",
              "Colombia",
              "Chile"
            ],
            "description": "Country context (gl) applied to every page and InnerTube request, including pagination, player and comment endpoints.",
            "editor": "select",
            "sectionCaption": "Localization",
            "sectionDescription": "Country and language context sent to YouTube for every request."
          },
          "language": {
            "title": "Language",
            "type": "string",
            "default": "en",
            "prefill": "en",
            "enum": [
              "en",
              "es",
              "fr",
              "de",
              "pt",
              "it",
              "nl",
              "pl",
              "ru",
              "ja",
              "ko",
              "zh",
              "hi",
              "ar",
              "tr",
              "id",
              "th",
              "vi",
              "sv",
              "no",
              "da",
              "fi",
              "cs",
              "el",
              "he",
              "uk",
              "ro",
              "hu",
              "ms",
              "bn"
            ],
            "enumTitles": [
              "English",
              "Spanish",
              "French",
              "German",
              "Portuguese",
              "Italian",
              "Dutch",
              "Polish",
              "Russian",
              "Japanese",
              "Korean",
              "Chinese",
              "Hindi",
              "Arabic",
              "Turkish",
              "Indonesian",
              "Thai",
              "Vietnamese",
              "Swedish",
              "Norwegian",
              "Danish",
              "Finnish",
              "Czech",
              "Greek",
              "Hebrew",
              "Ukrainian",
              "Romanian",
              "Hungarian",
              "Malay",
              "Bengali"
            ],
            "description": "Interface language (hl) for labels and relative dates. Titles and descriptions stay in the creator's language.",
            "editor": "select"
          }
        }
      },
      "output": {
        "actorOutputSchemaVersion": 1,
        "title": "YouTube Channel Video Feed Quick Scraper Output",
        "description": "One row per video with recordType/sourceUrl, exact publish date, like count, category, tags, optional comment count, view/like metrics, Shorts and live flags, plus the channel's authorMetadata with subscriber counts, About-page links and derived channel analytics (lastUploadDate, averageViews, uploadFrequencyDays, videosAnalyzed). recordType is 'video' for video rows, 'channel' for the channel-info-only row (maxVideos=0 or no videos), and 'error' for a failed channel. Optional shorts, playlists and liveVideos arrays are attached to the first row when their include... input is enabled.",
        "properties": {
          "videos": {
            "type": "string",
            "title": "YouTube channel videos",
            "description": "Dataset containing video rows plus authorMetadata. Standard fields: recordType ('video' | 'channel' | 'error') and sourceUrl (the video watch URL or channel URL). Video fields: videoId, title, url, viewCount, viewCountText, likeCount, commentCount, publishDate, uploadDate, category, tags, publishedTimeText, duration, durationSeconds, thumbnailUrl, description, isLive, isShort, badges, scrapedAt. Channel fields under authorMetadata: channelId, channelName, handle, channelUrl, subscriberCount, subscriberCountText, videoCount, videoCountText, country, location, totalViews, totalViewsText, joinedDateText, externalLinks, channelLinks, description, aboutDescription, keywords, rssUrl, avatarUrl, bannerUrl, isVerified, isFamilySafe, isOfficialArtistChannel, lastUploadDate, averageViews, uploadFrequencyDays, videosAnalyzed.",
            "template": "{{links.apiDefaultDatasetUrl}}/items"
          }
        }
      },
      "storages": {
        "dataset": {
          "actorSpecification": 1,
          "views": {
            "overview": {
              "title": "Overview",
              "transformation": {
                "fields": [
                  "recordType",
                  "title",
                  "videoId",
                  "viewCount",
                  "likeCount",
                  "publishDate",
                  "duration",
                  "url",
                  "sourceUrl",
                  "isShort",
                  "authorMetadata.channelName",
                  "authorMetadata.subscriberCount"
                ],
                "flatten": [
                  "authorMetadata"
                ]
              },
              "display": {
                "component": "table",
                "properties": {
                  "recordType": {
                    "label": "Record Type",
                    "format": "text"
                  },
                  "title": {
                    "label": "Title",
                    "format": "text"
                  },
                  "videoId": {
                    "label": "Video ID",
                    "format": "text"
                  },
                  "viewCount": {
                    "label": "Views",
                    "format": "number"
                  },
                  "likeCount": {
                    "label": "Likes",
                    "format": "number"
                  },
                  "publishDate": {
                    "label": "Published (exact)",
                    "format": "text"
                  },
                  "duration": {
                    "label": "Duration",
                    "format": "text"
                  },
                  "url": {
                    "label": "URL",
                    "format": "link"
                  },
                  "sourceUrl": {
                    "label": "Source URL",
                    "format": "link"
                  },
                  "isShort": {
                    "label": "Short",
                    "format": "boolean"
                  },
                  "authorMetadata.channelName": {
                    "label": "Channel",
                    "format": "text"
                  },
                  "authorMetadata.subscriberCount": {
                    "label": "Subscribers",
                    "format": "number"
                  }
                }
              }
            },
            "detailed": {
              "title": "Detailed",
              "transformation": {
                "fields": [
                  "recordType",
                  "sourceUrl",
                  "videoId",
                  "title",
                  "url",
                  "viewCount",
                  "viewCountText",
                  "likeCount",
                  "commentCount",
                  "publishDate",
                  "uploadDate",
                  "category",
                  "tags",
                  "publishedTimeText",
                  "duration",
                  "durationSeconds",
                  "thumbnailUrl",
                  "description",
                  "isLive",
                  "isShort",
                  "badges",
                  "authorMetadata.channelId",
                  "authorMetadata.channelName",
                  "authorMetadata.handle",
                  "authorMetadata.channelUrl",
                  "authorMetadata.subscriberCount",
                  "authorMetadata.subscriberCountText",
                  "authorMetadata.videoCount",
                  "authorMetadata.videoCountText",
                  "authorMetadata.country",
                  "authorMetadata.isVerified",
                  "authorMetadata.avatarUrl",
                  "authorMetadata.bannerUrl",
                  "authorMetadata.rssUrl",
                  "authorMetadata.isFamilySafe",
                  "authorMetadata.keywords",
                  "authorMetadata.description",
                  "authorMetadata.aboutDescription",
                  "authorMetadata.channelLinks",
                  "authorMetadata.joinedDateText",
                  "authorMetadata.totalViewsText",
                  "authorMetadata.totalViews",
                  "authorMetadata.location",
                  "authorMetadata.externalLinks",
                  "authorMetadata.lastUploadDate",
                  "authorMetadata.averageViews",
                  "authorMetadata.uploadFrequencyDays",
                  "authorMetadata.videosAnalyzed",
                  "shorts",
                  "playlists",
                  "liveVideos",
                  "scrapedAt"
                ],
                "flatten": [
                  "authorMetadata"
                ]
              },
              "display": {
                "component": "table",
                "properties": {
                  "recordType": {
                    "label": "Record Type",
                    "format": "text"
                  },
                  "sourceUrl": {
                    "label": "Source URL",
                    "format": "link"
                  },
                  "videoId": {
                    "label": "Video ID",
                    "format": "text"
                  },
                  "title": {
                    "label": "Title",
                    "format": "text"
                  },
                  "url": {
                    "label": "URL",
                    "format": "link"
                  },
                  "viewCount": {
                    "label": "Views",
                    "format": "number"
                  },
                  "viewCountText": {
                    "label": "Views Text",
                    "format": "text"
                  },
                  "likeCount": {
                    "label": "Likes (exact)",
                    "format": "number"
                  },
                  "commentCount": {
                    "label": "Comments (exact)",
                    "format": "number"
                  },
                  "publishDate": {
                    "label": "Published (exact)",
                    "format": "text"
                  },
                  "uploadDate": {
                    "label": "Uploaded (exact)",
                    "format": "text"
                  },
                  "category": {
                    "label": "Category",
                    "format": "text"
                  },
                  "tags": {
                    "label": "Tags",
                    "format": "text"
                  },
                  "publishedTimeText": {
                    "label": "Published (relative)",
                    "format": "text"
                  },
                  "duration": {
                    "label": "Duration",
                    "format": "text"
                  },
                  "durationSeconds": {
                    "label": "Duration (s)",
                    "format": "number"
                  },
                  "thumbnailUrl": {
                    "label": "Thumbnail",
                    "format": "link"
                  },
                  "description": {
                    "label": "Description",
                    "format": "text"
                  },
                  "isLive": {
                    "label": "Live",
                    "format": "boolean"
                  },
                  "isShort": {
                    "label": "Short",
                    "format": "boolean"
                  },
                  "badges": {
                    "label": "Badges",
                    "format": "text"
                  },
                  "authorMetadata.channelId": {
                    "label": "Channel ID",
                    "format": "text"
                  },
                  "authorMetadata.channelName": {
                    "label": "Channel",
                    "format": "text"
                  },
                  "authorMetadata.handle": {
                    "label": "Handle",
                    "format": "text"
                  },
                  "authorMetadata.channelUrl": {
                    "label": "Channel URL",
                    "format": "link"
                  },
                  "authorMetadata.subscriberCount": {
                    "label": "Subscribers",
                    "format": "number"
                  },
                  "authorMetadata.subscriberCountText": {
                    "label": "Subscribers Text",
                    "format": "text"
                  },
                  "authorMetadata.videoCount": {
                    "label": "Video Count",
                    "format": "number"
                  },
                  "authorMetadata.videoCountText": {
                    "label": "Videos Text",
                    "format": "text"
                  },
                  "authorMetadata.country": {
                    "label": "Country",
                    "format": "text"
                  },
                  "authorMetadata.isVerified": {
                    "label": "Verified",
                    "format": "boolean"
                  },
                  "authorMetadata.avatarUrl": {
                    "label": "Avatar URL",
                    "format": "link"
                  },
                  "authorMetadata.bannerUrl": {
                    "label": "Banner URL",
                    "format": "link"
                  },
                  "authorMetadata.rssUrl": {
                    "label": "RSS URL",
                    "format": "link"
                  },
                  "authorMetadata.isFamilySafe": {
                    "label": "Family Safe",
                    "format": "boolean"
                  },
                  "authorMetadata.keywords": {
                    "label": "Keywords",
                    "format": "text"
                  },
                  "authorMetadata.description": {
                    "label": "Description",
                    "format": "text"
                  },
                  "authorMetadata.aboutDescription": {
                    "label": "About Description",
                    "format": "text"
                  },
                  "authorMetadata.channelLinks": {
                    "label": "Channel Links",
                    "format": "text"
                  },
                  "authorMetadata.joinedDateText": {
                    "label": "Joined Date",
                    "format": "text"
                  },
                  "authorMetadata.totalViewsText": {
                    "label": "Total Views Text",
                    "format": "text"
                  },
                  "authorMetadata.totalViews": {
                    "label": "Total Views",
                    "format": "number"
                  },
                  "authorMetadata.location": {
                    "label": "Location",
                    "format": "text"
                  },
                  "authorMetadata.externalLinks": {
                    "label": "External Links",
                    "format": "text"
                  },
                  "authorMetadata.lastUploadDate": {
                    "label": "Last Upload",
                    "format": "text"
                  },
                  "authorMetadata.averageViews": {
                    "label": "Avg Views (sample)",
                    "format": "number"
                  },
                  "authorMetadata.uploadFrequencyDays": {
                    "label": "Upload Gap (days)",
                    "format": "number"
                  },
                  "authorMetadata.videosAnalyzed": {
                    "label": "Videos Analyzed",
                    "format": "number"
                  },
                  "shorts": {
                    "label": "Shorts",
                    "format": "text"
                  },
                  "playlists": {
                    "label": "Playlists",
                    "format": "text"
                  },
                  "liveVideos": {
                    "label": "Live Videos",
                    "format": "text"
                  },
                  "scrapedAt": {
                    "label": "Scraped At",
                    "format": "text"
                  }
                }
              }
            }
          }
        }
      },
      "readme": "# YouTube Channel Video Feed Quick Scraper\r\n\r\nPoint this actor at one or more YouTube channels and get back their video list — newest, most popular or oldest first — with exact publish dates, exact like counts, categories, tags and a full channel profile. It reads YouTube's own public pages, so there is no API key and no login.\r\n\r\n## What this actor does\r\n\r\n- Accepts any mix of channel handles (`@name`), full channel URLs, or raw channel IDs across a single run\r\n- Reads the Videos tab, the channel's uploads playlist (`UU{channelId}`), or both; the uploads playlist is a complete chronological feed that also includes Shorts and uploads the Videos tab omits. \"Both\" merges the sources, de-duplicated by video ID, then applies the chosen sort\r\n- Returns exact `publishDate`, `likeCount`, `category` and `tags` for each video from YouTube's player response\r\n- Optionally resolves exact public comment counts per video\r\n- Sorts videos newest, most popular, or oldest first; Shorts have their own Latest/Popular/Oldest filter\r\n- Can emit only videos that are new since the previous monitor run\r\n- Adds derived channel analytics: last upload date, average views, upload gap in days and sample size\r\n- Optionally pulls the channel's About-page data (total views, join date, location, social links), Shorts, Playlists, and Live/Streams tabs\r\n- Returns a channel-info-only row (no video fields) when `maxVideos` is set to `0`\r\n- Applies a country and interface language to every request, including pagination and player endpoints\r\n- Omits any field YouTube did not expose for that video or channel — it never fills a gap with an empty string or a made-up value\r\n\r\n## Output per video row\r\n\r\nEvery video row has `recordType: \"video\"` and `sourceUrl` set to its watch URL, plus the full `authorMetadata` object for its channel. A channel-info-only row (`maxVideos: 0` or a channel with no listed videos) has `recordType: \"channel\"` and `sourceUrl` set to the channel URL. A failed channel emits `recordType: \"error\"`.\r\n\r\n- `recordType`, `sourceUrl`, `videoId`, `title`, `url`\r\n- `viewCount` — only when YouTube's own data exposes an exact integer; a rounded label like \"93K views\" stays in `viewCountText` and is never converted into a fake exact number\r\n- `viewCountText`, `publishedTimeText` — the relative label exactly as YouTube displays it\r\n- `likeCount` — exact integer from the player response, when YouTube exposes it\r\n- `commentCount` — exact integer, only when `includeCommentCounts` is on and the video has a public comment section\r\n- `publishDate` — exact ISO 8601 publish timestamp with YouTube's original UTC offset\r\n- `uploadDate` — only when it differs from `publishDate`\r\n- `category` — YouTube's category label, e.g. `\"Science & Technology\"`\r\n- `tags` — the creator's video tags, when any were set\r\n- `duration` — may be the literal string `\"LIVE\"` for an ongoing stream; `durationSeconds` is only present once YouTube reports a finite length\r\n- `thumbnailUrl`, `description`\r\n- `isLive`, `isShort`\r\n- `badges` — labels shown on the video tile, e.g. `[\"LIVE\"]` or `[\"NEW\"]`, when any apply\r\n- `shorts[]`, `playlists[]`, `liveVideos[]` — only present when the matching `include...` input is on\r\n- `scrapedAt`\r\n\r\n### `authorMetadata` fields\r\n\r\n- `channelId`, `channelName`, `handle`, `channelUrl`\r\n- `description` — the channel's short header description\r\n- `aboutDescription` — the longer description shown on the channel's About page, when `includeAbout` is on\r\n- `subscriberCount` — only when YouTube's source data gives an exact integer; `subscriberCountText` always carries the displayed label (e.g. \"466M subscribers\")\r\n- `videoCount`, `videoCountText` — same exact-vs-rounded distinction as subscribers\r\n- `country`, `location` — `location` and `totalViews`/`totalViewsText`/`joinedDateText` come from the About page (`includeAbout`)\r\n- `joinedDateText`, `totalViews`, `totalViewsText`\r\n- `externalLinks[]` — links listed on the About page (`includeAbout`); `channelLinks[]` — links shown directly on the channel header\r\n- `lastUploadDate`, `averageViews`, `uploadFrequencyDays`, `videosAnalyzed` — channel analytics derived from the exact rows returned by this run\r\n- `rssUrl`, `avatarUrl`, `bannerUrl`\r\n- `isVerified`, `isFamilySafe`\r\n- `isOfficialArtistChannel` — only present when the channel carries YouTube's official-artist badge\r\n- `keywords[]`\r\n\r\n## Input\r\n\r\n| Field | Type | Default | Description |\r\n|---|---|---|---|\r\n| `channelUrls` | array | – | Channel URLs, handles or channel IDs, any mix |\r\n| `maxVideos` | integer | `50` | Max videos per channel (0–10000; 10,000 is a policy cap, `0` returns channel info only). Exact player metadata refresh has a 900-second budget per run; beyond it rows keep listing metadata |\r\n| `videoSource` | string | `videosTab` | `videosTab`, `uploadsPlaylist` (catches Shorts and omissions) or `both` |\r\n| `sortVideosBy` | string | `newest` | `newest`, `popular` or `oldest` |\r\n| `sortShortsBy` | string | `latest` | `latest`, `popular` or `oldest` for the Shorts tab |\r\n| `includeCommentCounts` | boolean | `false` | Fetch exact comment counts (up to two extra requests per video; the description `/next` response is reused when available) |\r\n| `onlyNewVideos` | boolean | `false` | Monitor mode: emit only videos not seen by a previous run |\r\n| `includeAbout` | boolean | `true` | Pull total views, join date, location, links and analytics |\r\n| `includePlaylists` | boolean | `false` | Include the channel's Playlists tab |\r\n| `maxPlaylists` | integer | `20` | Max playlists to return when `includePlaylists` is on (1–500) |\r\n| `includeShorts` | boolean | `false` | Include the channel's Shorts tab and mark matching videos with `isShort` |\r\n| `maxShorts` | integer | `20` | Max Shorts to return when `includeShorts` is on (1–2000) |\r\n| `includeLiveVideos` | boolean | `false` | Include the channel's Live/Streams tab |\r\n| `maxLiveVideos` | integer | `20` | Max live/stream videos to return (1–500) |\r\n| `market` | string | `US` | Country code (`gl`) applied to every request (31 supported) |\r\n| `language` | string | `en` | Interface language (`hl`), 30 supported |\r\n\r\n### Example: a few channels' latest uploads\r\n\r\n```json\r\n{\r\n  \"channelUrls\": [\"@Apify\", \"@mkbhd\"],\r\n  \"maxVideos\": 10,\r\n  \"sortVideosBy\": \"newest\"\r\n}\r\n```\r\n\r\n### Example: uploads playlist to include Shorts and omitted uploads\r\n\r\n```json\r\n{\r\n  \"channelUrls\": [\"@mkbhd\"],\r\n  \"maxVideos\": 100,\r\n  \"videoSource\": \"both\",\r\n  \"includeShorts\": true,\r\n  \"sortShortsBy\": \"popular\"\r\n}\r\n```\r\n\r\n### Example: recent videos with exact engagement metrics\r\n\r\n```json\r\n{\r\n  \"channelUrls\": [\"@MrBeast\"],\r\n  \"maxVideos\": 20,\r\n  \"includeCommentCounts\": true\r\n}\r\n```\r\n\r\n### Example: monitor a channel for new uploads\r\n\r\n```json\r\n{\r\n  \"channelUrls\": [\"@Fireship\"],\r\n  \"maxVideos\": 10,\r\n  \"onlyNewVideos\": true,\r\n  \"videoSource\": \"uploadsPlaylist\"\r\n}\r\n```\r\n\r\n### Example: channel profile only, no videos\r\n\r\n```json\r\n{\r\n  \"channelUrls\": [\"@mrbeast\"],\r\n  \"maxVideos\": 0\r\n}\r\n```\r\n\r\n## Use cases\r\n\r\n- **Bulk channel monitoring** — track upload activity across a long list of channels on a recurring schedule\r\n- **New-upload alerts** — `onlyNewVideos` emits just the videos published since the previous run\r\n- **Competitor benchmarking** — compare exact view/like counts and posting cadence across several creators in a niche\r\n- **Influencer shortlisting** — pull subscriber counts, verification status and social links for a batch of candidate channels\r\n- **Content inventory** — build a catalog of a channel's videos, Shorts and playlists, including uploads the Videos tab hides\r\n- **Engagement analysis** — export exact like/comment counts and category/tag metadata for a published date range\r\n- **Growth tracking** — re-run on a schedule to watch subscriber and view counts change over time\r\n\r\n## FAQ\r\n\r\n**Is a YouTube API key needed?**\r\nNo — this actor reads YouTube's own public channel and video pages and needs no API key or login.\r\n\r\n**Which channel reference formats work?**\r\nA `@handle`, a full `/channel/UC...` URL, a full `@handle` URL, or a raw channel ID all resolve to the same channel.\r\n\r\n**What is the difference between the Videos tab and the uploads playlist?**\r\nThe Videos tab is a curated 30-per-page list. The uploads playlist (`UU` + the channel ID without its `UC` prefix) is the complete chronological feed and returns 100 videos per page. It also includes Shorts and other uploads the Videos tab omits. Use `videoSource: \"uploadsPlaylist\"` when coverage matters.\r\n\r\n**Are like counts exact?**\r\nYes. `likeCount` comes from YouTube's player response as an exact integer. The rounded label YouTube shows in the interface is not used.\r\n\r\n**Why is `commentCount` missing?**\r\nComment counts are opt-in (`includeCommentCounts`). They cost up to two extra requests per video: a `/next` seed request and, when the seed does not already contain the count, a comments-continuation request. When the actor already fetched `/next` for the description, that response is reused so no second seed request is made. The field is omitted when the video has comments disabled or no public comment section. A count of `0` is a real value and is kept.\r\n\r\n**Why is `viewCount` sometimes missing even though `viewCountText` shows a number?**\r\nYouTube's video-card label is often rounded (e.g. \"93K views\"). This actor only fills `viewCount` when the underlying data gives an exact figure, rather than reverse-engineering an approximate one.\r\n\r\n**Why would `duration` show `\"LIVE\"` with no `durationSeconds`?**\r\nThat's an ongoing live stream — its length isn't final yet, so there's nothing finite to report until the broadcast ends.\r\n\r\n**Does \"popular\" or \"oldest\" sort the whole uploads playlist?**\r\nNo. The uploads playlist has no server-side sort menu, so those orders are applied client-side to a scan window of `max(maxVideos, min(2 × maxVideos, 60))` videos. For a full-history Popular/Oldest sort, use `videoSource: \"videosTab\"`, which has YouTube's native sort chips.\r\n\r\n**Can I filter by exact publish date?**\r\nNot in this version. Exact dates come from YouTube's player response, which is frequently unavailable to guest requests; exposing a date filter would silently return 0 videos. Use the channel's video list and filter downstream by `publishDate` when it is present, or use `onlyNewVideos` for ongoing monitoring.\r\n\r\n**How does monitor mode store what it has seen?**\r\n`onlyNewVideos` keeps a per-channel list of video IDs in the actor's named `youtube-channel-monitor` key-value store, which persists across runs. The first run returns the normal window; later runs emit only new IDs. Only the rows actually returned are marked as seen, so a `maxVideos` cap pauses the remaining new videos instead of skipping them permanently.\r\n\r\n**Does `market` or `language` change which videos are returned?**\r\n`market` sends the country context (`gl`) and `language` sends the interface language (`hl`) on every page and InnerTube request, including pagination, player and comment calls. They affect localized labels, relative dates, and regionally restricted content. Neither changes which channel you look up.\r\n\r\n**Can I fetch 5,000+ videos from one channel?**\r\nYes — `maxVideos` goes up to 10,000. With `videoSource: \"uploadsPlaylist\"` the actor pages 100 videos at a time until it reaches your cap or the channel's uploads run out. The 10,000 cap is an intentional policy limit, and the exact player-metadata pass has a 900-second budget per run: if that budget runs out on a very large request, the remaining rows keep their listing data (title, view label, relative date) and the run still completes with the full dataset.\r\n\r\n**What about members-only, age-restricted or private videos?**\r\nPublic listing cards for members-only and age-restricted videos can still be returned, but YouTube gates their playback to signed-in viewers, so playback-only fields (exact metrics, description) may be missing for those rows. Private and deleted videos cannot be fetched at all.\r\n\r\n**What is `recordType`?**\r\nIt tells rows apart without inspecting which fields are present: `video` for normal video rows, `channel` for the channel-info-only row, and `error` for a channel that could not be fetched.\r\n\r\n**Can I get the channel's public business email?**\r\nNo. YouTube only reveals a business email after a Google sign-in and shows a \"Sign in to see email address\" gate to logged-out visitors. Public social and website links are still returned in `externalLinks`.\r\n\r\n**Why are subscriber counts sometimes rounded?**\r\nYouTube displays subscriber and video counts as rounded labels (e.g. \"21.4M subscribers\"). The actor keeps that text in `subscriberCountText`/`videoCountText` and only fills the integer when YouTube exposes an exact value.\r\n"
    },
    "buildNumber": "1.0.4",
    "imageDigest": "1279ea81e9301ec79312c48a228605c0dea12f29cbe63e6c102e7ffdfa66f0e0",
    "actVersion": {
      "sourceType": "SOURCE_FILES",
      "buildTag": "latest",
      "versionNumber": "1.0"
    },
    "usage": {
      "ACTOR_COMPUTE_UNITS": 0.03320666666666667
    }
  }
}