# Facebook Videos Scraper: Page Videos, Views (`automation_craft/facebook-videos-scraper`) Actor

Pull a public Facebook page's whole Videos tab, reels included, with no login: give links, usernames or page ids. Each video: exact plays and post plays, reactions by type, comment and share counts, title, upload date, length, HD and SD MP4 files, captions. JSON, CSV, API. Pay per video.

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

## Pricing

from $4.22 / 1,000 videos

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 Videos Scraper: Page Videos, Views

**Facebook videos scraper** for the Videos tab of public Facebook pages and profiles, with no login, no cookies and no Facebook account: give page links, usernames or numeric ids (or a link to a text file or Google Sheet of them) and get every video and reel the page posted, newest first, one row per video, with Facebook's exact play count, the post's own plays, reactions by type, comments, shares, title, text, publish time, length, size, the SD and HD video files and captions. One row per page adds its followers and about line. Pay per video, from $4.22 per 1,000.

Built for social media and brand teams tracking competitors' video performance, agencies reporting on client pages, media monitoring, researchers and archivists building video data sets, and 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

- **The whole Videos tab of a page**, newest first, to the number you set (up to 100,000 a page) or to Facebook's own end of the list. Reels are part of the list; with details (the default) each row says whether it is a reel or a video.
- **Exact plays**: `playCount` is Facebook's exact play count (not "353K"), `postPlayCount` the plays of this post alone, `playCountLabel` the count as Facebook shows it.
- **Details on every video at the video price** (on by default): reel or video, comment count, share count, the HD video file, Facebook's captions, the music of a reel. Turn them off for faster list only rows.
- **Pages in every form**: links (`/natgeo`, `/natgeo/videos/`, `profile.php?id=`, `/people/Name/id/`), usernames, `@handles`, numeric profile ids and a page's numeric (delegate) id, up to 500 a run. The same page given twice is read once.
- **Filters**: a publish date window, minimum and maximum plays, minimum and maximum length, minimum reactions, words to keep or leave out, reels only or videos only, only videos with captions. Videos a filter leaves out are free.
- **Transcripts** (free option): Facebook's own captions file of each video as text and timed cues.
- **Comments** (add-on): each delivered video's comments and replies as rows, oldest first, newest first or most relevant.
- **Page details** (free option): 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 **Videos per page** (the form starts at 10; empty means 50; 100000 reads a page's whole Videos tab).
3. Optional: a date window (**Published on or after**, **Published on or before**), **Minimum plays**, **Reels or videos**, words in **Text contains**.
4. Optional: the **Comments (add-on)**, **Transcripts** or **Page details**. **Video details** is on by default.
5. Click **Start**. Download the rows as JSON, CSV or Excel, or read them through the API.

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

### What you get

Every run writes rows of six types to its dataset: `video`, `page`, `comment` (the add-on), and the free `coverage`, `status` and `summary` rows. The `type` field says which.

#### Video rows

"With details" means **Video details** on (the default): each video's reel page is read, or, for a video of a post with several videos, the video's own page (that page shows no share count). The measured fill is over 1,547 rows (1,520 distinct videos) of 9 pages of different kinds (a media brand, a space agency, a public figure's profile, news outlets, a creator, an artist, a football club, a small bakery) read from the Videos tab list on 2026-10-24; the details fields are not on the list and come from the details read.

| Field | What it is | Without details | With details | Measured fill (list) |
|---|---|---|---|---|
| `type` | `video` | always | always | 100 percent |
| `videoId` | Facebook's numeric video id (a string) | always | always | 100 percent |
| `url` | the video's link: `facebook.com/<page>/videos/<id>/` for a Page (or a person's profile with personal data on), else `facebook.com/watch/?v=<id>` | always | always | 100 percent |
| `canonicalUrl` | the same link with Facebook's title slug | Pages | Pages | not measured |
| `videoType` | `reel` or `video`, from Facebook's own link of the video on its own page | null | yes | details only |
| `postId` | the post the video was published in | when the list names it | yes | not measured |
| `title` | the video's own title when it has one (null otherwise) | when set | when set | not measured |
| `savedTitle` | Facebook's saved title line (the text when no title is set) | yes | yes | 100 percent |
| `text`, `hashtags`, `mentions`, `linksInText` | the post's text exactly as Facebook serves it, its hashtags, mentioned pages and people, and the links written in it | when the post has text | when the post has text | 94.8 percent (text) |
| `phones`, `emails` | phone numbers and e-mail addresses written in the text | personal data on | personal data on | not measured |
| `publishedAt`, `publishedAtUnix`, `ageHours` | when the video was published (UTC) and its age at the run | yes | yes | 100 percent |
| `playCount`, `playCountLabel` | Facebook's exact play count (every post that shares the video together) and the same count as Facebook shows it ("353K") | yes | yes | 100 percent |
| `postPlayCount`, `totalPosts` | the plays of this post alone, and how many posts share the video | yes | yes | 95.9 percent (post plays) |
| `playsPerHour` | plays over the hours since publishing | yes | yes | derived |
| `reactionCount`, `reactionCountIsExact`, `reactionsByType` | the post's reactions and their split by type (like, love, care, haha, wow, sad, angry). Facebook's list gives most totals exactly, but sometimes gives a total of 10,000 or more as 10,000: that row says `reactionCountIsExact: false` (a floor: at least that many) and carries no split; with **Video details** on, the video's page gives the exact total (46 and 21 of 1,000 natgeo videos in two runs, 2026-10-24 and 2026-10-25), or, where it too shows only a floor, the larger of 10,000 and Facebook's cut label ("12K" is 12000), still marked not exact | the types the list shows; 10,000 is a floor | the exact total, or a floor | 99.9 percent |
| `commentCount` | the post's comment count | null | yes | details only |
| `shareCount`, `shareCountIsExact` | the post's share count: exact under 1,000, Facebook's label above ("1.8K" is 1800) | null | from the reel page | details only |
| `engagementCount`, `engagementRate` | reactions plus comments plus shares, and that sum per play | null | when all three are read and the reactions total is exact | derived |
| `durationSeconds` | the video's length in seconds | yes | yes | 100 percent |
| `width`, `height`, `orientation`, `aspectRatio` | the video's size | yes | yes | 100 percent |
| `isLive`, `broadcastStatus` | whether the video is live, and Facebook's broadcast status | yes | yes | 3 of 1,547 rows carried a status |
| `thumbnailUrl` | the video's thumbnail image | yes | yes | 100 percent |
| `videoFileUrlSd` | the SD MP4 file on Facebook's file host | yes | yes | 100 percent |
| `videoFileUrl` | the HD MP4 file | null | yes | details only |
| `videoFileQuality`, `videoFileFormat`, `videoFileUrlExpiresAt` | `sd` or `hd`, `mp4`, and when Facebook's file link stops working | yes | yes | follows the files |
| `hasCaptions`, `captionsUrl`, `captionsLocale`, `captionsLanguage`, `captionsCreationMethod`, `captionTracks` | Facebook's captions (subtitles): the file the video plays, its language, how it was made, and every track Facebook lists (`hasCaptions` is true when it lists any) | null | yes | details only |
| `transcript`, `transcriptCues`, `transcriptStatus` | the captions as text and timed cues (**Transcripts** option); the status says `ok`, `truncated`, `no_captions`, `not_read` or `not_requested` | not read | with the option | option |
| `musicTitle`, `musicAudioType` | a reel's own music track and Facebook's type for that audio | null | where Facebook serves it | details only |
| `detailsStatus`, `detailsSource` | `ok`, `not_requested`, `failed` or `other_post` (Facebook did not give the details: the row is free); `reel_page` or `video_page` | always | always | 100 percent |
| `pageName`, `pageType`, `pageId`, `pageClassicId`, `pageUsername`, `pageUrl`, `pageVerified`, `pageFollowers` | the page the video was read from (a person's id, username and link only with personal data on) | yes | yes | not measured |
| `position`, `pageInput`, `subjectKey`, `scrapedAt` | the video's place in the page's list (1 is the newest), the input value's position, the page's key in the run, and the time of the read | always | always | 100 percent |

Measured fill on 89 videos (86 reels, 3 videos) of 6 pages (National Geographic, NASA, CNN, BBC News, MrBeast Gaming, Mark Zuckerberg) read with **Video details** on in the test runs of 2026-10-24 (UTC): play count, the post's own plays, reactions by type, comments, the HD file and the post id 100 percent; text 96.6 percent; shares 96.6 percent (81 exact, the rest Facebook's rounded label; a video read from its own page has none); a title of its own 21.3 percent (`savedTitle` 100 percent); a reel's music 14.6 percent; captions listed 10.1 percent and a captions file 5.6 percent. Most pages post far more reels than classic videos (9 of 9 of the newest on natgeo, CNN, BBC News and TED were reels; 7 of 9 were videos on MrBeast Gaming).

**Row format** `compact` keeps 26 fields: `type`, `videoId`, `url`, `videoType`, `title`, `text`, `publishedAt`, `durationSeconds`, `playCount`, `postPlayCount`, `reactionCount`, `reactionCountIsExact`, `commentCount`, `shareCount`, `engagementRate`, `thumbnailUrl`, `videoFileUrl` (HD when read, else SD), `transcript`, `postId`, `detailsStatus`, `pageName`, `pageType`, `pageUrl`, `pageFollowers`, `subjectKey`, `scrapedAt`.

Example video row (natgeo's newest video on 2026-10-24, with details; long links cut with "..."):

```json
{
  "type": "video",
  "videoId": "1390373583080292",
  "url": "https://www.facebook.com/natgeo/videos/1390373583080292/",
  "canonicalUrl": "https://www.facebook.com/natgeo/videos/dont-let-its-stubby-arms-fool-youkoleken-.../1390373583080292/",
  "videoType": "reel",
  "postId": "1696521885178568",
  "title": null,
  "savedTitle": "Don't let its stubby arms fool you - Koleken inakayali was an ambush predator from the abelisaurid family that once thrived in the Southern Hemisphere. Named by National Geographic Explorer Diego Pol and colleagues, Koleken inakayali's tiny forelimbs continue to puzzle experts. \n\nLearn more about Koleken inakayali: https://on.natgeo.com/I0YfR8",
  "text": "Don't let its stubby arms fool you - Koleken inakayali was an ambush predator from the abelisaurid family that once thrived in the Southern Hemisphere. Named by National Geographic Explorer Diego Pol and colleagues, Koleken inakayali's tiny forelimbs continue to puzzle experts. \n\nLearn more about Koleken inakayali: https://on.natgeo.com/I0YfR8",
  "hashtags": [],
  "mentions": [],
  "linksInText": ["https://on.natgeo.com/I0YfR8"],
  "phones": null,
  "emails": null,
  "publishedAt": "2026-10-20T22:00:00.000Z",
  "publishedAtUnix": 1792533600,
  "ageHours": 95,
  "playCount": 353819,
  "playCountLabel": "353K",
  "postPlayCount": 182881,
  "totalPosts": 1,
  "playsPerHour": 3724.41,
  "reactionCount": 3149,
  "reactionsByType": { "like": 2824, "love": 176, "haha": 73, "wow": 56, "care": 12, "angry": 1 },
  "commentCount": 184,
  "shareCount": 178,
  "shareCountIsExact": true,
  "engagementCount": 3511,
  "engagementRate": 0.009923,
  "durationSeconds": 54.976,
  "width": 1080,
  "height": 1920,
  "orientation": "portrait",
  "aspectRatio": 0.563,
  "isLive": false,
  "broadcastStatus": null,
  "thumbnailUrl": "https://scontent-sjc3-1.xx.fbcdn.net/v/t15.5256-10/859640554_1390373673080283_..._n.jpg?...",
  "videoFileUrl": "https://video-dfw5-2.xx.fbcdn.net/o1/v/t2/f2/m366/AQNNaDtGaoiV....mp4?...",
  "videoFileUrlSd": "https://video-sjc6-1.xx.fbcdn.net/o1/v/t2/f2/m412/AQNhTCux-FT9....mp4?...",
  "videoFileQuality": "hd",
  "videoFileFormat": "mp4",
  "videoFileUrlExpiresAt": "2026-10-29T05:43:29.000Z",
  "hasCaptions": false,
  "captionsUrl": null,
  "captionsLocale": null,
  "captionsLanguage": null,
  "captionsCreationMethod": null,
  "captionTracks": [],
  "transcript": null,
  "transcriptCues": null,
  "transcriptStatus": "not_requested",
  "musicTitle": null,
  "musicAudioType": null,
  "detailsStatus": "ok",
  "detailsSource": "reel_page",
  "pageName": "National Geographic",
  "pageType": "page",
  "pageId": "100044623170418",
  "pageClassicId": "23497828950",
  "pageUsername": "natgeo",
  "pageUrl": "https://www.facebook.com/natgeo",
  "pageVerified": true,
  "pageFollowers": 51431262,
  "position": 1,
  "pageInput": 1,
  "subjectKey": "pg:ae8fc17e7f4977c8",
  "scrapedAt": "2026-10-24T21:00:00.000Z"
}
```

#### Page rows

One per page, after the page's videos: `pageName`, `pageType` (page or person), `pageId`, `pageClassicId`, `pageUsername`, `pageUrl`, `pageVerified`, `pageFollowers`, `pageTalkingAbout`, `pageWereHere`, `pageAbout`, `pagePlace`, `pageProfilePictureUrl`. With **Page details**: `category`, `address`, `phone`, `email`, `websites`, `businessHours`, `priceRange`, `rating`, `recommendPercent`, `reviewCount`, and from the Meta Ad Library `isRunningAds`, `activeAdsCount`, `adLibraryUrl`, `pageCreatedAt`, `pageNameChanges`, `pageAdminCountries`. Page details are read only for a Page that delivered a video in the run; `pageDetailsStatus` says `ok`, `not_a_page` (a person's profile), `no_videos`, `not_read` or `not_requested`.

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

`commentId`, `videoId`, `postId`, `itemUrl`, `parentCommentId`, `threadCommentId`, `depth`, `text`, `language`, `createdAt`, `authorName`, `authorIsPage`, `authorId` and `authorUrl` (for a Page, or with personal data on), `authorIsItemOwner`, `authorBadges`, `reactionCount`, `reactions`, `replyCount`, `attachments`, `isEdited`, `mentions`, `phones` and `emails` (with personal data on), `commentUrl`, `pageName`, `subjectKey`, `scrapedAt`.

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

- A **coverage** row per value of the input: videos read, delivered and charged, the videos each filter left out, the newest and oldest video dates met, list calls, whether Facebook's end of the list was reached, and why the walk ended (`stopReason`: `end_of_videos`, `end_of_window`, `max_videos_per_page`, `no_videos`, `not_found`, `not_public`, `already_read`, `max_items`, `charge_limit`, `work_allowance` and others).
- **Status** rows: a page Facebook does not show, a profile that is not public, values that are not usable (a single video link among them), an add-on or option that could not be read, the sample. All free.
- A **summary** row last: the run's counters, the events charged, the requests made.

#### How fast

The form's own input (10 videos of natgeo with their details) ran in 8 to 71 seconds on Apify over 12 runs on 2026-10-24 and 2026-10-25 (10 of them under 20 seconds). Details are read 3 at a time, one extra call per video: 1,000 videos of natgeo took 42 to 44 minutes with their details and 5 minutes without them (two runs each, 256 MB); turn **Video details** off for the fastest list only rows. Facebook answers slower at some hours.

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

Pay per event: you pay for what is delivered, never for misses.

| Event | Free | Bronze | Silver | Gold |
|---|---|---|---|---|
| Video, per 1,000 videos | $4.98 | $4.98 | $4.90 | $4.22 |
| Page, per 1,000 pages | $1.55 | $1.40 | $1.28 | $1.10 |
| Comment (add-on), per 1,000 comments | $0.27 | $0.24 | $0.22 | $0.19 |
| Actor start, per run | $0.01 | $0.01 | $0.01 | $0.01 |

Platinum and Diamond plans pay the Gold price. The Actor start is charged once per run (per GB of memory: this Actor runs at 256 MB, so it pays one) and has no plan discount. The Store pricing card shows these same prices per 1,000 events: "$4.22 / 1,000" on the Video row means one video costs 0.422 cents at Gold (0.498 cents on the Free plan).

- **Video**: one video row delivered for the first time in the run, with its details when they are on (no extra charge for the details). A video met twice in a run is charged once.
- **Page**: one page row, after the page's videos, charged once when the page delivered at least one charged video; a page that delivers no charged video gets its row free.
- **Comment**: only with the Comments add-on on, per comment or reply row delivered.
- Free: videos a filter leaves out, repeats, pages that are missing, not public or without videos, refused calls, invalid input (the run pays only its start fee), transcripts, page details, the coverage, status and summary rows, and a video whose details Facebook did not give (delivered with `detailsStatus` `failed` or `other_post`).

Examples at the Gold price: 1,000 videos of one page with their details cost $0.01 + 1,000 x $0.00422 + $0.0011 = $4.2311, about $4.23. 100 videos of one page with 20 comments each cost $0.01 + 100 x $0.00422 + $0.0011 + 2,000 x $0.00019 = $0.8131, about $0.81.

#### The work allowance

Work that ends without a charged row (videos a filter leaves out, missing pages, refused calls) is bounded in every run by an allowance that grows with the events charged. A filter nothing passes therefore stops early with nothing charged but the start fee, with a coverage row saying `work_allowance`, instead of reading a page's whole history at no charge.

### Input

#### Pages

| Setting | What it does |
|---|---|
| **Facebook pages or profiles** (`pages`) | One per line: a page or profile link, a username or `@handle`, a numeric profile id or a page's numeric (delegate) id. Up to 500 values. Also read as `startUrls`, `profileUrls`, `facebook_urls`, `username`, `pageId`, `profileId`, `pageNames`, `pageIds`, `pageTargets`, `urls`, `delegatePageId` or `delegate_page_id`. |
| **Pages from a file or Google Sheet link** (`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; `startUrls` items in the `{ "requestsFromUrl": ... }` form are read the same way. |
| **Videos per page** (`maxVideosPerPage`) | Videos delivered per page, newest first (50 when empty, up to 100000). Videos a filter leaves out do not count. Also read as `resultsLimit`, `maxResultsPerPage`, `maxVideosPerTab` or `maxVideosPerProfile`. |
| **Videos in the whole run** (`maxItems`) | A bound across every page. Also read as `maxResults`, `maxVideos` or `maxTotalItems`. |

#### Filters

| Setting | What it does |
|---|---|
| **Published on or after** (`onlyVideosNewerThan`) | YYYY-MM-DD, an ISO time, `today`, `yesterday`, or `7 days`, `2 weeks`, `3 months`, `1 year` back from the run's start (UTC). The walk stops at the first older videos. Also read as `onlyNewerThan`, `publishedAfter`, `dateFrom` or `newerThan`. |
| **Published in the last N days** (`sinceDays`) | The same window as a number of days (0 is today). Send one of the two. |
| **Published on or before** (`onlyVideosOlderThan`) | An end date in the same forms (see "End date" below). Also read as `onlyOlderThan`, `publishedBefore`, `dateTo` or `olderThan`. |
| **Minimum plays** (`minPlays`), **Maximum plays** (`maxPlays`) | Bounds on the exact play count. `minPlays` is also read as `minViews`. |
| **Minimum length** (`minDurationSeconds`), **Maximum length** (`maxDurationSeconds`) | Bounds on the length in seconds. |
| **Minimum reactions** (`minReactions`) | Leaves out videos with fewer reactions. With **Video details** off, Facebook's list sometimes gives a total of 10,000 or more as 10,000, so a minimum above 10,000 is surest with the details on. |
| **Text contains** (`includeKeywords`), **Text does not contain** (`excludeKeywords`) | Whole words or phrases in the title, text or hashtags, case and accents ignored. `includeKeywords` is also read as `keywords` or `captionContains`. |
| **Reels or videos** (`videoTypes`) | `reel`, `video` or both (empty). Needs **Video details** on. Also read as `videoType`; `onlyReels: true` keeps reels. |
| **Only videos with captions** (`onlyWithCaptions`) | Keeps videos that carry Facebook captions. Needs **Video details** on. |

#### Details, add-ons and options

| Setting | What it does |
|---|---|
| **Video details** (`includeDetails`) | On by default, no extra charge: reel or video, comment and share counts, HD file, captions, music, exact time. Off: the list's facts only, faster. Also read as `includeEngagement`. |
| **Transcripts** (`includeTranscripts`) | Free: Facebook's own captions file as `transcript` and `transcriptCues`. Needs **Video details** on. Also read as `fetchTranscripts`. A video whose page lists only Facebook's automatic translations of its captions (no `captionsUrl`; 4 of 60 natgeo reels on 2026-10-24) gets `no_captions`: the translations stay in `captionTracks`. |
| **Comments (add-on)** (`includeComments`), **Comments per video** (`maxCommentsPerVideo`, 20 when empty, replies included; also read as `maxCommentsPerItem` or `comments_limit`), **Comment order** (`commentsOrder`: `oldest`, `newest`, `relevant`; also read as `comment_filter`), **Replies to comments** (`includeReplies`), **Replies per comment** (`maxRepliesPerComment`, 10 when empty) | The Comments add-on, charged per comment row. |
| **Page details** (`includePageDetails`) | Free: the About tab and Meta Ad Library facts on the page row, for a Page that delivered a video. |
| **Include personal data** (`includePersonalData`) | Off by default; see "Personal data". |

#### Run

| Setting | What it does |
|---|---|
| **Row format** (`outputFormat`) | `full` (every field) or `compact` (26 fields). |
| **Pages at once** (`maxConcurrency`) | 1 to 3 pages read at the same time (1 when empty). |
| **Pause between calls (ms)** (`requestDelayMs`) | 200 to 10000 ms between two calls of one page (300 when empty). |
| **Stop after (seconds)** (`maxRunSeconds`) | Ends the run after this many seconds with what was read. |
| **Proxy** (`proxyConfiguration`) | Apify Proxy by default: the Videos tab pages, details and comments through Apify's datacenter pool, the Videos tab's list through Apify residential exits in the country named (US when empty). Your own proxy links are possible; with no proxy Facebook gives the first 9 videos of each page only. Also read as `proxy`. |

Example input:

```json
{
  "pages": ["https://www.facebook.com/natgeo", "NASA"],
  "maxVideosPerPage": 200,
  "onlyVideosNewerThan": "3 months",
  "minPlays": 10000
}
```

#### Reels or videos

The Videos tab lists a page's reels and its other videos together, with nothing on the list that tells them apart, so **Reels or videos** is judged on each video's own page (the details read). The videos of the kind you did not ask for are read and left out free. On a page whose list is almost all of the other kind, that unpaid reading can end the run early on its work allowance, with nothing charged but the start fee, with a coverage row saying so: NASA's newest 49 videos, for example, held 48 reels and 1 other video.

#### End date

The Videos tab lists videos newest first, so with **Published on or before** the videos newer than the end date are read first (from the list only, no details) and left out free, within the run's unpaid work allowance. In a test run on 2026-10-24 a window from 2026-10-05 to 2026-10-12 on natgeo read 26 newer videos free and delivered the 11 inside the window. An end date far back in a busy page's list can end the run early with a free row saying so.

#### Personal data

Off by default (`includePersonalData`). With it off, a person's profile (a public figure's included) keeps its name, and its profile id, username, link and picture are empty; its video links are Facebook's watch links (`facebook.com/watch/?v=<id>`), which name no profile; mentioned people and commenters keep their names without ids or links; links in the text that reach a person's profile are left out. With it on, those fields are filled, and phone numbers and e-mail addresses written in the text get fields of their own. Texts are always delivered as Facebook serves them. You are responsible for using personal data lawfully, the GDPR included.

### What this Actor does NOT do

- No login, cookies or private content: it reads what a visitor who is not logged in sees. A private profile gets a free `not_public` row; so does a public page that Facebook answered with its login page on all 12 exits a run tried (rare; it happens at busy hours, and a new run may read it), and, now and then, a page that does not exist (Facebook often answers a missing page with its login page too). When Facebook answers a page's Videos tab with its login page 4 times, the Actor asks the page's main page and the tab in turn; a main page that answers starts the videos list from its newest video (the same rows; the summary counts these pages as `mainPageHeads`). That needs the list call's residential exits: with no proxy or your own proxies, only the tab is asked.
- No single video or reel by its link: it reads the Videos tab of a page or profile, and a link to one video gets a free status row. One video by its link is the job of our [Facebook Post Scraper: Reactions and Shares by URL](https://apify.com/automation_craft/facebook-post-scraper).
- No "only new videos since the last run" or monitor mode: every run reads its pages fresh, and monitor settings are refused (the run pays only its start fee). Schedule the Actor with Apify's scheduler and keep the videos you have by their `videoId`.
- No always on real time API (Standby mode): it runs as a normal Actor run, because a server kept waiting between calls would cost more than the videos it serves.
- No page photos or albums: those are the job of our [Facebook Photos Scraper: Albums, Dates, No Login](https://apify.com/automation_craft/facebook-photos-scraper).
- No search of Facebook by keyword: that is our [Facebook Video Search Scraper: Reels, No Login](https://apify.com/automation_craft/facebook-video-search-scraper).
- No stored copies of the video files: rows carry Facebook's own file links, which stop working at `videoFileUrlExpiresAt`.
- No share count for a video read from its own video page (a video of a post with several videos): `shareCount` is null there.
- At most 100,000 rows a run (videos, pages and comments together).

### API examples

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

```bash
curl -X POST "https://api.apify.com/v2/acts/automation_craft~facebook-videos-scraper/run-sync-get-dataset-items?token=<TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"pages": ["https://www.facebook.com/natgeo"], "maxVideosPerPage": 10, "includeDetails": true, "maxCommentsPerVideo": 20, "maxRepliesPerComment": 10, "proxyConfiguration": {"useApifyProxy": true}}'
```

Node.js:

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<TOKEN>' });
const run = await client.actor('automation_craft/facebook-videos-scraper').call({
    pages: ['https://www.facebook.com/natgeo'],
    maxVideosPerPage: 10,
    includeDetails: true,
    maxCommentsPerVideo: 20,
    maxRepliesPerComment: 10,
    proxyConfiguration: { useApifyProxy: true },
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const v of items.filter((x) => x.type === 'video')) console.log(v.publishedAt, v.playCount, v.url);
```

Python:

```python
from apify_client import ApifyClient
client = ApifyClient("<TOKEN>")
run = client.actor("automation_craft/facebook-videos-scraper").call(run_input={
    "pages": ["https://www.facebook.com/natgeo"],
    "maxVideosPerPage": 10,
    "includeDetails": True,
    "maxCommentsPerVideo": 20,
    "maxRepliesPerComment": 10,
    "proxyConfiguration": {"useApifyProxy": True},
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    if item["type"] == "video":
        print(item["publishedAt"], item["playCount"], item["videoType"], item["url"])
```

### FAQ

#### How do I download all the videos of a Facebook page?

Give the page and set **Videos per page** to 100000: the Videos tab is read newest first to Facebook's own end of the list, reels included. Each row carries the MP4 file links (`videoFileUrl` for HD with details on, `videoFileUrlSd` for SD), which you can download until `videoFileUrlExpiresAt`. A run stops at its timeout (2 hours by default): with **Video details** on that is about 2,700 videos (1,000 took 42 to 44 minutes), so for a longer list raise the run's timeout in its options, or turn the details off (1,000 videos in 5 minutes). A run that stops at its timeout says so in its coverage rows.

#### Can I see the views on someone else's Facebook video or reel?

Yes, for videos of public pages and profiles: each row carries `playCount`, Facebook's exact play count, next to `postPlayCount` (the plays of that post alone) and `playCountLabel`, the rounded count Facebook shows.

#### How do I get a Facebook page's video view counts without being its admin?

Give the page's link, username or id: the Actor reads its Videos tab as a visitor would, so no page access, insights or Graph API token is needed. Schedule the run to follow the counts over time and match rows by `videoId`.

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

Yes. The Actor reads what Facebook shows a visitor who is not logged in, through Apify's proxy, with no account, cookies or password of yours.

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

It needs only its own run's storage: the dataset it writes and the run's key-value store, where it keeps its run record so a restarted run does not charge a video twice. Limited permissions keep it from reading or changing anything else in your account.

### Changelog

- 0.1 (2026-10-25): first release.

### More data tools by Automation Craft

- [Facebook Reels Scraper: Views, Likes, No Login](https://apify.com/automation_craft/facebook-reels-scraper)
- [Facebook Photos Scraper: Albums, Dates, No Login](https://apify.com/automation_craft/facebook-photos-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 Posts Scraper - Page Posts, No Login](https://apify.com/automation_craft/facebook-posts-scraper)
- [Facebook Video Search Scraper: Reels, No Login](https://apify.com/automation_craft/facebook-video-search-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)

# Changelog

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

# Actor input Schema

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

One per line: a public page or profile (facebook.com/natgeo, facebook.com/natgeo/videos/, facebook.com/profile.php?id=100044623170418, facebook.com/people/Name/100044623170418/, a username such as natgeo or @natgeo, a numeric profile id or a page's numeric (delegate) id such as 23497828950). Its Videos tab is read: every video and reel the page posted, newest first. A link to one single video or reel is not read (a free status row says so). Up to 500 values. Also read as startUrls, profileUrls, facebook_urls, username, pageId, profileId, pageNames, pageIds, pageTargets, urls, delegatePageId or delegate_page_id.

## `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 a Facebook page or profile is read as one more value of "pages". startUrls items in Apify's { "requestsFromUrl": ... } form are read the same way.

## `maxVideosPerPage` (type: `integer`):

How many videos to deliver for each page, newest first (50 when empty, up to 100000: a page's whole Videos tab). Videos left out by a filter do not count. Also read as resultsLimit, maxResultsPerPage, maxVideosPerTab or maxVideosPerProfile.

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

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

## `onlyVideosNewerThan` (type: `string`):

Only videos 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. The Videos tab lists videos newest first, so the walk stops at the first older ones. Also read as onlyNewerThan, publishedAfter, dateFrom or newerThan.

## `sinceDays` (type: `integer`):

The same window as "Published on or after", given as a number of days back from the run's start (0 is today). Send one of the two.

## `onlyVideosOlderThan` (type: `string`):

Only videos published on or before this day (UTC), in the same forms. The newer videos before it are read free (they are not charged) within the run's unpaid work allowance, so an end date far back in a busy page's list can end the run early with a free row saying so. Also read as onlyOlderThan, publishedBefore, dateTo or olderThan.

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

Leave out videos with fewer plays than this (Facebook's exact play count). Videos left out are free. Also read as minViews.

## `maxPlays` (type: `integer`):

Leave out videos with more plays than this. Videos left out are free.

## `minDurationSeconds` (type: `integer`):

Leave out videos shorter than this many seconds. Videos left out are free.

## `maxDurationSeconds` (type: `integer`):

Leave out videos longer than this many seconds. Videos left out are free.

## `minReactions` (type: `integer`):

Leave out videos with fewer reactions than this. Videos left out are free. With Video details off, Facebook's list sometimes gives 10,000 or more as 10,000: a minimum above 10,000 is surest with the details on.

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

Only videos whose title, text or hashtags contain at least one of these words or phrases, as whole words, case and accents ignored. Videos left out are free. Also read as keywords or captionContains.

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

Leave out videos whose title, text or hashtags contain any of these words or phrases (the same matching). Videos left out are free.

## `videoTypes` (type: `array`):

Keep only reels, or only videos that are not reels (empty: both; the Videos tab lists both). Judged on Facebook's own link of each video, which its details give, so it needs "Video details" on. Videos left out are free. Also read as videoType; onlyReels (true) keeps reels.

## `onlyWithCaptions` (type: `boolean`):

Keep only videos that carry Facebook captions (subtitles), judged on their details (needs "Video details" on). Videos left out are free.

## `includeDetails` (type: `boolean`):

On (the default): each video's own page is read and delivered at no extra charge: reel or video, comment count, share count, the HD video file, Facebook's captions (link, language, every track), the music of a reel, the exact time. Off: the rows carry what the Videos tab list gives (plays, reactions, time, text, size, SD file, thumbnail) and the run is faster. Also read as includeEngagement.

## `includeTranscripts` (type: `boolean`):

Read Facebook's own captions file of each delivered video that has one and deliver it as text and timed cues (transcript, transcriptCues). No extra charge; needs "Video details" on. A video without captions gets transcriptStatus no_captions. Also read as fetchTranscripts.

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

Deliver the comments of each delivered video as rows of their own, up to the number below, in the order chosen below. Charged as the Comment event per comment row. Commenters' names are delivered; their profile ids and links only with personal data on.

## `maxCommentsPerVideo` (type: `integer`):

With comments on: how many comment rows (replies included) to deliver for each video (20 when empty). Also read as maxCommentsPerItem or comments_limit.

## `commentsOrder` (type: `string`):

With comments on: oldest first (the default), newest first, or Facebook's most relevant first. Also read as comment_filter (most_relevant, newest, all_comments).

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

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

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

With replies on: how many replies to read under each comment (10 when empty).

## `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). No extra charge; read only for a page that delivered a video.

## `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, and its video links are Facebook's watch links (facebook.com/watch/?v=<id>), which name no profile; mentions and commenters that are people keep their names without ids or links; links in the text that reach a person's profile are left out. On: they are delivered, and phone numbers and e-mail addresses written in the text get fields of their own. You are responsible for using personal data lawfully, the GDPR included. Texts are always delivered as Facebook serves them.

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

full: every field of a video. compact: 26 fields most buyers sort, chart and download by (ids, link, kind, title, text, time, length, plays, counts, engagement rate, thumbnail, video file, transcript, 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 (200 to 10000; 300 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 Proxy by default: the Videos tab pages, each video's details and the comments go through Apify's datacenter pool, and the Videos tab's list through Apify residential exits (the only exits Facebook answers it on), in the country named here (US when empty); naming the RESIDENTIAL group changes nothing else. Your own proxy links are possible (every call through them), and no proxy uses the run container's own address (Facebook then gives the first 9 videos of each page only).

## Actor input object example

```json
{
  "pages": [
    "https://www.facebook.com/natgeo"
  ],
  "maxVideosPerPage": 10,
  "includeDetails": true,
  "maxCommentsPerVideo": 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"
    ],
    "maxVideosPerPage": 10,
    "includeDetails": true,
    "maxCommentsPerVideo": 20,
    "maxRepliesPerComment": 10,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation_craft/facebook-videos-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"],
    "maxVideosPerPage": 10,
    "includeDetails": True,
    "maxCommentsPerVideo": 20,
    "maxRepliesPerComment": 10,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("automation_craft/facebook-videos-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"
  ],
  "maxVideosPerPage": 10,
  "includeDetails": true,
  "maxCommentsPerVideo": 20,
  "maxRepliesPerComment": 10,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call automation_craft/facebook-videos-scraper --silent --output-dataset

```

## MCP server setup

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