# Facebook Photos Scraper (`khadinakbar/facebook-photos-scraper`) Actor

Collect public Facebook Page photo galleries with pagination. Export photo IDs, image URLs, thumbnails, alt text, dimensions and Facebook links. No Facebook login.

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

## Pricing

from $1.00 / 1,000 photo 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 Photos Scraper

Collect photo galleries from public Facebook Pages into one structured dataset. Supply Page URLs or usernames and receive a row for each unique photo, with its image URL, Facebook permalink, thumbnail, dimensions and available accessibility text.

This Actor is a private development candidate. Public release and human source/data-use review remain pending. The examples below describe the implemented input and output contract; the sample output is illustrative.

### Input

```json
{
    "startUrls": ["https://www.facebook.com/NASA"],
    "maxPhotos": 5,
    "maxPhotosPerPage": 5,
    "maxRequests": 2,
    "maxProviderCostUsd": 0.01
}
```

| Field                | Default  | Behavior                                                                                       |
| -------------------- | -------- | ---------------------------------------------------------------------------------------------- |
| `startUrls`          | Required | 1–20 public Page roots, `/photos` URLs, or usernames.                                          |
| `maxPhotos`          | 100      | Global maximum of unique saved photos, from 1 to 10,000.                                       |
| `maxPhotosPerPage`   | 50       | Maximum saved photos per Facebook Page, from 1 to 10,000.                                      |
| `maxRequests`        | 30       | Global maximum upstream requests, from 1 to 100. Empty and failed attempts count.              |
| `maxProviderCostUsd` | 0.10     | Upstream cost reservation cap, from $0.001 to $0.50. This excludes Apify usage and event fees. |

Both photo limits apply. The request and provider-cost limits can stop a run before it reaches the requested number of photos. A Page with fewer accessible photos returns fewer rows. Repeated inputs are collapsed and photo IDs are deduplicated across the run. Requests are serial and have no automatic retries.

### Output

```json
{
    "photoId": "1001",
    "photoUrl": "https://www.facebook.com/photo.php?fbid=1001",
    "sourceUrl": "https://www.facebook.com/examplepage",
    "imageUrl": "https://scontent.xx.fbcdn.net/illustrative-image.jpg",
    "thumbnailUrl": null,
    "width": 1080,
    "height": 720,
    "altText": "May be an image of a mountain",
    "provider": "scrapecreators",
    "scrapedAt": "2026-10-26T00:00:00.000Z"
}
```

`imageUrl` is the largest viewer image supplied by the source; original upload resolution is not guaranteed. Signed CDN URLs may expire. Missing optional fields are `null`. `altText` is the accessibility caption supplied by Facebook. `scrapedAt` is the collection time.

Use the Dataset tab to export JSON, CSV or Excel. The output schema exposes the dataset, `OUTPUT` and `RUN_SUMMARY` for API and agent consumers. After deployment, Apify's hosted MCP can run the batch Actor with the same input; a hosted MCP call has not yet been tested.

### Scope and limits

The Actor collects accessible public Page galleries without Facebook credentials. It does not accept cookies or access private/friends-only content. Personal-profile gallery coverage is unverified; a numeric `profile.php?id=...` Page URL is accepted but does not guarantee personal-profile access.

Individual photo permalinks, album crawling, tagged-photo selection, videos, dates, post captions, reactions and image-file downloads are outside this version's contract. For individual media URLs, use [Facebook Media Downloader](https://apify.com/khadinakbar/facebook-media-downloader). For Page metadata, use [Facebook Page Scraper](https://apify.com/khadinakbar/facebook-page-scraper).

The Actor uses an owner-managed upstream key. Users do not enter provider secrets. Provider outages, login walls and access restrictions can reduce coverage. No secondary provider with verified equivalent gallery coverage is configured.

### Charges and stop behavior

Pay per event charges are **$0.005 per startup**, **$0.02 per gallery request**, and **$0.001 per saved photo** ($1.00 per 1,000 photos, plus request fees, startup and platform usage). Each pagination request is a separate gallery request. For example, one request saving 8 photos costs $0.033 in events; two requests saving one photo each cost $0.047 in events. These rates apply equally across paid tiers.

The platform startup event can apply even to invalid, empty or failed runs (one event per GB of Actor memory, minimum one). The gallery request fee is accepted before an upstream attempt and applies to empty responses and failed attempts as well as successful pages. An interruption after an accepted request fee can require owner reconciliation before dispatch; it is never blindly replayed. A saved photo incurs one result event; duplicates and rejected records incur no photo fee. Before dispatch, the run reserves the gallery request fee plus room for at least one saved photo within the event limit. The event limit excludes additional platform usage. Provider spending is separately capped by the input limits.

The provider reservation uses the verified published baseline of $0.00188 per request. It is a conservative estimate, not a provider invoice. Tariff drift or a provider reporting more than the expected one credit stops work; a changed tariff can already have charged for that request. Free/non-paying traffic and failed requests can still create owner costs.

`OUTPUT.outcome` and `RUN_SUMMARY.outcome` explain the result:

| Outcome           | Meaning                                                                                                                                      |
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `COMPLETE`        | The available gallery or requested photo cap was delivered.                                                                                  |
| `PARTIAL`         | Useful output was retained with failures, invalid rows, cancellation or a request/spending/deadline stop; caps can also stop before any row. |
| `VALID_EMPTY`     | The provider successfully returned an empty gallery.                                                                                         |
| `INVALID_INPUT`   | Correct the documented input fields.                                                                                                         |
| `UPSTREAM_FAILED` | No useful photos were available because extraction failed. The cloud run fails.                                                              |
| `CONFIG_ERROR`    | Required owner configuration or reconciliation is missing. With no confirmed output, the cloud run fails.                                    |

Pagination, duplicate IDs, reservations and pending effects are checkpointed within the same run. Confirmed writes are skipped on resurrection. An interrupted request or dataset/charge operation with an uncertain result blocks further billable work until the owner reconciles it. This is not an exactly-once or automatic recovery guarantee. Export the dataset directly if a saved row has an unresolved charge receipt.

### Responsible use

Use only data you are authorized to collect and use. Public accessibility does not grant image reuse rights. This Actor is independently developed and is not affiliated with Meta or Facebook. Store publication and source/data-use review remain separate from technical testing.

# Actor input Schema

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

1–20 public Page roots, /photos URLs, or usernames. Duplicates are collapsed. No cookies or login.

## `maxPhotos` (type: `integer`):

Global cap on unique saved photos. Stops before extra result charges. Fewer photos may be available.

## `maxPhotosPerPage` (type: `integer`):

Unique saved-photo cap per Facebook Page, independent of the provider pagination batch size.

## `maxRequests` (type: `integer`):

Global hard cap on upstream attempts, including empty and failed requests. Each attempt costs $0.02 in events. No automatic retries. Can limit output below maxPhotos.

## `maxProviderCostUsd` (type: `number`):

Stops before dispatch at the verified $0.00188/request reservation. Bounds estimated upstream spend only; excludes Apify usage and event charges. A tariff change stops extraction.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.facebook.com/NASA"
  ],
  "maxPhotos": 100,
  "maxPhotosPerPage": 50,
  "maxRequests": 30,
  "maxProviderCostUsd": 0.1
}
```

# Actor output Schema

## `photos` (type: `string`):

One validated photo per row.

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

Compact terminal outcome and accepted event counts.

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

Target coverage, request reservations, invalid rows, stop reason and safe diagnostics.

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

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

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

```

## MCP server setup

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