# Facebook Page Contact Info Scraper (`dami_studio/facebook-page-contact-info-scraper`) Actor

Every Facebook Page has a contact block its owner filled in on purpose, and that is what comes back: website, email, phone, street address, opening status, linked accounts, verified badge and follower counts. No login needed from you. $1.30 per 1,000 Pages, 200 per run.

- **URL**: https://apify.com/dami\_studio/facebook-page-contact-info-scraper.md
- **Developed by:** [Dami's Studio](https://apify.com/dami_studio) (community)
- **Categories:** Social media, Lead generation
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.30 / 1,000 facebook pages

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Facebook Page Contact Info Scraper

Reads the About tab of a Facebook Page and hands back the contact block published there: website, email, phone, street address, category, opening status, price range, linked Instagram or X accounts, the recommendation summary, follower and like counts, and whether the Page carries a verified badge.

Nothing is logged in. No account of yours, and none of ours behind the scenes either. What you get is the panel any signed-out visitor sees.

It takes full URLs, About-tab URLs, bare handles, `@handles`, numeric Page ids and `profile.php?id=` links, so you can throw a messy column from a spreadsheet at it without cleaning it up first.

### What you get

One row per Page. A real row from `https://www.facebook.com/katzsdeli`:

```json
{
  "inputUrl": "https://www.facebook.com/katzsdeli",
  "handle": "katzsdeli",
  "pageName": "Katz's Delicatessen",
  "pageUrl": "https://www.facebook.com/katzsdeli/",
  "pageId": "100064806517961",
  "isVerified": false,
  "category": "Deli",
  "categories": ["Deli"],
  "website": "http://katzsdelicatessen.com/",
  "websites": ["http://katzsdelicatessen.com/"],
  "email": "cs@katzsdelicatessen.com",
  "emails": ["cs@katzsdelicatessen.com"],
  "phone": "(212) 254-2246",
  "phones": ["(212) 254-2246"],
  "address": "205 E Houston St, New York, NY, United States, 10002",
  "socialLinks": [
    { "network": "Instagram", "handle": "katzsdeli", "url": "https://www.instagram.com/katzsdeli" }
  ],
  "openingHoursStatus": "Closed now",
  "priceRange": "Price Range · $$",
  "services": "Dine-in · Outdoor seating · In-store pickup",
  "ratingSummary": "98% recommend (52,548 Reviews)",
  "recommendPercent": 98,
  "reviewsCount": 52548,
  "followers": "903K followers",
  "followersApprox": 903000,
  "likesCount": 903060,
  "talkingAboutCount": 83782,
  "checkinsCount": 528401,
  "profilePicture": "https://lookaside.fbsbx.com/lookaside/crawler/media/?media_id=100064806517961",
  "bio": "New York City's most iconic deli.",
  "scrapedAt": "2026-08-20T04:51:55.017Z"
}
```

Singular and plural fields sit side by side on purpose. `email` is the first one found, `emails` is all of them. If you're building a CRM import you want the singular columns; if you're doing research you want the arrays.

`followers` is Facebook's own rounded string (`"903K followers"`). `followersApprox` is that same value parsed to a number so you can sort on it. They will not agree exactly, and `likesCount` is the precise figure where the Page exposes it.

### Input

```json
{
  "startUrls": [
    "https://www.facebook.com/katzsdeli",
    "shakeshack",
    "@nasa",
    "https://www.facebook.com/profile.php?id=100064806517961"
  ],
  "maxPages": 50
}
```

- `startUrls` — the Pages to read. Up to 200 per run. Duplicates are dropped before anything is fetched, so you aren't billed twice for the same Page appearing twice in your list.
- `maxPages` — optional ceiling on how many of those to actually read. Handy when you want to point a 200-row list at it but only spend on the first 50.
- `sessionCookies` — optional, and you almost certainly don't need it. See below.
- `proxyUrls` — optional. Leave empty unless you already pay for proxies and want the traffic to go through them.

Run it with empty input and you get one free sample row showing the shape of the output. That row is labelled and not charged.

### Limits worth knowing up front

**200 Pages per run.** Not a soft cap. If you have 5,000 Pages, that's 25 runs.

**Only what the Page publishes.** This reads the public About panel. A Page that never filled in a phone number has no phone number to give you, and you'll get `null`. Plenty of Pages publish a website but no email. That's normal, not a failure. Pages that return no contact details at all are not charged.

**Facebook refuses some requests, and what it refuses is the address doing the asking.** So a refused Page gets retried up to nine times, each attempt from a different address. Most come back on the first or second try. On a wide run a handful never do, and those aren't charged.

**Follower counts are approximate by Facebook's own choice.** They round in the UI. We parse what they show.

**No posts, no reviews, no ads.** This actor reads the contact block only. Other actors in this account cover posts, comments, reviews, events and reels.

#### About the `sessionCookies` field

Runs are logged out by default and that's enough for the public About panel, which is all this actor reads. The field exists for one case: Facebook counts requests against an account, so a cookie you supply puts the run on your account and your quota instead of on shared addresses. Your cookies are used alone and never mixed with anyone else's. Format is `c_user=<value>; xs=<value>`, one line per account.

Treat those values like a password. Anyone holding them can act as that account, and Facebook may sign the session out or restrict the account for automated use. If you don't have a specific reason to fill this in, leave it empty.

### Billing

$1.30 per 1,000 Pages delivered, plus a $0.001 run-start fee. Flat rate, every plan, no volume tiers.

You are charged per Page that actually lands in your dataset. Not charged: the sample row, diagnostic rows, duplicate Pages, Pages that stayed blocked, and Pages that publish no contact details at all.

If a run falls over halfway, it still finishes as a succeeded run with an honest diagnostic row rather than failing, so you keep the rows you already paid for.

### Reading the output in a spreadsheet

Export as CSV and the array fields (`emails`, `phones`, `socialLinks`, `categories`) flatten into numbered columns. If you only want one row per Page with one value per column, use the singular fields and ignore the plurals.

### Diagnostics

Uncharged rows with a `code` field turn up when something needed saying:

- `BAD_INPUT` — that entry wasn't a Facebook Page reference. The message names what was wrong with it.
- `PROXY_INPUT_ADJUSTED` — your proxy settings were changed to something the actor supports, and the note says how.
- Run-summary row — request count, megabytes transferred, exit addresses used and bytes per row.

# Actor input Schema

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

The Pages to read. Each entry can be a full Page URL (https://www.facebook.com/katzsdeli), an About-tab URL, a bare handle (katzsdeli), an @handle, a numeric Page id, or a profile.php?id= link. Up to 200 per run; duplicates are removed before anything is fetched.

## `maxPages` (type: `integer`):

Optional ceiling on how many of the Pages above to actually read, so you can point the Actor at a long list and still cap the spend. Leave empty to read all of them. Hard ceiling 200.

## `proxyUrls` (type: `array`):

Leave this empty. By default the run rotates its own pool of addresses that cost you nothing per gigabyte. Fill it in only if you specifically want the traffic to leave through proxy servers you already pay for, in the form http://user:pass@host:port.

## `sessionCookies` (type: `array`):

Leave this empty unless you need it. Runs are logged out by default and that is enough for public Facebook content. Facebook shows some things only to a signed-in account, and it limits how fast any one account may read; supplying your own cookie uses your account and your own rate limit, shared with nobody. In Chrome: open facebook.com while signed in, press F12, then Application > Cookies > https://www.facebook.com, and paste the values as "c\_user=<value>; xs=<value>". One line per account. Treat these like a password: anyone with them can act as that account, and Facebook may sign the session out or restrict the account for automated use.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.facebook.com/katzsdeli",
    "https://www.facebook.com/shakeshack"
  ]
}
```

# Actor output Schema

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

Every row in the default dataset: inputUrl, handle, pageName, pageUrl, pageId, isVerified, category, categories, website, websites, email, emails, phone, phones, address, socialLinks, openingHoursStatus, priceRange, services, ratingSummary, recommendPercent, reviewsCount, followers, followersApprox, likesCount, talkingAboutCount, checkinsCount, profilePicture, bio, scrapedAt. An empty, blocked or unmatched run returns a single uncharged row explaining what happened instead.

# 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/katzsdeli",
        "https://www.facebook.com/shakeshack"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("dami_studio/facebook-page-contact-info-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/katzsdeli",
        "https://www.facebook.com/shakeshack",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("dami_studio/facebook-page-contact-info-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/katzsdeli",
    "https://www.facebook.com/shakeshack"
  ]
}' |
apify call dami_studio/facebook-page-contact-info-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/facebook-page-contact-info-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/BZt04do3csSbklsdP/builds/QhqzbXFUl7UtbeX8I/openapi.json
