# Facebook Business Page Finder by Keyword & City (`nimbryxo-studio/facebook-business-page-finder-by-keyword-and-city`) Actor

Find Facebook business pages by direct URL, or discover them by keyword and city, and get names, categories, addresses, follower counts, contact details, business hours, ratings, and reviews. A Facebook login cookie is recommended for full coverage.

- **URL**: https://apify.com/nimbryxo-studio/facebook-business-page-finder-by-keyword-and-city.md
- **Developed by:** [Nimbryxo-studio](https://apify.com/nimbryxo-studio) (community)
- **Categories:** Social media, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.99 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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 Business Page Finder by Keyword & City

Find Facebook business pages either by pasting direct page URLs or by discovering them through a keyword and city, then get back page identity, engagement metrics, contact details, business hours, ratings, and reviews for each one.

### What this actor does

- Scrapes direct Facebook page URLs, or discovers pages by combining search terms with locations (e.g. "Coffee Shop" + "London")
- Returns page identity (name, ID, URL, categories), engagement (followers, likes, check-ins), and contact details (phone, email, address, website, Messenger link) when the page owner has listed them
- Pulls business hours, star/recommend rating, and an ad library reference for each page
- Optionally fetches real reviews per page (reviewer name, recommend verdict, review text, date) via `includeReviews`
- Scales to large result sets by combining multiple search terms with multiple locations and raising `maxItems`
- Pages that turn out to be deleted, unavailable, or shown only as a login wall are skipped entirely rather than appearing as empty rows

### Input

| Field         | Type             | Default      | Description                                                                                       |
| ------------- | ---------------- | ------------ | ------------------------------------------------------------------------------------------------- |
| `startUrls`   | Array of `{url}` | –            | Direct list of Facebook page URLs to scrape — skips discovery for these. Either this or `searchTerms` is required |
| `searchTerms` | Array of strings | –            | Plain search terms for page discovery (e.g. `["Coffee Shop", "Bakery"]`). Either this or `startUrls` is required |
| `locations`   | Array of strings | –            | Optional locations combined with each search term (e.g. `["London", "Manchester"]`)               |
| `maxItems`    | Integer          | `60`         | Maximum number of page rows to output (1–5000)                                                    |
| `includeReviews` | Boolean       | `true`       | Fetch and include up to 10 reviews per page (adds one extra request per page)                      |
| `cookies`     | String           | –            | Facebook session cookies — **strongly recommended**. See [Cookies](#cookies-authentication) below |

#### Example Input — direct URLs

```json
{
  "startUrls": [
    { "url": "https://www.facebook.com/McDonalds" },
    { "url": "https://www.facebook.com/BBCNews" }
  ],
  "cookies": "..."
}
```

#### Example Input — keyword + location discovery

```json
{
  "searchTerms": ["Coffee Shop", "Cafe", "Bakery"],
  "locations": ["London", "Manchester", "Birmingham"],
  "maxItems": 300,
  "cookies": "..."
}
```

That single input produces 9 search combinations (3 terms × 3 cities), each yielding up to ~40 discovered URLs — giving a pool of up to ~360 candidates to fill 300 results from. `startUrls` and `searchTerms` can also be combined in the same run — results from both are merged into the same output dataset.

#### Cookies (Authentication)

**Strongly recommended for any run.**

Without session cookies, Facebook serves a compact login-wall stub for many discovered pages — you'll get some data but contact fields (phone, address, website) are gated. Providing cookies dramatically increases both field coverage and the number of pages you can successfully retrieve.

**How to export cookies from your browser:**

1. Log in to Facebook in Chrome or Firefox
2. Open DevTools → Application → Cookies → `facebook.com`
3. Export the cookies for `.facebook.com` using a browser extension like [EditThisCookie](https://chrome.google.com/webstore/detail/editthiscookie/fngmhnnpilhplaeedifhccceomclgfbg) (export as JSON) or [Cookie Quick Manager](https://addons.mozilla.org/en-US/firefox/addon/cookie-quick-manager/) on Firefox
4. Paste the exported JSON array into the `cookies` field

**Minimum cookies needed:** `c_user`, `xs`, `datr`, `fr`, `sb`.

**Accepted formats:**

1. **JSON array** (recommended — export directly from your browser extension):

   ```json
   [
     { "name": "c_user", "value": "100074...", "domain": ".facebook.com", "path": "/", "expires": 1815212390, "httpOnly": false, "secure": true },
     { "name": "xs", "value": "8%3A2vaT...", "domain": ".facebook.com", "path": "/", "httpOnly": true, "secure": true },
     { "name": "datr", "value": "7JhPar...", "domain": ".facebook.com", "path": "/", "httpOnly": true, "secure": true }
   ]
   ```

2. **Cookie header string:** `"c_user=100074...; xs=8%3A...; datr=7JhP..."`

Cookies expire after a while, or when you log out of that browser session. If you see high skip rates, refresh your cookies.

### Scaling to 1K+ Results

The actor is designed to scale — here is the fastest path to large datasets:

1. **Use multiple search terms and locations.** Each `(term, location)` pair runs its own discovery pass. Example: 5 terms × 10 cities = 50 combinations × up to ~40 pages each = up to ~2,000 candidates in the pool.

2. **Set `maxItems` to your target.** The actor over-discovers ~2× `maxItems` URLs to absorb login-walls and fetch failures without leaving you short.

3. **Provide session cookies.** This is essential at scale — cookies enable Facebook's own search as the primary discovery source, which is far more reliable than discovering pages through other search engines, and unlock contact fields on login-gated pages.

4. **Vary your search terms.** Generic terms (e.g. `"Restaurant"`) produce many duplicate pages across locations. More specific terms (e.g. `"Italian Restaurant"`, `"Sushi Bar"`) yield more unique pages.

**Example for 1K results:**

```json
{
  "searchTerms": ["Restaurant", "Cafe", "Bar", "Pub", "Bistro"],
  "locations": ["London", "Manchester", "Birmingham", "Glasgow", "Leeds", "Bristol", "Edinburgh", "Liverpool", "Sheffield", "Cardiff"],
  "maxItems": 1000,
  "cookies": "..."
}
```

50 search combinations, each yielding up to ~40 unique URLs — a pool of up to ~2,000 candidates. How many become rows depends on how many of them Facebook actually serves; cookies make the biggest difference.

### Output

#### Page Identity

| Field        | Type           | Description                              |
| ------------ | -------------- | ---------------------------------------- |
| `facebookUrl` | String        | Facebook page URL                        |
| `pageUrl`    | String         | Normalized page URL                      |
| `pageName`   | String         | Page name or slug                        |
| `pageId`     | String | Facebook page identifier                 |
| `facebookId` | String | Facebook ID (usually matches `pageId`)   |
| `title`      | String | Full page title with context             |

#### Classification

| Field      | Type          | Description                              |
| ---------- | ------------- | ---------------------------------------- |
| `categories` | Array | Page categories                        |
| `category` | String | Primary category                         |
| `info`     | Array  | Short info lines from the page           |
| `intro`    | String | Page introduction or description         |

#### Contact & Business

| Field        | Type           | Description                              |
| ------------ | -------------- | ---------------------------------------- |
| `phone`      | String | Public phone number                      |
| `email`      | String | Public contact email                     |
| `messenger`  | String | Messenger link                           |
| `address`    | String | Address or coordinates                   |
| `addressUrl` | String | Google Maps link for the address         |
| `website`    | String | Primary linked website                   |
| `websites`   | Array  | All detected website links               |
| `priceRange` | String | Price range (e.g. `"££"`)               |

#### Engagement

| Field             | Type           | Description                     |
| ----------------- | -------------- | ------------------------------- |
| `followers`       | Number | Follower count                  |
| `likes`           | Number | Like count                      |
| `followings`      | Number | Following count                 |
| `checkins`        | Number | Check-in count ("were here")    |
| `talkingAboutCount` | Number | Talking-about count           |

#### Media

| Field               | Type           | Description               |
| ------------------- | -------------- | ------------------------- |
| `profilePictureUrl` | String | Profile picture URL       |
| `coverPhotoUrl`     | String | Cover photo URL           |

#### Business Details

| Field            | Type            | Description                                                      |
| ---------------- | --------------- | ---------------------------------------------------------------- |
| `business_hours` | String  | Business hours info                                              |
| `ratingOverall`  | Number  | Overall rating score, synthesized to a 0-5 scale for compatibility (Facebook Pages actually use a recommend %, not 1-5 stars — see `recommendPercentage`) |
| `ratingCount`    | Number  | Review/rating count                                              |
| `ratingText`     | String  | Human-readable rating text                                       |
| `recommendPercentage` | Number | Raw recommend percentage (0-100) as shown on the page — the authentic Facebook Pages rating metric |
| `ownerOrganization` | String | Confirmed owning organization/business ("X is responsible for this Page"), when Facebook discloses it |
| `pageAdLibrary`  | Object or string  | Ad library metadata when found on the page, otherwise a constructed Ad Library search URL for the page |
| `reviews`        | Array   | Up to 10 reviews that Facebook shows first on the page's reviews tab: `[{reviewerName, recommends, reviewText, reviewDate}]` (`reviewDate` as `YYYY-MM-DD`). Inside a review, `reviewText` or `reviewDate` can be `null` when Facebook didn't include them. Controlled by the `includeReviews` input (default on) |

A top-level field that Facebook didn't expose for a page is left out of that record entirely rather than included as `null` (the review objects described above are the one exception).

#### Sample Output

```json
{
  "facebookUrl": "https://www.facebook.com/ozonecoffeeuk",
  "pageUrl": "https://www.facebook.com/ozonecoffeeuk",
  "pageName": "ozonecoffeeuk",
  "pageId": "191234567",
  "facebookId": "191234567",
  "title": "Ozone Coffee Roasters | Facebook",
  "categories": ["Coffee Shop"],
  "category": "Coffee Shop",
  "intro": "Specialty coffee roaster and cafe in London.",
  "messenger": "https://m.me/191234567",
  "followers": 9100,
  "followings": 12,
  "profilePictureUrl": "https://scontent.xx.fbcdn.net/v/...",
  "coverPhotoUrl": "https://scontent.xx.fbcdn.net/v/...",
  "pageAdLibrary": "https://www.facebook.com/ads/library/?active_status=all&ad_type=all&country=ALL&view_all_page_id=191234567&search_type=page",
  "reviews": [
    {
      "reviewerName": "Jane Smith",
      "recommends": true,
      "reviewText": "Great coffee and friendly staff!",
      "reviewDate": "2025-11-02"
    }
  ]
}
```

#### Unavailable Pages

When a discovered or provided URL turns out to be unavailable or deleted, it is detected and **skipped entirely** — it does not appear in the output dataset and does not consume your `maxItems` budget. This keeps the dataset free of junk rows; check the run log if you need to know which URLs were skipped and why.

### Use Cases

- **Local business discovery**: find businesses in specific cities or regions
- **Competitive intelligence**: build datasets of competitor pages in your industry
- **Lead generation**: collect pages with contact info for outreach
- **Market research**: survey the Facebook page landscape for a category
- **Monitoring**: run repeatedly to track new pages for a search term

### FAQ

#### Do I need a Facebook account to use this?

No, but it's strongly recommended. Without cookies, page discovery relies on other search engines and extracts only public HTML. Providing session cookies from a logged-in Facebook account enables the most reliable discovery method (Facebook's own search) and gives access to contact fields that aren't present in the public HTML.

#### Why are some fields missing from a record?

A missing field means Facebook did not expose that information in the page's public HTML, the page owner did not fill it in, or the field layout for that page type doesn't include it — it's left out of the record rather than included as an empty value. Fields like `phone`, `address`, and `website` are only populated when the page owner has listed them on their Facebook page. Adding cookies increases the chance of extracting these for login-gated pages.

#### Why did I get fewer results than `maxItems`?

The most common reasons:

- **Login walls**: Facebook gates some pages behind a login session, and pages that come back as a login wall are skipped. Provide session cookies to reach more of them.
- **No cookies provided**: without session cookies, discovery relies solely on DuckDuckGo/Google, which are less reliable than Facebook's own search — add cookies for the best results.
- **Narrow search terms**: each `(term, location)` pair yields a limited pool. Add more search terms or locations.

#### Can I get 1,000+ results?

Yes — see [Scaling to 1K+ Results](#scaling-to-1k-results) above. The short version: combine multiple search terms × multiple locations and set `maxItems` to your target. The actor handles all pagination and over-discovers URLs automatically.

#### How often do I need to refresh my cookies?

Whenever they stop working: logging out of that browser session or Facebook expiring the session invalidates them. If you notice a sudden drop in results or many login-wall skips in the logs, export fresh cookies from your browser.

#### Does this work for Facebook Groups or personal profiles?

No. The scraper targets public Facebook Pages (business pages, community pages, public figures). Facebook Groups and personal profiles have different URL structures and content restrictions.

#### Is this affiliated with Facebook or Meta?

No. This is an independent, third-party actor that reads Facebook's publicly accessible pages; it is not affiliated with, endorsed by, or operated by Meta Platforms, Inc.

# Actor input Schema

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

Direct list of Facebook page URLs to scrape (skips keyword/location discovery entirely for these). Accepts full page URLs, e.g. https://www.facebook.com/McDonalds. Can be combined with searchTerms — results from both are merged. Either startUrls or searchTerms is required.

## `searchTerms` (type: `array`):

Search terms for page discovery. Each term is combined with each location (if provided) to find matching Facebook pages. Either searchTerms or startUrls is required.

## `locations` (type: `array`):

Optional locations to combine with each search term for location-aware discovery. For example, adding 'London' will search for 'Coffee Shop London'.

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

Maximum number of page rows to output. For 500–1000+ results, provide Facebook session cookies and use multiple search terms or locations to maximize discovery. Also scales SERP pagination depth automatically.

## `includeReviews` (type: `boolean`):

Fetch and include real reviews (reviewer name, recommend/don't-recommend verdict, review text, date) for each page, when available. Adds one extra request per page. Disable for faster/cheaper runs if you don't need reviews.

## `cookies` (type: `string`):

Facebook session cookies. STRONGLY RECOMMENDED — without valid cookies, Facebook blocks ~94% of discovered pages with a login wall, most contact/business fields (phone, email, address, hours) will be empty, and page discovery itself is far less reliable. Accepts EITHER (1) a JSON array of Playwright-style cookie objects, OR (2) a raw `name=value; name2=value2` Cookie header string. Required cookies: c_user, xs, datr, fr, sb. Export them from your logged-in Facebook session via browser DevTools (Application > Cookies > facebook.com). Example: \[{"name":"c_user","value":"1000...","domain":".facebook.com","path":"/"}]

## Actor input object example

```json
{
  "searchTerms": [
    "Coffee Shop"
  ],
  "locations": [
    "London"
  ],
  "maxItems": 10,
  "includeReviews": true
}
```

# Actor output Schema

## `pages` (type: `string`):

Dataset containing discovered Facebook page rows with structured metadata

# 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 = {
    "searchTerms": [
        "Coffee Shop"
    ],
    "locations": [
        "London"
    ],
    "maxItems": 10,
    "cookies": ""
};

// Run the Actor and wait for it to finish
const run = await client.actor("nimbryxo-studio/facebook-business-page-finder-by-keyword-and-city").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 = {
    "searchTerms": ["Coffee Shop"],
    "locations": ["London"],
    "maxItems": 10,
    "cookies": "",
}

# Run the Actor and wait for it to finish
run = client.actor("nimbryxo-studio/facebook-business-page-finder-by-keyword-and-city").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 '{
  "searchTerms": [
    "Coffee Shop"
  ],
  "locations": [
    "London"
  ],
  "maxItems": 10,
  "cookies": ""
}' |
apify call nimbryxo-studio/facebook-business-page-finder-by-keyword-and-city --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nimbryxo-studio/facebook-business-page-finder-by-keyword-and-city"
        }
    }
}
```

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/MBGiwo5b4i8oo7LJo/builds/MxL4I7jxVSTIn4ZtK/openapi.json
