# Facebook Reels & Video Metadata / Transcript Extractor (`fanndev/facebook-reels-video-extractor`) Actor

Extract Facebook reels and videos with play counts, engagement, duration, audio track, direct MP4 URLs and spoken-word transcripts. Transcripts are real: Facebook publishes a SubRip caption file for many reels and this actor downloads and parses it. Read a page's whole tab, or pass individual URLs.

- **URL**: https://apify.com/fanndev/facebook-reels-video-extractor.md
- **Developed by:** [Faisal Ahdan naufal](https://apify.com/fanndev) (community)
- **Security:** Limited permissions
- **Stats:** 2 total users, 2 monthly users, 90.2% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 results

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 & Video Metadata / Transcript Extractor

Extract Facebook reels and videos with their play counts, engagement, duration,
audio track, **direct MP4 URLs** and **spoken-word transcripts**.

Read a page's whole reels or videos tab, or pass individual reel / watch / video
URLs. No login, no cookies to paste, no proxy required.

### The transcripts are real

Facebook publishes a SubRip caption file for many reels. This actor finds the
`.srt` link in the payload, downloads it, and parses it into plain text plus
timed cues:

> `You think you know Domino's but when it's mission critical, it's not the pizza
> we send in. Operation Loaded Chicken is a go. Crispy Bacon and Tomato, team
> leader…`

A live check on one page's reels tab found captions on **4 of 10** reels and
transcribed them. Videos with no captions get `transcript: null` — this actor
does not run speech recognition of its own and does not pretend to.

### What you get

| Field | Example |
| --- | --- |
| `videoId`, `permalinkUrl`, `isReel` | `637979908801309`, `facebook.com/reel/…`, `true` |
| `pageName`, `pageId` | `Domino's Pizza` |
| `caption`, `title` | the post text and video title |
| `playCount`, `playCountLabel` | `292000`, `292K` |
| `reactionCount`, `commentCount`, `shareCount` | |
| `engagementTotal`, `engagementRatePercent` | `442`, `0.151` |
| `lengthSeconds`, `width`, `height` | `39.25`, `1080`, `1920` |
| `trackTitle`, `isOriginalAudio` | audio track behind the reel |
| `videoHdUrl`, `videoSdUrl`, `thumbnailUrl` | direct downloads |
| `captionsUrl`, `captionLocales`, `transcript` | |
| `createdAtIso` | `2025-01-27T…` |

### Two tabs, two kinds of play count

| Tab | Play count |
| --- | --- |
| `/reels/` | abbreviated — Facebook publishes `"292K"`, parsed to `292000` |
| `/videos` | exact integers — `270777`, `390753`, `292030` |

Both numbers are given: `playCount` (parsed) and `playCountLabel` (exactly what
Facebook rendered), so an approximation is never mistaken for an exact figure.
Read both tabs to get the widest coverage.

### Input example

```json
{
  "pages": ["dominos"],
  "tabs": ["reels", "videos"],
  "maxVideosPerTab": 30,
  "fetchTranscripts": true,
  "onlyWithCaptions": true,
  "exportFormats": ["csv"]
}
```

Or for specific videos:

```json
{
  "videoUrls": [
    "https://www.facebook.com/reel/637979908801309",
    "https://www.facebook.com/watch/?v=10153231379946729",
    "1053159700187202"
  ]
}
```

The watch URL is used as the resolver, so you never need to know whether an id
is a reel or a page video.

### Running it on Apify: use a residential proxy for pagination

Facebook serves the **rendered first page** to any IP, including Apify's. But the
**first pagination request from a datacenter IP** comes back with
`Rate limit exceeded`, so a platform run with no proxy stops at the videos Facebook renders in the tab.

The rate limit is on Facebook's GraphQL endpoint, which every actor in this
family uses for its second page onwards. It was measured on 2026-09-20 with the
Ad Library actor, three runs of the same search within a minute:

| Run | Result |
| --- | --- |
| Apify, no proxy | 30 results, 1 page — log: `Rate limit exceeded` |
| Apify, `RESIDENTIAL` proxy | 60 results, 4 pages |
| Local machine, no proxy | 70 results, 5 pages |

So: switch the Apify proxy on and pick the **RESIDENTIAL** group whenever you
want more than the first page. Running from your own machine needs no proxy at
all.

The actor logs a warning naming the rate limit when it hits one, so a short run
is never silently mistaken for a short result set.

### Notes

- `engagementRatePercent` is engagement over plays, and is **null** when the play
  count is unknown or zero. A fabricated denominator would turn an unknown into a
  confident wrong number.
- `videoHdUrl`, `videoSdUrl`, `thumbnailUrl` and `captionsUrl` are signed CDN
  links and expire. Download what you need during or shortly after the run.
- Reels tabs are large — about 13 MB each — which is why `maxVideosPerTab`
  defaults to 20.
- A page with no reels tab, or a video restricted to signed-in viewers, produces
  an `ERROR` row saying so rather than a silent empty result.

# Actor input Schema

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

Vanity slugs ('dominos') or page URLs. Their reels and/or videos tabs are read in full.

## `videoUrls` (type: `array`):

Individual videos: a reel URL (facebook.com/reel/<id>), a watch URL (facebook.com/watch/?v=<id>), a page video URL, or a bare numeric id. The watch URL is used as the resolver, so you do not need to know whether an id is a reel or a page video.

## `startUrls` (type: `array`):

Page or video URLs, for pasting a list straight out of another actor's dataset.

## `tabs` (type: `array`):

The reels tab carries abbreviated play counts ('292K'); the videos tab carries exact integers. Reading both gives you the widest coverage.

## `maxVideosPerTab` (type: `integer`):

A reels tab renders about ten reels and weighs ~13 MB, so keep this modest while you are tuning a run.

## `fetchTranscripts` (type: `boolean`):

When Facebook has captioned a video it publishes a .srt file; this downloads and parses it into plain text plus timed cues. One small extra request per captioned video. Videos with no captions get transcript: null rather than an invented one.

## `onlyReels` (type: `boolean`):

Drop ordinary page videos and keep short-form reels.

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

Keep only videos Facebook has captioned - the ones a transcript can be produced for.

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

Videos whose play count could not be read are dropped, since an unknown count cannot be shown to clear the bar.

## `captionContains` (type: `string`):

Case-insensitive substring match across the post caption, the video title and the transcript.

## `emitSummary` (type: `boolean`):

Append one RUN_SUMMARY record: videos collected, how many are reels, how many carry captions, median plays and median engagement rate.

## `exportFormats` (type: `array`):

Also write the results to the key-value store in these formats. The dataset is always produced regardless.

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

Recommended on the Apify platform if you want more than the videos Facebook renders in the tab. Facebook serves the rendered first page fine from any IP, but on Apify's datacenter IPs it answers the very first pagination request with "Rate limit exceeded" - measured 2026-09-20. Switching the Apify proxy on with the RESIDENTIAL group restored full pagination in the same test (60 ads over 4 pages against 30). Running from your own machine, no proxy is needed at all. The actor logs a warning naming this when it happens, so a short run is never silently mistaken for a short result set.

## Actor input object example

```json
{
  "pages": [
    "dominos"
  ],
  "tabs": [
    "reels",
    "videos"
  ],
  "maxVideosPerTab": 20,
  "fetchTranscripts": true,
  "onlyReels": false,
  "onlyWithCaptions": false,
  "emitSummary": true,
  "exportFormats": [],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

One row per reel or video, plus the run summary and error rows.

# 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": [
        "dominos"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("fanndev/facebook-reels-video-extractor").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": ["dominos"] }

# Run the Actor and wait for it to finish
run = client.actor("fanndev/facebook-reels-video-extractor").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": [
    "dominos"
  ]
}' |
apify call fanndev/facebook-reels-video-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,fanndev/facebook-reels-video-extractor"
        }
    }
}
```

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/aiyI6k7un8MOOyYha/builds/1kaWnwibjXrBTHQQX/openapi.json
