# Facebook Page Video Downloader (`khadinakbar/facebook-page-video-downloader`) Actor

Discover videos from public Facebook Page Videos and Reels tabs, paginate and deduplicate results, and save bounded MP4 files with source metadata and download status.

- **URL**: https://apify.com/khadinakbar/facebook-page-video-downloader.md
- **Developed by:** [Khadin Akbar](https://apify.com/khadinakbar) (community)
- **Categories:** Social media, Videos, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 1,000 video result saveds

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

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

## What's an Apify Actor?

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 Page Video Downloader

Find videos from public Facebook Page **Videos and Reels tabs**, then save available MP4 copies with captions, source links and download status. Start with a Page URL; get one Dataset row per unique video and a saved-file URL when downloading succeeds. Native discovery uses Apify US residential proxy and has **no scan-event charge**. Video results and automatic startup events are billed, with Apify platform usage additional.

### What it does

- Discover Page videos without collecting individual post links first.
- Paginate through the Videos listing, Reels grid, or both; combine up to ten Pages and deduplicate by video ID.
- Return available progressive SD/HD MP4 addresses, captions, publish times and public counts.
- Save complete MP4 files within per-file and combined saved-byte limits.

### Example workflow

Use this Actor when you need an authorized Page-video archive, an editorial clip review, or a Page-level video analysis workflow. For example, an editor can request twelve recent public videos from a publisher, save small SD copies, then export source links and download outcomes for review.

Avoid this Actor when you need private content, individual-video URL downloads, complete historical coverage or permanent file hosting.

Accepts Page home URLs and Videos/Reels tab URLs. It does not accept individual video URLs, groups or private content. It uses content Facebook exposes without a login, with an anonymous source session kept only in process memory. A requested maximum is a cap, not a guarantee that every historical video is accessible.

### Quick start

```json
{
  "pageUrls": ["https://www.facebook.com/NASA/"],
  "mode": "feed",
  "maxVideos": 3,
  "maxScans": 2,
  "downloadMp4": true,
  "quality": "sd",
  "maxFileSizeMB": 25,
  "maxTotalDownloadMB": 100
}
```

The stable API value `feed` now reads the Page's public **Videos tab**. Choose `reels` for the Reels grid or `both` for both sources. Set `downloadMp4` to `false` to export media links without saving files.

### Input settings

| Setting | Default | Effect |
|---|---|---|
| `pageUrls` | Required | 1–10 public Page URLs; duplicate URLs are combined |
| `mode` | `feed` | Videos tab, Reels tab, or both |
| `maxVideos` | 10 | Unique result cap across all Pages; maximum 100 |
| `maxScans` | 2 | Discovery-page cap across all sources; maximum 50 |
| `downloadMp4` | `true` | Save available complete MP4 copies |
| `quality` | `sd` | Prefer SD, or `hd` when exposed; use available quality if the preference is absent |
| `maxFileSizeMB` | 25 | Single saved-file limit in MiB; maximum 100 |
| `maxTotalDownloadMB` | 100 | Combined saved-file limit in MiB; maximum 500 |

One MiB is 1,048,576 bytes. Transfer consumed before an oversized or interrupted response stops can still incur platform usage. The saved-byte cap does not cap every attempted network byte. Progressive MP4 files are supported; separate audio/video streams and manifests are not joined.

### Output fields

| Fields | Meaning |
|---|---|
| `videoId`, `pageUrl`, `videoUrl`, `mediaType` | Stable identity, input Page, source permalink and video/Reel type |
| `downloadUrl`, `sdDownloadUrl`, `hdDownloadUrl` | Exposed MP4 addresses; signed source links can expire |
| `caption`, `authorName`, `postedAt` | Public metadata where exposed; missing values remain null |
| `durationSeconds`, `reactionCount`, `viewCount`, `viewCountSource` | Media/count values with source; Reels badge counts may be rounded |
| `storedMp4Url`, `storedBytes`, `downloadStatus` | Saved-file location and outcome; a result can remain useful without a saved copy |
| `discoveryMode`, `provider`, `scrapedAt` | Source selection, native route and retrieval timestamp |

A shortened source-record example:

```json
{
  "videoId": "1803909017420449",
  "pageUrl": "https://www.facebook.com/NASA/",
  "videoUrl": "https://www.facebook.com/watch/?v=1803909017420449",
  "mediaType": "video",
  "provider": "native-facebook",
  "storedMp4Url": null,
  "storedBytes": 0,
  "downloadStatus": "not_requested"
}
```

`OUTPUT` and `RUN_SUMMARY` explain the outcome, delivered videos, saved files, requests, accepted named events, effective event prices and warnings. An unavailable source is classified as `UPSTREAM_FAILED` when no useful row was saved. A completed source with genuinely no matches is `VALID_EMPTY`. A spending limit that prevents any result returns actionable limit diagnostics, rather than a useful partial-result label.

### Pricing and spending limits

Check the [live Pricing tab](https://apify.com/khadinakbar/facebook-page-video-downloader/pricing) for effective fees. Pay per event applies: current native builds charge startup plus saved video results, **without discovery-page events**:

| Buyer tier | Per video | 10 videos plus one start, before usage |
|---|---:|---:|
| Free, Bronze, Silver, Gold, Platinum and Diamond | $0.0005 | $0.0051 |

Startup is **$0.0001 per automatic memory-scaled unit**, minimum one. Restarts/resurrections can add startup units. Empty or unavailable-source runs can still incur startup and platform usage. A video-result event includes a bounded file attempt and is charged for the saved video metadata/link record even if the MP4 is oversized or unavailable. There is no separate saved-file event.

For example, 10 rows of saved video metadata at the flat rate cost **$0.0051 in Actor events**, plus your platform compute, proxy, transfer and storage usage.

Total cost is **startup units × startup price + saved video rows × your result price + platform usage**. Native discovery has no paid external lookup; Apify residential proxy bandwidth is additional platform usage at the caller’s applicable residential rate and requires access to Apify Proxy. The Pricing tab retains a legacy discovery event for older provider-backed builds; current native builds never charge it.

Set a maximum event charge when starting a run and choose video/scan/byte limits. An event cap does not cap all platform transfer, compute or storage costs. Retained files and later reads also consume usage. Files follow run-storage retention; this is not permanent hosting.

### API example

```bash
curl --request POST \
  'https://api.apify.com/v2/acts/khadinakbar~facebook-page-video-downloader/runs' \
  --header "Authorization: Bearer $APIFY_TOKEN" \
  --header 'Content-Type: application/json' \
  --data '{"pageUrls":["https://www.facebook.com/NASA/"],"maxVideos":1,"maxScans":1,"downloadMp4":true}'
```

Poll the returned run ID. After completion, export `/v2/datasets/<defaultDatasetId>/items`, read `/v2/key-value-stores/<defaultKeyValueStoreId>/records/RUN_SUMMARY`, and open each saved row's `storedMp4Url`. Keep credentials in the authorization header.

### AI agent prompt

> Find up to three public videos from this Facebook Page. Scan at most two discovery pages, save SD MP4 copies no larger than 25 MiB each, and return source links, saved-file URLs and download warnings.

### Best results and recovery

- Start with a small request for a Page visible while logged out.
- Increase `maxScans` for more pages; check the summary for caps and source failures.
- Prefer SD when file size matters. HD availability and historical coverage depend on the source.
- Treat direct media links as temporary. Download a saved copy before run storage expires.
- Interruption leaves a record of pending effects. Inspect `STATE` before resuming ambiguous work; the Actor refuses to replay uncertain persistence or charges automatically.

### Verification and freshness

Checked 2026-10-26 using public Page samples, parser fixtures and saved SD/HD MP4 decoding. Checks cover source identity, distinct video IDs, metadata, cursor parsing, size limits and named-event accounting. A bounded sample does not establish population-wide reliability; availability can change with Facebook responses.

### Builder's note

Engineering evidence is dated October 26, 2026. Each release is checked against its immutable cloud build with saved Dataset rows, named-event counts and run summaries; this describes a bounded QA sample. In my testing, the native route returned distinct videos on successive pages. I designed it to read public listings and pagination data exposed by the Page. That removes the external lookup bill and finds Videos-tab content directly, rather than scanning photo/text posts for videos. Facebook can change its response shape or restrict a Page; the summary preserves that unavailability instead of inventing an empty success. Acceptance results describe the tested sample; population-wide reliability remains unmeasured.

### Source and responsible use

This independent Actor is not affiliated with or endorsed by Meta or Facebook. Use it for content you own or have authority to collect and retain. Public accessibility does not grant copyright or other reuse rights. Respect applicable terms, privacy requirements and retention obligations. The Actor does not use login credentials or bypass authentication.

# Changelog

This Actor's version history is a separate document: https://apify.com/khadinakbar/facebook-page-video-downloader/changelog.md

# Actor input Schema

## `pageUrls` (type: `array`):

Enter 1–10 HTTPS public Facebook Page home URLs or Videos/Reels tab URLs. The Actor reads the public Videos listing or Reels grid without a login. Example: https://www.facebook.com/NASA/. Use Facebook Video Downloader when you already have individual video URLs.

## `mode` (type: `string`):

Read the public Videos listing, Reels grid, or both. The stable API value feed selects the Videos listing. Discovery rotates through input Page/source pairs before fetching more pages. Only videos owned by the resolved Page enter the Dataset.

## `maxVideos` (type: `integer`):

Stop after this many unique video records across all input Pages. Duplicate video IDs are returned once. This caps video-result events. The scan cap can stop discovery earlier.

## `maxScans` (type: `integer`):

Cap logical discovery pages across Pages and sources, including unsuccessful attempts. Native discovery has no scan-event fee. A discovery page can need a bounded redirect or a public query request. Increase this limit to paginate further, subject to the run deadline.

## `downloadMp4` (type: `boolean`):

Save complete MP4 copies to this run’s key-value store. Direct links and metadata are returned when files are unavailable or exceed the limits. Download status explains skipped files. Platform transfer and storage usage are additional.

## `quality` (type: `string`):

Choose SD for smaller files or HD when exposed. The Actor uses the available quality if the preferred URL is absent. HD is not guaranteed. Large files can be skipped under your byte limits.

## `maxFileSizeMB` (type: `integer`):

Limit each stored MP4 by actual bytes read, even without a size header. Oversized files are skipped with a reason. Direct links remain in the Dataset. The unit is 1,048,576 bytes.

## `maxTotalDownloadMB` (type: `integer`):

Cap combined saved MP4 bytes across the run. Further files are skipped after the limit. Video link results continue to your maxVideos cap. The unit is 1,048,576 bytes.

## Actor input object example

```json
{
  "pageUrls": [
    "https://www.facebook.com/NASA/"
  ],
  "mode": "feed",
  "maxVideos": 10,
  "maxScans": 2,
  "downloadMp4": true,
  "quality": "sd",
  "maxFileSizeMB": 25,
  "maxTotalDownloadMB": 100
}
```

# Actor output Schema

## `videos` (type: `string`):

Video records

## `output` (type: `string`):

Output summary

## `runSummary` (type: `string`):

Discovery and billing report

# 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 = {
    "pageUrls": [
        "https://www.facebook.com/NASA/"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("khadinakbar/facebook-page-video-downloader").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 = { "pageUrls": ["https://www.facebook.com/NASA/"] }

# Run the Actor and wait for it to finish
run = client.actor("khadinakbar/facebook-page-video-downloader").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 '{
  "pageUrls": [
    "https://www.facebook.com/NASA/"
  ]
}' |
apify call khadinakbar/facebook-page-video-downloader --silent --output-dataset

```

## MCP server setup

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

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/n7D4hb4VTEOc289n3/builds/rgUiGzBTqgWJwIL43/openapi.json
