# YouTube Community Posts Scraper (Engagement Analytics) (`scrapio/youtube-community-posts-scraper`) Actor

YouTube Community Posts Scraper (Engagement Analytics) extracts community posts, captions, images, polls, likes, comments, shares, timestamps, channel details, and engagement metrics. Ideal for audience research, content analysis, competitor monitoring, and engagement insights.

- **URL**: https://apify.com/scrapio/youtube-community-posts-scraper.md
- **Developed by:** [Scrapio](https://apify.com/scrapio) (community)
- **Categories:** Lead generation, Social media, Videos
- **Stats:** 5 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.99 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

### YouTube Community Posts Scraper — Posts, Engagement and Media

YouTube Community Posts Scraper (Engagement Analytics) pulls every post from a channel's Community tab and turns the raw HTML into typed JSON — text, author, publish time, poll choices, images, video thumbnails, and two parsed numeric fields, `likeCountValue` and `commentCountValue`. Unlike scraping frameworks that hand back raw HTML, it returns structured rows ready for your model, database, or spreadsheet without any parsing. Filter by minimum likes, minimum comments, or post type, and optionally sort every result by total engagement so the best-performing posts surface first. This guide covers every input and output field plus how teams deploy it for enrichment, monitoring, and dataset building.

### What Does YouTube Community Posts Scraper Do?

It fetches the Community/Posts tab for one or more YouTube channels and extracts every post it finds there — text posts, image posts, video-share posts, and polls. No YouTube account, login, or API key is required: the source code (`src/main.py`) runs entirely unauthenticated, fetching the public `/posts` page and paginating YouTube's internal `browse` endpoint. On top of the raw post data it layers an engagement-analytics pass that the plain Community tab doesn't give you.

- Scrapes text, image, video, and poll-type community posts from any public channel
- Parses abbreviated like/comment counts (`"12K"`, `"1.2M"`) into real integers you can filter and sort on
- Filters output by minimum likes, minimum comments, or a single post type
- Optionally sorts the whole result set by total engagement (likes + comments), descending
- Accepts both `youtube.com/@handle` and `youtube.com/channel/UC...` channel URLs
- Scans multiple channels in a single run
- Falls back through a proxy chain and retries with backoff when YouTube serves a soft-block page

### Features & Capabilities

Three things define this Actor: what it extracts, how the engagement layer works, and how it fails gracefully when YouTube pushes back.

#### Core features

- **Full post extraction** — `channelId`, `postId`, `author`, `authorUrl`, `text`, `publishedTime`, `attachmentType`, `pollChoices`, `images`, `videoThumbnail`, and `sourceUrl` for every post, read directly from the `backstagePostRenderer` YouTube serves.
- **Parsed engagement fields** — `likeCountValue` and `commentCountValue` are computed from the raw `likeCount` / `commentCount` strings using an abbreviation parser that handles `K`/`M`/`B` suffixes and comma-formatted numbers; they are `null`, not `0`, when YouTube shows no count at all.
- **Engagement filtering** — `minLikeCount` and `minCommentCount` drop posts below a numeric threshold; a missing count is treated as `0` for the comparison.
- **Post-type isolation** — `postType` restricts output to `text`, `image`, `video`, or `poll` posts by their actual `attachmentType`.
- **Global engagement sort** — `sortByEngagement` ranks the entire filtered result set by `likeCountValue + commentCountValue`, descending, across all channels in the run.
- **Resilient fetch engine** — Chrome-131 TLS/JA3 impersonation via `curl_cffi`, a hybrid HTML + InnerTube (`youtubei/v1/browse`) pagination path, exponential-backoff retries, and a soft-block guard that treats a data-less HTML shell as a signal to retry rather than return empty.
- **URL normalization** — `clean_posts_url()` strips any trailing `/about`, `/videos`, `/posts`, or `/community` segment from whatever URL you supply and re-appends `/posts`, so a channel's homepage, About tab, or Videos tab URL all resolve to the same Community feed.
- **Continuation-based pagination** — after the first page of posts, the Actor reads the `INNERTUBE_API_KEY` and context out of the page's `ytcfg` payload and walks YouTube's `browse` continuation tokens until `maxPosts` is reached or YouTube stops returning more posts.

#### How YouTube Community Posts Scraper compares to other community post scrapers

| Feature | This Actor | scrapestorm/youtube-community-posts-scraper | lurkapi/youtube-community-posts-scraper | scraper-engine/youtube-community-posts-scraper |
| --- | --- | --- | --- | --- |
| Parsed numeric engagement (`likeCountValue`/`commentCountValue`) | Yes, built in | Not documented | Not documented | Not documented |
| Engagement threshold filter (min likes / min comments) | Yes (`minLikeCount`, `minCommentCount`) | Not documented | Not documented | Not documented |
| Sort output by total engagement | Yes (`sortByEngagement`) | Not documented | Not documented | Not documented |
| Post-type filter | Yes — `all`/`text`/`image`/`video`/`poll` | Not documented | Yes — all/text/polls/images/videos (observed 2026-07-26) | Not documented as a discrete parameter |
| Pricing model | Pay per result (`row_result` charged event) | Flat $9.90/month (observed 2026-07-26) | Pay-per-event, $0.003/post plus paid add-ons for comments, image download, and language detection (observed 2026-07-26) | Flat $5/month (observed 2026-07-26) |
| Proxy handling | Custom proxy → Apify Datacenter → Apify Residential → direct, with a soft-block guard | "No proxy required" (observed 2026-07-26) | Automatic / Datacenter / Residential / custom / no-proxy (observed 2026-07-26) | Not documented |

If your use case is feeding structured data to an LLM or a dashboard, the parsed-engagement row is the decision-maker — sorting and thresholding on `"12K"`-style strings inside your own code is a reliability failure mode, not a feature you should have to build yourself.

#### When another tool might suit you better

lurkapi's listing (observed 2026-07-26) documents paid add-ons this Actor does not have: downloading full-resolution images to storage, scraping the reply comments underneath each community post, and automatic language detection on post text. If your workflow needs the comment thread on a post, or the actual image files rather than their URLs, that listing is the better starting point. This Actor's focus is narrower and deeper on one problem: turning likes and comments into numbers you can filter and rank on, rather than being the broadest possible collector of everything a community post can carry.

#### YouTube Community Posts Scraper within the Scrapio data stack

This Actor covers community posts. For playlist contents with transcripts, use Youtube Playlist Scraper (Transcript & Subtitles). For individual video metadata and subtitles, use YouTube Video Details Scraper (Subtitles & Translations). For Shorts-specific data, use YouTube Shorts Scraper With Transcripts & Captions. For channel outreach data, use youtube-channel-contact-extractor.

### Why do developers and data teams scrape YouTube community posts?

#### 🏢 Marketing and community teams

A social team managing several creator or brand channels runs this Actor against its own channel list with `sortByEngagement` enabled to see, at a glance, which post type — polls, images, or plain text — is pulling the most `likeCountValue` + `commentCountValue` this week, then feeds that into the next content calendar without opening each post individually. Because `postType` isolates one attachment type at a time, the same run can be repeated to compare, say, poll engagement against image-post engagement across a full quarter of Community tab activity.

#### 📊 AI training data and RAG indexing

The `text` field is the highest-information field for RAG indexing — it's the actual post caption or poll question, in the creator's own words, unlike a video description written for SEO. For training data, `likeCountValue`, `commentCountValue`, and `attachmentType` are the most consistently structured fields across every post, since they're typed integers and a fixed enum rather than free text. Together they support (1) enrichment of a creator knowledge base with what a channel has actually said in its Community tab, and (2) supervised datasets that pair post text with an engagement label.

#### 📱 Competitive and market intelligence

Track a competitor's or an industry's Community tab activity by running the same channel list on a schedule and diffing `postId` and `likeCountValue` between runs to see which posts are gaining traction after publication, not just at scrape time.

#### 🔬 Research and academic use

Community posts are a public, unauthenticated data source for studying creator-audience interaction patterns, poll usage, or engagement distribution across post types. Scope any dataset to what a channel has made publicly visible on its Community tab.

#### 🎥 Product and SaaS development

Build a creator-analytics dashboard, an engagement-alert tool, or a content-performance API on top of this Actor's output — the `row_result` charged event and typed dataset schema make it a stable base layer to call from a scheduled job rather than a one-off script.

### 🍚 Input Parameters

All seven parameters come directly from `.actor/actor.json`. There are no credential or API-key fields — the Actor runs unauthenticated, and the `proxy` field is a standard Apify proxy configuration object, not a secret.

| Parameter | Required | Type | Default | Description | Example Value |
| --- | --- | --- | --- | --- | --- |
| `channelUrls` | Yes | array of strings | — | One or more YouTube channel URLs to scan for community posts. Accepts `youtube.com/@handle` or `youtube.com/channel/UC...` — one per line or comma-separated. | `["https://www.youtube.com/@MrBeast"]` |
| `maxPosts` | No | integer (1–10,000) | `10` | How many community posts to fetch per channel before filtering. Filters are applied to this pool, so scan more than you expect to keep. | `100` |
| `minLikeCount` | No | integer (≥ 0) | `0` | Keep only posts whose parsed like count is at least this value. Uses the numeric `likeCountValue` (e.g. `"12K"` → `12000`). Set `0` to disable. | `5000` |
| `minCommentCount` | No | integer (≥ 0) | `0` | Keep only posts whose parsed comment count is at least this value. Uses the numeric `commentCountValue`. Set `0` to disable. | `100` |
| `postType` | No | enum: `all`, `text`, `image`, `video`, `poll` | `"all"` | Restrict output to a single post type by attachment. `all` keeps everything. | `"poll"` |
| `sortByEngagement` | No | boolean | `false` | When enabled, output is sorted by total engagement (parsed likes + comments) in descending order, so the top-performing posts appear first. | `true` |
| `proxy` | No | proxy object | runs without a proxy | Enable an Apify proxy group or a custom URL for higher volume; if blocked, the Actor escalates to Apify RESIDENTIAL on a fresh IP and continues. | `{"useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"]}` |

#### Advanced parameters (accepted, not in the input form)

`src/main.py` also reads three fields that are not part of the published input schema, so they don't appear in the Console form but can be sent in raw JSON input:

| Parameter | Type | Default | Clamp | Description |
| --- | --- | --- | --- | --- |
| `requestTimeout` | integer | `15` | 1–300 | Per-request timeout, in seconds, for each page/API fetch. |
| `maxRetries` | integer | `3` | 1–10 | Number of fetch attempts per proxy configuration before escalating. |
| `retryDelay` | integer | `2` | 0–60 | Base delay, in seconds, before the first retry; doubles on each subsequent attempt. |

#### Example input

```json
{
  "channelUrls": [
    "https://www.youtube.com/@MrBeast",
    "https://www.youtube.com/channel/UCX6OQ3DkcsbYNE6H8uQQuVA"
  ],
  "maxPosts": 100,
  "minLikeCount": 5000,
  "minCommentCount": 0,
  "postType": "all",
  "sortByEngagement": true,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}
```

#### Supported URL types and input formats

`channelUrls` accepts:

- **Handle URLs** — `https://www.youtube.com/@MrBeast`
- **Channel-ID URLs** — `https://www.youtube.com/channel/UCX6OQ3DkcsbYNE6H8uQQuVA`
- **A mixed list** — combine handle and channel-ID URLs in the same run; each is normalized to its `/posts` path internally (`clean_posts_url` strips `/about`, `/videos`, `/posts`, or `/community` before appending `/posts`)

`channelUrls` is defined as a string-list array in the schema; the code also accepts a single comma-separated string as a fallback and splits it into individual URLs. Whatever variant you paste in, `clean_posts_url()` normalizes it to the channel's `/posts` path before fetching, so you don't need to manually navigate to the Community tab URL yourself.

### 📦 Output Format

Every field below is written by `extract_post_data()` in `src/main.py` and pushed to the dataset — the dataset's default table view surfaces all 15 of them, so there is no hidden subset here.

#### Output for a community post

```json
{
  "channelId": "UCX6OQ3DkcsbYNE6H8uQQuVA",
  "postId": "Ugkx1a2B3c4D5e6F7g8H9i0J",
  "author": "MrBeast",
  "authorUrl": "/@MrBeast",
  "text": "Which one should we do next?",
  "publishedTime": "3 days ago",
  "likeCount": "480K",
  "commentCount": "22K",
  "likeCountValue": 480000,
  "commentCountValue": 22000,
  "pollChoices": ["Option A", "Option B"],
  "videoThumbnail": null,
  "images": [],
  "attachmentType": "poll",
  "sourceUrl": "https://www.youtube.com/@MrBeast"
}
```

| Field | Type | Description |
| --- | --- | --- |
| `channelId` | string | The channel's unique ID (starts with `UC...`). |
| `postId` | string | Unique ID for this community post. |
| `author` | string | The channel's display name. |
| `authorUrl` | string | Relative URL to the channel that published this post (e.g. `/@MrBeast`). |
| `text` | string | The full message or caption of the community post. |
| `publishedTime` | string | Relative publish time as shown by YouTube (e.g. `"2 days ago"`). |
| `likeCount` | string or null | Original abbreviated like string as shown by YouTube (e.g. `"12K"`). Null when not shown. |
| `commentCount` | string or null | Original abbreviated comment string (e.g. `"1.2K"`). Null when not shown. |
| `likeCountValue` | integer or null | Like count parsed to an integer (`"12K"` → `12000`). Null when no count is shown. Use for filtering/sorting. |
| `commentCountValue` | integer or null | Comment count parsed to an integer. Null when no count is shown. Use for filtering/sorting. |
| `pollChoices` | array of strings | For poll posts, the answer options. Empty array for non-poll posts. |
| `videoThumbnail` | string or null | URL of the video thumbnail when the post attaches a video. Null otherwise. |
| `images` | array of strings | URLs of images attached to the post. Empty array when there are none. |
| `attachmentType` | string or null | One of `text`, `image`, `video`, `poll`. Null when it cannot be determined. |
| `sourceUrl` | string | The channel URL you passed as input for this scrape. |

This Actor returns a single entity type — the community post — so there is no separate secondary-entity schema; every post row, regardless of attachment type, carries the same 15 keys, with the fields that don't apply (`pollChoices`, `images`, `videoThumbnail`) set to an empty array or `null` rather than omitted.

#### Notes on accuracy

- `likeCount` and `commentCount` are read exactly as YouTube renders them in the page; when YouTube shows no count at all, both the raw string and its parsed numeric counterpart are `null` — the Actor never substitutes a fabricated `0` for a genuinely missing value.
- For the purposes of `minLikeCount`, `minCommentCount`, and the engagement sort, a missing (`null`) count is treated as `0` so filtering still works predictably on posts with no visible like or comment count.
- `attachmentType` is derived from which renderer is present on `backstageAttachment` (`videoRenderer`, `backstageImageRenderer`, or `pollRenderer`); a post with none of those attachments is classified as `text`.

#### Schema stability and export options

Field names stay stable across runs; `attachmentType` and the numeric engagement fields are computed by the Actor itself rather than mirrored from an unstable YouTube UI field, so a YouTube front-end redesign is less likely to change your downstream schema than it would for a scraper that returns raw page HTML. If YouTube changes the underlying `ytInitialData`/`browse` structure enough to break a specific extraction path, the affected field returns `null` or an empty array rather than a stale or malformed value, keeping the schema's shape intact even when a value can't be found for a given post. Every run's dataset can be exported from the Apify Console or API as JSON, CSV, Excel, XML, or HTML table — the same export options every Apify dataset supports.

### 💡 YouTube Community Posts Scraper Strategy Guide

#### 🎯 Strategy 1: Real-time enrichment pipeline

Trigger a run whenever a monitored channel publishes new content (from your own webhook or scheduler), scan with a modest `maxPosts`, and append `likeCountValue`, `commentCountValue`, and `attachmentType` to the matching row in your CRM or content-ops database. Because engagement fields arrive as integers, no downstream parsing step is needed before writing them back — the value that lands in your database is already the number you'll query, chart, or threshold on, not a string like `"12K"` that needs its own parser on the receiving end.

#### 🎯 Strategy 2: Scheduled monitoring and alerting

Run the Actor on an Apify Schedule (a cron-based recurring trigger configured in the Apify Console) against a fixed channel list, store the previous run's dataset, and diff on `postId` plus `likeCountValue`/`commentCountValue` to catch posts whose engagement crossed a threshold since the last run. Set `minLikeCount` to the alert threshold itself so the Actor only returns posts already worth flagging, and enable `sortByEngagement` so the first row of each run's dataset is always the post you'd want to look at first.

#### 🎯 Strategy 3: Bulk dataset build

For a research or training corpus, list every target channel in `channelUrls` and set `maxPosts` to the depth you need; channels are processed one after another within a single run, so for very large channel lists, fan out across several parallel Actor runs (via the Apify API) rather than one run with a long `channelUrls` list, and merge the resulting datasets afterward — for example, by channel or by `postId` — before loading them into a database or notebook.

#### Strategy comparison at a glance

| Strategy | Best for | Run pattern | Output format |
| --- | --- | --- | --- |
| Real-time enrichment | Appending live engagement data to an existing record | Triggered single run per event | JSON row appended to your database |
| Scheduled monitoring | Catching engagement changes over time | Apify Schedule, recurring | Dataset diffed run-over-run |
| Bulk dataset build | Research or training corpora | Multiple parallel runs, one per channel batch | Aggregated CSV/JSON export |

### 🌴 Related YouTube Scrapers & Tools

Community posts are one slice of a channel's public footprint. The scrapers below cover the rest of YouTube, plus the equivalent engagement data on other platforms if your monitoring spans more than one network.

| Scraper | What it extracts |
| --- | --- |
| Youtube Playlist Scraper (Transcript & Subtitles) | Playlist contents with video transcripts and subtitles |
| YouTube Video Details Scraper (Subtitles & Translations) | Per-video metadata, subtitles, and translations |
| YouTube Shorts Scraper With Transcripts & Captions | Shorts-specific video data with transcripts |
| YouTube Search Scraper: Country & Language Targeting | Search results filtered by country and language |
| youtube-channel-contact-extractor | Channel contact/outreach details |
| Instagram UGC Engagement Scraper | Cross-platform engagement data for Instagram posts |
| TikTok Trending Hashtags Analytics (Top Videos) | Cross-platform trending-content analytics for TikTok |

### How to integrate YouTube Community Posts Scraper with your stack

YouTube Community Posts Scraper works with any language or tool that can make an HTTP request through the Apify API — there is no platform-specific SDK requirement beyond a standard Apify client.

#### Python

```python
from apify_client import ApifyClient
import csv

client = ApifyClient("<YOUR_API_TOKEN>")

run_input = {
    "channelUrls": [
        "https://www.youtube.com/@MrBeast",
        "https://www.youtube.com/@mkbhd",
    ],
    "maxPosts": 100,
    "minLikeCount": 5000,
    "postType": "all",
    "sortByEngagement": True,
}

run = client.actor("<YOUR_USERNAME>/youtube-community-posts-scraper-engagement-analytics").call(run_input=run_input)

with open("community_posts.csv", "w", newline="", encoding="utf-8") as f:
    writer = None
    for item in client.dataset(run["defaultDatasetId"]).iterate_items():
        if writer is None:
            writer = csv.DictWriter(f, fieldnames=list(item.keys()))
            writer.writeheader()
        writer.writerow(item)

print("Saved results to community_posts.csv")
```

#### Node.js

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });

const input = {
    channelUrls: ['https://www.youtube.com/@MrBeast'],
    maxPosts: 100,
    minCommentCount: 100,
    sortByEngagement: true,
};

const run = await client.actor('<YOUR_USERNAME>/youtube-community-posts-scraper-engagement-analytics').call(input);
const { items } = await client.dataset(run.defaultDatasetId).listItems();

items.forEach((post) => {
    console.log(`${post.author}: ${post.likeCountValue} likes, ${post.commentCountValue} comments`);
});
```

#### Async and scheduled pipelines

For fire-and-forget large jobs, start the run via the API without waiting on it, then poll `client.run(runId).get()` for status or configure an Apify Schedule for recurring runs from the Console. Apify webhooks can notify your own endpoint when a run reaches `SUCCEEDED` so you don't need to poll at all — the standard delivery pattern is retrieving results from the dataset once the webhook or polling loop reports completion, rather than a callback that carries the data itself. This suits a large `channelUrls` batch you kick off overnight and collect from the dataset the next morning, rather than a script that has to stay connected for the run's full duration.

### Who Needs YouTube Community Posts Scraper? (Use Cases & Industries)

#### 🏢 Marketing and community teams

Rank a brand or client channel's own posts by `likeCountValue + commentCountValue` to decide which post format — poll, image, or plain text — to repeat next, without manually opening the Community tab.

#### 📊 AI and data teams

Feed `text` into a RAG index of creator content, and use `likeCountValue`/`commentCountValue`/`attachmentType` as clean, typed labels for a supervised engagement-prediction dataset.

#### 📱 Competitive intelligence teams

Track a competitor's or an industry vertical's Community tab activity on a schedule, comparing `likeCountValue` growth across runs to see which posts are still gaining traction after publication.

#### 🔬 Researchers

Study creator-audience interaction patterns, poll usage, or engagement distribution across post types using only publicly visible Community tab data.

#### 🎥 Product and SaaS builders

Use the Actor's stable, typed dataset schema as the data layer for a creator-analytics dashboard, an engagement-alert product, or a content-performance monitoring tool.

### Is it legal to scrape YouTube community posts?

Scraping publicly accessible web data is generally lawful in the United States; in *hiQ Labs, Inc. v. LinkedIn Corp.*, 938 F.3d 985 (9th Cir. 2019), reaffirmed on remand in 2022, the Ninth Circuit held that scraping data a website makes publicly available does not violate the Computer Fraud and Abuse Act. That case concerned LinkedIn profile data, not YouTube specifically, but the underlying principle — public data access is not unauthorized access — is widely applied to public web scraping generally.

A separate question is YouTube's own Terms of Service, which restrict automated access to the site; violating a platform's ToS is a civil, contract-law matter between the user and the platform, not a criminal one, and carries its own risk (such as IP or account action) independent of the CFAA question above.

Community posts are public content published by a channel, and `author`/`authorUrl` identify the channel's public display name rather than a private individual's contact details — so this Actor is closer to a public-content scraper than a personal-data scraper. It still returns only publicly accessible data. What you do with that data is your responsibility — consult legal counsel for commercial applications, especially where a channel is operated by an identifiable individual rather than a brand, and before republishing post text or images at scale.

### ❓ Frequently asked questions

#### Does YouTube Community Posts Scraper work without a YouTube account?

Yes. `src/main.py` makes unauthenticated requests to YouTube's public `/posts` page and its internal `browse` endpoint — no login, cookies, or API key are used or required anywhere in the Actor. This also means the output only ever contains what YouTube shows to a logged-out visitor, which is the same public view every reader of a channel's Community tab sees.

#### How does YouTube Community Posts Scraper handle YouTube's anti-scraping measures?

It fetches pages with Chrome-131 TLS/JA3 impersonation via `curl_cffi`, retries failed requests with exponential backoff, and checks every response for a "data-less shell" (a page missing `ytInitialData` or shorter than 20,000 bytes) that indicates a soft block, treating it as a signal to retry — and, if retries are exhausted, to escalate to the next proxy configuration in the fallback chain — rather than return an empty result silently.

#### Can I run YouTube Community Posts Scraper at scale without getting blocked?

The Actor tries proxy configurations in order — a custom proxy URL if supplied, then any selected Apify proxy groups, then a direct connection — and escalates to the next configuration on a fresh IP if one fails. No uptime or block-rate figure is published for this behavior, since none has been measured and documented; for higher-volume runs, supplying `apifyProxyGroups: ["RESIDENTIAL"]` gives the fallback chain a proxy tier to escalate to instead of falling back to a direct, unproxied connection.

#### How fresh is the data YouTube Community Posts Scraper returns?

It is a live fetch on every run — the Actor requests the channel's Community tab and paginates the `browse` endpoint at run time. It does not read from a cache or a previously stored snapshot, so re-running against the same channel a minute later reflects whatever YouTube is serving at that moment, including any new posts or updated engagement counts.

#### What happens if a channel has no Community tab, or no posts match my filters?

If a channel has no Community tab or no posts are found, the run logs a warning and the channel contributes zero rows; other channels in the same run are unaffected. If posts are found but all get filtered out by `minLikeCount`, `minCommentCount`, or `postType`, the run completes with zero pushed rows and a log message suggesting you loosen the filters — the raw scrape count and the pushed count are both recorded in the run's key-value store under `SUMMARY`, alongside the per-channel success/failure counts.

#### Which fields work best for AI training and RAG indexing?

For RAG, `text` carries the highest-information content — it's the creator's own post caption or poll question, not a caption written for search. For training data, `likeCountValue`, `commentCountValue`, and `attachmentType` are the most consistently structured fields, since they arrive as typed integers and a fixed enum rather than free text, and none of the returned fields need normalization before use in a downstream pipeline or model prompt.

#### Does YouTube Community Posts Scraper work with Claude, ChatGPT, and other AI agent tools?

There is no MCP server for this Actor. It is callable as an Apify API endpoint by any agent framework that can make an HTTP request — every response is typed JSON, so no HTML parsing step is needed before passing results into an LLM's context window, and an agent can call it mid-task the same way it would call any other REST tool.

#### How does YouTube Community Posts Scraper compare to other YouTube community post scrapers?

Compared to scrapestorm's and scraper-engine's listings (observed 2026-07-26), which return raw like/comment strings without a numeric engagement layer, this Actor's `likeCountValue`/`commentCountValue`/`sortByEngagement` do the parsing and ranking for you. Compared to lurkapi (observed 2026-07-26), which offers paid add-ons for comment scraping, image downloads, and language detection, this Actor is narrower — it doesn't fetch reply comments or download image files — but it's the only one of the three whose listing documents built-in numeric engagement filtering and sorting.

#### Are poll vote percentages or posts older than the Community tab's visible history available?

No. `pollChoices` returns each poll's answer text only — YouTube does not expose vote percentages to unauthenticated requests, so no percentage field exists in the output. `maxPosts` can be set as high as 10,000, but the Actor can only return as many posts as YouTube's Community tab actually serves for a given channel; it cannot recover posts beyond what the tab exposes.

### ℹ️ Disclaimer

YouTube Community Posts Scraper (Engagement Analytics) extracts only publicly available data from YouTube's Community tab. This tool is intended for lawful use cases only. Users are responsible for complying with YouTube's Terms of Service and applicable data protection laws in their jurisdiction.

# Actor input Schema

## `channelUrls` (type: `array`):

One or more YouTube channel URLs to scan for community posts. Accepts youtube.com/@handle or youtube.com/channel/UC... — one per line or comma-separated.

## `maxPosts` (type: `integer`):

How many community posts to fetch per channel before filtering (1–10,000). Filters are applied to this pool, so scan more than you expect to keep.

## `minLikeCount` (type: `integer`):

Keep only posts whose parsed like count is at least this value. Uses the numeric likeCountValue (e.g. "12K" → 12000). Set 0 to disable.

## `minCommentCount` (type: `integer`):

Keep only posts whose parsed comment count is at least this value. Uses the numeric commentCountValue. Set 0 to disable.

## `postType` (type: `string`):

Restrict output to a single post type by attachment. 'all' keeps everything.

## `sortByEngagement` (type: `boolean`):

When enabled, the output is sorted by total engagement (parsed likes + comments) in descending order, so the top-performing posts appear first.

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

Optional. Runs without a proxy by default. Enable an Apify proxy group or a custom URL for higher volume; if blocked, the actor escalates to Apify RESIDENTIAL on a fresh IP and continues.

## Actor input object example

```json
{
  "channelUrls": [
    "https://www.youtube.com/@MrBeast"
  ],
  "maxPosts": 10,
  "minLikeCount": 0,
  "minCommentCount": 0,
  "postType": "all",
  "sortByEngagement": false,
  "proxy": {
    "useApifyProxy": false,
    "apifyProxyGroups": []
  }
}
```

# Actor output Schema

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

All scraped items in the Actor's default dataset.

## `summary` (type: `string`):

JSON summary of the run: raw vs. pushed post counts, successful/failed channel counts, and the engagement filters that were applied.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "channelUrls": [
        "https://www.youtube.com/@MrBeast"
    ],
    "proxy": {
        "useApifyProxy": false,
        "apifyProxyGroups": []
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapio/youtube-community-posts-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "channelUrls": ["https://www.youtube.com/@MrBeast"],
    "proxy": {
        "useApifyProxy": False,
        "apifyProxyGroups": [],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("scrapio/youtube-community-posts-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "channelUrls": [
    "https://www.youtube.com/@MrBeast"
  ],
  "proxy": {
    "useApifyProxy": false,
    "apifyProxyGroups": []
  }
}' |
apify call scrapio/youtube-community-posts-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapio/youtube-community-posts-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/jW40c6Ljnwyw66Ahp/builds/e6WgnnNHPwXNeOJ27/openapi.json
