# Facebook Reels Scraper: Views, Likes, No Login (`automation_craft/facebook-reels-scraper`) Actor

Scrape the reels of public Facebook pages and profiles, no login, from links, usernames, ids or a Google Sheet, with date and caption filters. Rows: caption, hashtags, plays, exact reactions and comments, shares, music, MP4 links, page followers. JSON, CSV, API. Pay per reel delivered.

- **URL**: https://apify.com/automation_craft/facebook-reels-scraper.md
- **Developed by:** [Automation Craft](https://apify.com/automation_craft) (community)
- **Categories:** Social media, Videos, Marketing
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.32 / 1,000 reels

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

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

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### Facebook Reels Scraper: Views, Likes, No Login

**Facebook Reels scraper** for the reels of public Facebook pages and profiles, with no login, no cookies and no Facebook account: give page links, usernames, numeric ids or a link to a text file or Google Sheet, and get each page's reels from its Reels tab, newest first, down to the end of the tab or to the number of reels you ask for. Every row carries the reel's link, caption, hashtags, mentions, publish and upload time, duration and size, Facebook's play figure, exact reaction and comment counts, shares, music, thumbnail, HD and SD video links and the page's followers; one page row per page adds talking about, were here, the about line and the verified mark. Pay per reel, from $0.318 per 1,000.

Built for social media and content teams, agencies reporting on client pages, creator and brand research, trend tracking, newsrooms, academic studies and AI data sets, and for scheduled runs in n8n, Make or Zapier. Rows carry what Facebook shows a visitor who is not logged in; use them under the rules that apply to you.

#### At a glance

- A page's Reels tab read logged out from Apify's datacenter proxy: no account to lose, no cookies to keep fresh. Pages, public figures' profiles and personal profiles that show their reels to visitors are read the same way.
- Deep walks: the tab is read 10 reels a call to Facebook's end of the tab, to your number of reels, or to the start of your date window.
- Filters: a publish date window (dates or a time back such as `30 days`), words to keep or leave out of the caption, a minimum number of plays, reels per page and reels per run. Reels a filter leaves out are free.
- **Exact view count** (add-on): each delivered reel's own watch page, for the exact play count behind the cut figure the tab shows ("230K"), the video views and the reactions by type.
- **Comments** (add-on): each delivered reel's comments, and replies if you like, as rows of their own.
- Free options: transcripts from Facebook's own captions, and page details (category, address, phone, e-mail, websites, hours, price range, rating, and from the Meta Ad Library whether the Page runs ads now).

### Quick start

1. Open the Actor and type one or more pages in **Facebook pages or profiles**, one per line, for example `https://www.facebook.com/natgeo` or just `natgeo`.
2. Set **Reels per page** (the form starts at 10).
3. Optional: **Published on or after** (for example `30 days`), caption words, **Minimum plays**, the **Exact view count** or **Comments** add-ons, **Transcripts**, **Page details**.
4. Click **Start**. Download the rows as JSON, CSV or Excel, or read them through the API.

An input with no page at all returns a free sample: the newest 3 reels of facebook.com/natgeo, with only the start fee charged.

### What you get

One row per reel (`type` `reel`), one row per page (`type` `page`), comment rows with the Comments add-on (`type` `comment`), one free coverage row per page, free status rows and one free summary row per run.

#### Reel rows

| Field | What it is |
|---|---|
| `reelId`, `postId`, `url`, `mediaType` | Facebook's video id, its post id, the link (`facebook.com/reel/<id>/`, or `facebook.com/watch/?v=<id>` for a regular video Facebook lists on the page's reels tab) and `reel` or `video` |
| `caption`, `hashtags`, `mentions`, `linksInCaption` | the caption exactly as Facebook serves it, its hashtags, the people and pages it mentions (see Personal data) and the links written in it |
| `publishedAt`, `uploadedAt`, `ageHours` | when the reel was published (the date Facebook shows), when its video was uploaded, and its age in hours at the read (UTC) |
| `durationSeconds`, `width`, `height`, `aspectRatio`, `orientation` | length and size; `portrait`, `landscape` or `square` |
| `playCountLabel`, `playCountMin`, `playCountMax` | the play figure the Reels tab shows ("137K") and the range it stands for (137,000 to 137,999: Facebook cuts the figure, it does not round it) |
| `reactionCount`, `commentCount` | exact numbers of reactions and comments |
| `shareCountLabel`, `shareCountMin`, `shareCountMax` | the share figure Facebook shows (exact below 1,000, cut above) and its range |
| `engagementCount`, `engagementRate`, `playsPerHour` | reactions plus comments, that sum divided by the page's followers, and plays an hour since publication (from `playCountMin`, or from the exact play count with the add-on) |
| `thumbnailUrl`, `videoUrlHd`, `videoUrlSd`, `videoUrlExpiresAt` | the thumbnail, the HD and SD MP4 links Facebook's player plays, and the time those links stop working |
| `captionsUrl`, `captionTracks` | Facebook's own captions file and its tracks, where the reel has captions |
| `music` | `title`, `artist`, `song`, `soundtrackId`, `audioType` (`original`, `library_music`, or Facebook's own type name in lower case), `isOriginalAudio`; the title is Facebook's own sound line (artist and song, or the page and "Original audio") |
| `isPinned` | the reel Facebook shows first on the tab: the first reel uploaded more than an hour before the one after it |
| `isReshare`, `reshareCreatorName`, `reshareCreatorId`, `reshareCreatorUrl`, `collaborators` | a reshared reel's original creator, and the reel's collaborators |
| `isBrandedContent`, `brandedContentSponsor` | Facebook's paid partnership mark and the sponsor it names |
| `aiGeneratedDetected`, `aiGeneratedSelfDisclosed`, `aiTransparencyType` | Facebook's AI labels for the reel |
| `ownerName`, `ownerId`, `ownerVerified` | who posted it |
| `instagramReactionCount`, `instagramCommentCount` | the reel's Instagram counts where Facebook shows a cross posted reel's figures (empty on most reels) |
| `phones`, `emails` | phone numbers and e-mail addresses written in the caption, with personal data on only (see Personal data) |
| `pageName`, `pageType`, `pageId`, `pageClassicId`, `pageUsername`, `pageUrl`, `pageVerified`, `pageFollowers` | the page or profile whose Reels tab was read; `pageType` is `page` or `person`; followers exact |
| `playCount`, `viewCount`, `reactionsByType`, `exactViewsStatus` | with **Exact view count**: the exact play count, the video views and the reactions by type (`like`, `love`, `care`, `haha`, `wow`, `sad`, `angry`); `exactViewsStatus` is `ok`, `no_figures`, `not_found`, `other_video`, `failed`, `not_read`, `skipped_charge_limit` or `not_requested` |
| `transcript`, `transcriptCues`, `transcriptLocale`, `transcriptStatus` | with **Transcripts**: the captions' text, its timed cues and language; `transcriptStatus` is `ok`, `truncated`, `no_captions`, `not_read` or `not_requested` |
| `tabPosition`, `pageInput`, `subjectKey`, `scrapedAt` | the reel's place on the tab, the page's place in your input, a key, the time of the read |

`outputFormat` `compact` gives 28 one level fields instead (reel and post ids, link, caption, time, duration, plays, reactions, comments, shares, engagement rate, thumbnail, HD link, music title, pinned, page, transcript).

Measured fill, real platform runs of 2026-10-24 UTC on the final build (256 MB, datacenter proxy). Sample A: 1,000 reels of facebook.com/natgeo in one run (run `ngbJi8Sk5ncEhVqbn`, published 2024-03-22 to 2026-10-23). Sample B: 45 reels, one each from 45 different pages (media, sports, retail, technology and creator pages; run `pkgDFEuyytO1hIUan`).

| Field | Sample A (1,000 reels) | Sample B (45 reels) |
|---|---|---|
| `reelId`, `postId`, `url`, `mediaType`, `caption`, `publishedAt`, `uploadedAt`, `durationSeconds`, `width`, `height` | 100 % | 100 % |
| `playCountLabel` (and its range), `reactionCount`, `commentCount`, `shareCountLabel`, `engagementRate`, `playsPerHour` | 100 % | 100 % |
| `thumbnailUrl`, `videoUrlSd`, `videoUrlExpiresAt` | 100 % | 100 % |
| `videoUrlHd` | 98.8 % | 100 % |
| `pageFollowers`, `pageVerified`, `ownerName` | 100 % | 100 % |
| `hashtags` (at least one) | 45.7 % | 40 % |
| `mentions` (at least one) | 45 % | 11.1 % |
| `music.title` | 7.4 % | 37.8 % |
| `captionsUrl` (Facebook's own captions) | 3.7 % | 26.7 % |

`mediaType`: 605 of the 1,000 natgeo rows were `reel` and 395 were `video`, regular videos Facebook lists on that page's reels tab (sample B: 40 reels and 5 videos), so filter on `mediaType` if you want reels only. With the add-ons on (smaller runs of the same day): **Exact view count** read 6 of 6 reels; **Transcripts** gave text for 7 of 10 reels of a public figure's profile (3 `no_captions`); **Page details** read the About tab and the Ad Library facts of 2 of 2 Pages (a media brand with 237 active ads, a bakery with its address, phone and rating) and marked the person's profile `not_a_page`.

#### Page rows

`pageName`, `pageType`, `pageId`, `pageClassicId`, `pageUsername`, `pageUrl`, `pageVerified`, `pageFollowers`, `pageTalkingAbout`, `pageWereHere`, `pageAbout`, `pagePlace`, `pageProfilePictureUrl`. With **Page details** on, for Pages: `category`, `address`, `phone`, `email`, `websites`, `businessHours`, `priceRange`, `rating`, `recommendPercent`, `reviewCount`, `pageDetailsStatus`, and from the Meta Ad Library `isRunningAds`, `activeAdsCount`, `adLibraryUrl`, `pageCreatedAt`, `pageNameChanges`, `pageAdminCountries`, `adsStatus`. Page details are never read for a person's profile (`not_a_page`).

#### Comment rows (Comments add-on)

`commentId`, `reelId`, `postId`, `reelUrl`, `parentCommentId`, `threadCommentId`, `depth`, `text`, `language`, `createdAt`, `authorName`, `authorId`, `authorUrl`, `authorIsReelAuthor`, `authorBadges`, `reactionCount`, `reactions`, `replyCount`, `attachments`, `isEdited`, `mentions`, `phones`, `emails`, `commentUrl` (the comment's link on the reel's own link, `?comment_id=`), `pageName`, `subjectKey`, `scrapedAt`. Comments come oldest first, up to **Comments per reel** (replies included).

#### Coverage, status and summary rows (free)

- **coverage** (one per page): calls read, reels read, delivered and charged, repeats, reels another page already delivered, reels past the cap, every filter's count (`filtered`: `newer`, `older`, `keywords`, `plays`), whether a pinned reel was seen, the newest and oldest reel dates, `stopReason` (`end_of_reels`, `max_reels_per_page`, `window_end`, `no_reels`, `page_not_found`, `page_not_public`, `max_items`, `charge_limit`, `work_allowance`, `max_run_seconds` and the like) and `complete`.
- **status**: a page Facebook says is not available (`page_not_found`), a profile Facebook shows only behind its login page (`page_not_public`), values not used (`values_skipped`, positions only), an add-on that could not be read in the run (`addon_unavailable`), a call Facebook did not answer (`lookup_failed`), pages not started (`skipped`), invalid input (`invalid`), the empty input sample (`sample`), and a date window in the past that the walk did not reach (`window_not_reached`, with `passedNewer` and `reachedBackTo`: see Limits).
- **summary** (the last row): the run's counters, its requests, the work allowance and its charges per event.

#### Example reel row (Apify platform run of 2026-10-24, links shortened, some empty fields left out)

```json
{
  "type": "reel",
  "reelId": "1474215734570532",
  "postId": "1697487478415342",
  "url": "https://www.facebook.com/reel/1474215734570532/",
  "mediaType": "reel",
  "caption": "No wrong answers to this question.\n\n#IndiaFromAbove is now streaming on Disney+",
  "hashtags": ["IndiaFromAbove"],
  "mentions": [{ "name": "Disney+", "type": "person", "id": null, "url": null }],
  "linksInCaption": [],
  "phones": null,
  "emails": null,
  "publishedAt": "2026-10-21T22:00:13.000Z",
  "uploadedAt": "2026-10-21T22:00:00.000Z",
  "ageHours": 50.5,
  "durationSeconds": 15.018,
  "width": 1080,
  "height": 1920,
  "aspectRatio": 0.563,
  "orientation": "portrait",
  "playCountLabel": "137K",
  "playCountMin": 137000,
  "playCountMax": 137999,
  "reactionCount": 886,
  "commentCount": 24,
  "shareCountLabel": "21",
  "shareCountMin": 21,
  "shareCountMax": 21,
  "playsPerHour": 2712.86,
  "engagementCount": 910,
  "engagementRate": 0.000018,
  "thumbnailUrl": "https://scontent-lga3-2.xx.fbcdn.net/v/t15.5256-10/863384256...",
  "videoUrlHd": "https://video-lga3-1.xx.fbcdn.net/o1/v/t2/f2/m366/AQO4w1xE4-...",
  "videoUrlSd": "https://video-lga3-2.xx.fbcdn.net/o1/v/t2/f2/m412/AQMubjmvH_...",
  "videoUrlExpiresAt": "2026-10-28T09:58:18.000Z",
  "captionsUrl": null,
  "captionTracks": [],
  "music": { "title": null, "artist": null, "song": null, "soundtrackId": null, "audioType": null, "isOriginalAudio": true },
  "isReshare": false,
  "isPinned": false,
  "isBrandedContent": false,
  "aiGeneratedDetected": false,
  "aiGeneratedSelfDisclosed": false,
  "aiTransparencyType": "NONE",
  "collaborators": [],
  "ownerName": "National Geographic",
  "ownerId": "100044623170418",
  "ownerVerified": true,
  "pageName": "National Geographic",
  "pageType": "page",
  "pageId": "100044623170418",
  "pageClassicId": "23497828950",
  "pageUsername": "natgeo",
  "pageUrl": "https://www.facebook.com/natgeo",
  "pageVerified": true,
  "pageFollowers": 51425370,
  "playCount": null,
  "viewCount": null,
  "reactionsByType": null,
  "exactViewsStatus": "not_requested",
  "transcript": null,
  "transcriptStatus": "not_requested",
  "tabPosition": 5,
  "pageInput": 1,
  "scrapedAt": "2026-10-24T00:30:13.603Z"
}
```

The mention shows the personal data switch at work: Facebook did not type that mention as a Page, so with personal data off it keeps its name and its id and link stay empty.

#### How fast

Measured on the platform (final build, 256 MB, datacenter proxy), 2026-10-24 UTC: the prefill (10 reels) in 7 seconds; 1,000 reels of one page in 953 seconds (about 63 a minute), peak memory 108 MB; 3 pages at once (`maxConcurrency` 3) delivered 26 reels in 10 seconds; 6 reels with **Exact view count** in 48 seconds; 3 reels with their comments and replies in 8 seconds; 50 pages of one reel each in 447 seconds.

### How much does it cost to scrape Facebook reels?

Pay per event: you pay for the reels delivered, once for each page that delivered a charged reel, and for the add-ons you turn on. A repeat, a reel a filter leaves out, a page that is missing, private or has no reels, a failed call and an input that cannot be used are never charged.

| Event | Free | Bronze | Silver | Gold |
|---|---|---|---|---|
| Reel (`reel`), per 1,000 reels | $0.45 | $0.41 | $0.37 | $0.318 |
| Page (`page`), per 1,000 pages | $1.80 | $1.65 | $1.50 | $1.30 |
| Exact view count (`exact_views`), per 1,000 reels, add-on | $1.26 | $1.15 | $1.05 | $0.90 |
| Comment (`comment`), per 1,000 comments, add-on | $0.27 | $0.24 | $0.22 | $0.19 |
| Actor start (`apify-actor-start`), once per run | $0.008 | $0.008 | $0.008 | $0.008 |

Platinum and Diamond plans pay the Gold price. There is no discount on the Actor start event (one event per GB of run memory; this Actor runs at 256 MB, so a run pays one). The Store pricing card shows these same prices per 1,000 events: "$0.45 / 1,000" on the Reel row means one reel costs $0.00045 on the Free plan, under a twentieth of a cent, and "$1.80 / 1,000" on the Page row means one page row costs $0.0018.

- **Reel** is charged once per reel per run: a page given twice, or a reel on two pages' tabs, is delivered and charged once.
- **Page** is charged once per page, with the page's first charged reel; a page that delivers no charged reel gets its page row free.
- **Exact view count** is charged only with the add-on on, and only when the reel's watch page gave its figures. Some watch pages come back without them (4 of 11 first reads in the feasibility tests of 2026-10-23); such a page is asked again on a fresh exit, up to 3 reads in all, and a reel whose page still shows none is delivered without them (`exactViewsStatus` `no_figures`) and not charged for them.
- **Comment** is charged per comment or reply row with the add-on on.
- **Transcripts** and **Page details** cost nothing extra.

Worked examples, start fee included:

| Run | Free | Bronze | Silver | Gold |
|---|---|---|---|---|
| The prefill: 10 reels of one page | $0.0143 | $0.01375 | $0.0132 | $0.01248 |
| 100 reels of one page | $0.0548 | $0.05065 | $0.0465 | $0.0411 |
| 1,000 reels: 100 reels from each of 10 pages | $0.476 | $0.4345 | $0.393 | $0.339 |
| 20 reels of one page with Exact view count (all 20 read) | $0.044 | $0.04085 | $0.0379 | $0.03366 |
| 20 reels of one page with 20 comments each (400 comment rows) | $0.1268 | $0.11385 | $0.1049 | $0.09166 |

Every run reads its pages fresh: a reel a scheduled run delivered yesterday is delivered and charged again today. Narrow a daily run with **Published on or after** (for example `2 days`) and dedupe on `reelId` in your own sheet or workflow. Set a charge limit on the run and it stops there, with every row already delivered kept.

#### The work allowance

Work that earns nothing (pages whose reels every filter leaves out, refused calls, long stretches of repeats) is bounded by an allowance in real cost that grows with every event the run bills. When it is spent the run stops: the page it was reading ends with `work_allowance` in its coverage row, the pages not started get a free `skipped` row, and every row already delivered is kept. The add-ons read from a small allowance of their own, so a watch page or a comment call that fails never stops the walk it serves.

### Input

| Field | What it does | Default |
|---|---|---|
| `pages` | Up to 500 public pages or profiles, one per line: a link (`facebook.com/natgeo`, `facebook.com/natgeo/reels/`, `facebook.com/profile.php?id=100044623170418`, `facebook.com/people/Name/100044623170418/`, `facebook.com/p/Name-100044623170418/`), a username (`natgeo` or `@natgeo`) or a numeric id. A link to a single reel, video, post, group or event is skipped free and named in a `values_skipped` row. Also read: `startUrls`, `profileUrls`, `facebook_urls`, `username`, `pageId`. | none (the form starts with `https://www.facebook.com/natgeo`) |
| `pagesListUrl` | One https link to a public text or CSV file of up to 1 MB, or a Google Sheet shared with "anyone with the link" (its first tab, or the tab in the link). Every cell that names facebook.com is read, and in a one column file every line (a value that is not a page is skipped free). It joins `pages` (500 together at most). One file link a run: a `startUrls` item written as `{ "requestsFromUrl": "..." }` is read the same way, instead of this field. A link that cannot be read in 20 seconds stops the run before anything is fetched from Facebook. | none |
| `maxReelsPerPage` | Reels delivered per page, newest first (after a pinned reel), 1 to 100,000; reels left out by a filter do not count. Also read: `resultsLimit`, `maxReelsPerProfile`, `reels_count`, `maxReels`. | 20 (the form starts at 10) |
| `maxItems` | A cap on the reels of the whole run. Also read: `maxResults`. | no cap |
| `onlyReelsNewerThan`, `onlyReelsOlderThan` | The publish date window, UTC: `YYYY-MM-DD`, an ISO time, `today`, `yesterday`, or a time back such as `7 days`, `2 weeks`, `3 months`, `1 year`. Also read: `onlyPostsNewerThan`, `reelsNewerThan`, `reels_newer_than`, `postedAfter`, `newerThan`, `sinceDays` (a number of days), `onlyPostsOlderThan`, `postedBefore`, `olderThan`. | no window |
| `includeKeywords`, `excludeKeywords` | Up to 50 words or phrases to keep (any of them) and to leave out (any of them), matched in the caption and hashtags as whole words, case and accents aside. Also read: `keywordFilter`. | none |
| `minPlays` | Only reels whose play figure on the tab certainly reaches this number ("28K" counts as 28,000). Also read: `minPlayCount`, `minViews`. | none |
| `includeExactViews` | The Exact view count add-on. Also read: `enrichDetailPage`, `enrichReelDetails`. | off |
| `includeComments`, `maxCommentsPerReel` | The Comments add-on and the comment rows per reel (1 to 5,000, replies included). Also read: `fetchComments`. | off, 20 |
| `includeReplies`, `maxRepliesPerComment` | Replies under each comment (1 to 1,000 a comment), with comments on. Also read: `fetchCommentReplies`. | off, 10 |
| `includeTranscript` | Facebook's own captions as text and timed cues (free). Also read: `fetchTranscript`. | off |
| `includePageDetails` | A Page's About tab and Ad Library facts on its page row (free, Pages only). Also read: `include_profile_details`, `enrichAuthorProfile`. | off |
| `includePersonalData` | The personal data switch (below). | off |
| `outputFormat` | `full` or `compact`. | `full` |
| `maxConcurrency` | Pages read at the same time, 1 to 3. Prices do not change. | 1 |
| `requestDelayMs` | The pause between two calls of one page, 300 to 10,000 ms. | 400 |
| `maxRunSeconds` | End the run after this many seconds (60 to 86,400) with what was read so far. | the run's own timeout |
| `proxyConfiguration` | Apify Proxy's datacenter pool (default), your own proxy links, or no proxy (the run's own address). Apify's `RESIDENTIAL` group is not offered (its transfer price is far above what a reel is charged): it refuses the input, nothing is fetched and only the run's start fee is charged. Also read: `proxy`. | Apify datacenter pool |

A value sent as `null` or `""` counts as left out. Two keys of one meaning sent together, a setting name the Actor does not know, or a value it cannot use as given refuse the input with one free `invalid` row (only the start fee is charged).

#### How the date window works

Facebook lists a page's reels by the time their video was UPLOADED, newest first, after an optional pinned reel, while the date it shows is the PUBLISH time, which can be later (a scheduled reel). The window is judged on the publish time, and the walk goes on until the reels it reads were uploaded more than 30 days before the window's start, so a reel published within 30 days of its upload is found. A reel published more than 30 days after its upload can be missed by a window.

Examples:

```json
{ "pages": ["natgeo", "https://www.facebook.com/nike/reels/"], "maxReelsPerPage": 100 }
```

```json
{
  "pages": ["natgeo"],
  "onlyReelsNewerThan": "30 days",
  "excludeKeywords": ["sponsored"],
  "minPlays": 100000,
  "includeExactViews": true
}
```

```json
{
  "pagesListUrl": "https://docs.google.com/spreadsheets/d/<your sheet id>/edit#gid=0",
  "maxReelsPerPage": 20,
  "includeComments": true,
  "maxCommentsPerReel": 20,
  "includePageDetails": true
}
```

### Limits

- **No jump to a date.** Facebook's Reels tab can only be walked newest first; there is no way to start at a date. A window that ends in the past (**Published on or before**, `onlyReelsOlderThan`) means walking past every newer reel first. That walk is free to you, but it is bounded in every run by the work allowance (above): asked for June 2026, the walk of facebook.com/natgeo passed 40 newer reels, back to 2026-10-01, before it stopped (platform run of 2026-10-24, final build). When the window is not reached, the page gets a free `window_not_reached` status row that says how far back the walk got (`passedNewer`, the reels walked past, and `reachedBackTo`, the oldest upload day it saw), and nothing is charged for that page. A window that reaches up to today (**Published on or after** alone) is read normally.
- A reel published more than 30 days after its upload can be missed by a date window (above).
- Up to 500 pages a run, up to 100,000 reels a page, 1 to 3 pages read at the same time, 256 MB of run memory. A run delivers at most 100,000 rows in all (reels, pages and comments together); run it again for more.
- The play figure on the Reels tab is cut ("230K"); exact plays need **Exact view count**, and a watch page that still shows no figures after 3 reads leaves the reel without them, free.
- Facebook's video links expire (`videoUrlExpiresAt`); download the files you need soon after the run.

### Personal data

Off by default. A Page's facts are always delivered. A person's profile (a public figure's included) keeps its name, and its profile id, username, link and picture stay empty (`pageId`, `pageClassicId`, `pageUsername`, `pageUrl`, `pageProfilePictureUrl`, `ownerId`). People mentioned in a caption, reshared or collaborating creators and commenters keep their names, without ids or profile links; phone numbers and e-mail addresses in captions and comments are not listed (`phones`, `emails` stay empty), and a link in a comment's attachments that leads to a person's profile, or is a contact link, is left empty. Reel links never hold a profile name (`facebook.com/reel/<id>/` or `facebook.com/watch/?v=<id>`). Texts are never masked. With **Include personal data** (`includePersonalData: true`) those fields are filled; you are responsible for a lawful use of personal data (GDPR included).

### What this Actor does NOT do

- **Logged in data and cookies**: it reads what a visitor who is not logged in sees; no account, no cookies, nothing private. A profile Facebook shows only behind its login page (asked twice, on two exits) gets a free `page_not_public` row.
- **A reel by its link**: it reads a page's Reels tab; a single reel, video or post link is skipped free. For posts, videos and reels by link use the Facebook Post Scraper.
- **Keyword or hashtag search**: it reads the pages you name; to find reels by words use the Facebook Video Search Scraper.
- **Jumping to a date**: the Reels tab is walked newest first, so a window far in the past may not be reached in one run (a free `window_not_reached` row says how far back it got; see Limits).
- **Exact plays without the add-on**: the Reels tab shows a cut play figure ("230K"); the exact play count comes only with **Exact view count**.
- **Speech to text**: transcripts are Facebook's own captions; a reel without captions has no transcript (`no_captions`).
- **The video files themselves**: rows carry the MP4 links Facebook serves, which stop working at `videoUrlExpiresAt`; the files are not stored.
- **A place**: the Reels tab carries no location for a reel.
- **A memory of earlier runs**: there is no monitor or "new reels only" mode; each run reads its pages fresh. Schedule it with Apify's scheduler and use a date window.
- **Alerts and an always on API**: no per reel webhook (use Apify's run webhooks) and no Standby endpoint.
- **Outside services**: no speech to text or translation through your own outside account or key; no residential proxy (see Input).

### API examples

Run and get the rows (replace `<APIFY_TOKEN>`):

```bash
curl -X POST "https://api.apify.com/v2/acts/automation_craft~facebook-reels-scraper/run-sync-get-dataset-items?token=<APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"pages": ["natgeo"], "maxReelsPerPage": 20}'
```

Node.js:

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<APIFY_TOKEN>' });
const run = await client.actor('automation_craft/facebook-reels-scraper').call({ pages: ['natgeo'], maxReelsPerPage: 20, includeExactViews: true });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.filter((x) => x.type === 'reel'));
```

Python:

```python
from apify_client import ApifyClient
client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("automation_craft/facebook-reels-scraper").call(run_input={"pages": ["natgeo"], "maxReelsPerPage": 20})
reels = [x for x in client.dataset(run["defaultDatasetId"]).iterate_items() if x["type"] == "reel"]
```

Send the rows where you need them with Apify's own integrations: a webhook on the run's end, or the Make, Zapier and n8n Apify modules.

### FAQ

#### Can I scrape Facebook reels without logging in?

Yes. The Actor reads each page's Reels tab the way a visitor who is not logged in sees it, through Apify's datacenter proxy: no account, no cookies. It returns public reels of pages and of profiles that show them to visitors; a profile Facebook shows only behind its login page (asked twice, on two exits) gets a free page_not_public row.

#### Does it get the exact view count of Facebook reels?

The Reels tab shows a cut play figure ("137K"), delivered as `playCountLabel` with the range it stands for (`playCountMin`, `playCountMax`). Turn on **Exact view count** and each reel's own watch page adds the exact `playCount`, the `viewCount` and `reactionsByType`; it is charged only when the page gave those figures.

#### How do I get all the reels of a Facebook page?

Set **Reels per page** high (up to 100,000): the walk goes 10 reels a call to the end of the tab, and the coverage row says `end_of_reels` when it got there. Add **Published on or after** to stop at a date instead.

#### Can I download the reels or export them to CSV?

Each row carries `videoUrlHd` and `videoUrlSd`, the MP4 files Facebook's player plays; download them before `videoUrlExpiresAt`, the time Facebook's links stop working. The rows themselves download as JSON, CSV or Excel from the run, or through the API.

#### Can I get the transcript of a Facebook reel?

Yes, where the reel has Facebook's own captions: turn on **Transcripts** (free) and each row gets `transcript`, its timed `transcriptCues` and `transcriptStatus`. There is no speech to text, so a reel without captions says `no_captions`.

#### Why does this Actor run with limited permissions?

It needs nothing beyond its own run storage, so it runs with Apify's limited permissions (least privilege): it can read and write only the dataset and key-value store of its own run, and nothing else in your account.

### More data tools by Automation Craft

- [Facebook Video Search Scraper: Reels, No Login](https://apify.com/automation_craft/facebook-video-search-scraper)
- [Facebook Posts Scraper - Page Posts, No Login](https://apify.com/automation_craft/facebook-posts-scraper)
- [Facebook Post Scraper: Reactions and Shares by URL](https://apify.com/automation_craft/facebook-post-scraper)
- [Facebook Comments Scraper: Replies, No Login](https://apify.com/automation_craft/facebook-comments-scraper)
- [Facebook Groups Scraper: Posts of Public Groups](https://apify.com/automation_craft/facebook-groups-scraper)
- [Facebook Page ID Finder: Names to Page IDs](https://apify.com/automation_craft/facebook-page-id-finder)
- [Instagram Posts Scraper: Profiles, Reels, No Login](https://apify.com/automation_craft/instagram-posts-scraper)
- [Threads Scraper: Posts, Search, Tags, Replies](https://apify.com/automation_craft/threads-scraper)
- [Meta Ad Transcript Scraper - Video Ads to Text](https://apify.com/automation_craft/meta-ad-transcript-scraper)
- [Meta Ads Library Scraper - Ad Library, All Filters](https://apify.com/automation_craft/meta-ads-library-scraper)

### Changelog

See the Changelog tab (`CHANGELOG.md`).

# Changelog

This Actor's version history is a separate document: https://apify.com/automation_craft/facebook-reels-scraper/changelog.md

# Actor input Schema

## `pages` (type: `array`):

Public Facebook pages or profiles, one per line: a link (facebook.com/natgeo, facebook.com/natgeo/reels/, facebook.com/profile.php?id=100044623170418, facebook.com/people/Name/100044623170418/), a username (natgeo or @natgeo) or a numeric id. Up to 500. Links of a single reel, post, video, group or event are skipped free. Also read as startUrls, profileUrls, facebook_urls, username or pageId.

## `pagesListUrl` (type: `string`):

One https link to a public text or CSV file of up to 1 MB, or to a Google Sheet shared with "anyone with the link" (its first tab, or the tab in the link, is read as CSV). Every cell that names facebook.com is read, and in a file of one column every line (a link, a username or a numeric id; a value that is not a page is skipped free). It joins the pages above (at most 500 together). A link that cannot be read in 20 seconds stops the run before anything is fetched from Facebook. One file link a run: an item of startUrls written as {"requestsFromUrl": "..."} is read the same way, instead of this field.

## `maxReelsPerPage` (type: `integer`):

How many reels to deliver for each page, newest first (after a pinned reel, which Facebook shows first). Reels left out by a filter do not count. Also read as resultsLimit, maxReelsPerProfile, reels_count or maxReels.

## `maxItems` (type: `integer`):

An upper bound on the reels the whole run delivers, across every page. Empty: no bound beyond the reels per page and your charge limit. Also read as maxResults.

## `onlyReelsNewerThan` (type: `string`):

Only reels published on or after this day (UTC): YYYY-MM-DD, an ISO time, today, yesterday, or a relative "7 days", "2 weeks", "3 months", "1 year" counted back from the run's start. Facebook lists reels by upload time; a reel published more than 30 days after its upload can be missed. Also read as onlyPostsNewerThan, reelsNewerThan, reels_newer_than, postedAfter or newerThan; sinceDays takes a number of days.

## `onlyReelsOlderThan` (type: `string`):

Only reels published on or before this day (UTC), the same forms as the start. Newer reels are read and left out free. Also read as onlyPostsOlderThan, postedBefore or olderThan.

## `includeKeywords` (type: `array`):

Only reels whose caption or hashtags contain at least one of these words or phrases, as whole words, case and accents ignored. Reels left out are free. Also read as keywordFilter.

## `excludeKeywords` (type: `array`):

Leave out reels whose caption or hashtags contain any of these words or phrases (the same matching). Reels left out are free.

## `minPlays` (type: `integer`):

Leave out reels whose play figure on the reels tab is below this number. Facebook shows a cut figure (28K), read as the lowest number it can stand for (28,000), so a reel is kept only when it certainly reaches the minimum. Reels left out are free. Also read as minPlayCount or minViews.

## `includeExactViews` (type: `boolean`):

Read each delivered reel's own watch page for its exact play count (the Reels tab shows a cut figure such as 28K), its video views and its reactions by type. Charged as the Exact view count event on each reel whose page gave its figures; a reel whose page did not is delivered without them, free. Also read as enrichDetailPage or enrichReelDetails.

## `includeComments` (type: `boolean`):

Deliver each delivered reel's comments as rows of their own, oldest first, up to the number below. Charged as the Comment event per comment row. Commenters' names are delivered; their ids and profile links only with personal data on. Also read as fetchComments.

## `maxCommentsPerReel` (type: `integer`):

With comments on: how many comment rows (replies included) to deliver for each reel.

## `includeReplies` (type: `boolean`):

With comments on: read the replies under each comment too (charged as Comment rows, inside the comments per reel). Also read as fetchCommentReplies.

## `maxRepliesPerComment` (type: `integer`):

With replies on: how many replies to read under each comment.

## `includeTranscript` (type: `boolean`):

Add each reel's spoken words where Facebook publishes its own captions for it: the text and the timed cues. No extra charge. A reel without captions says so (no speech to text is run). Also read as fetchTranscript.

## `includePageDetails` (type: `boolean`):

Add each Page's About tab and its Meta Ad Library facts to its page row: category, address, phone, e-mail, websites, business hours, price range, the rating line, and whether the Page runs ads now (with its active ads count, Ad Library link, creation date, name changes and the countries of the people who manage it). No extra charge; read for Pages only, never for a person's profile. Also read as include_profile_details or enrichAuthorProfile.

## `includePersonalData` (type: `boolean`):

Off: a person's profile (a public figure's included) keeps its name, and its profile id, username, link and picture are empty; commenters, mentioned people and reshared or collaborating creators keep their names without ids or links; phone numbers and e-mail addresses read from captions and comments are not listed. On: those fields are filled. You are responsible for a lawful use of personal data (GDPR included).

## `outputFormat` (type: `string`):

full: every field of a reel. compact: 28 fields most buyers sort and chart by (ids, link, caption, time, duration, plays, reactions, comments, shares, engagement, links, music, page).

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

How many pages to read at the same time (1 to 3).

## `requestDelayMs` (type: `integer`):

The pause between two calls of one page, in milliseconds (300 to 10000; 400 when empty).

## `maxRunSeconds` (type: `integer`):

End the run after this many seconds with what was read so far (60 to 86400). Empty: the run's own timeout.

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

Apify's datacenter proxy by default (every door of this Actor answers it logged out). Your own proxy links are possible, and no proxy uses the run container's own address. Apify's residential group is not offered: its transfer price is far above what a reel is charged.

## Actor input object example

```json
{
  "pages": [
    "https://www.facebook.com/natgeo"
  ],
  "maxReelsPerPage": 10,
  "maxCommentsPerReel": 20,
  "maxRepliesPerComment": 10,
  "includePersonalData": false,
  "outputFormat": "full",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `items` (type: `string`):

No description

# 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 = {
    "pages": [
        "https://www.facebook.com/natgeo"
    ],
    "maxReelsPerPage": 10,
    "maxCommentsPerReel": 20,
    "maxRepliesPerComment": 10,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation_craft/facebook-reels-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 = {
    "pages": ["https://www.facebook.com/natgeo"],
    "maxReelsPerPage": 10,
    "maxCommentsPerReel": 20,
    "maxRepliesPerComment": 10,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("automation_craft/facebook-reels-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 '{
  "pages": [
    "https://www.facebook.com/natgeo"
  ],
  "maxReelsPerPage": 10,
  "maxCommentsPerReel": 20,
  "maxRepliesPerComment": 10,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call automation_craft/facebook-reels-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation_craft/facebook-reels-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/XzqXkNj3nOEBV7Gda/builds/PYytLhHrwuActtKXv/openapi.json
