# Facebook Events Scraper (`fanndev/facebook-events-scraper`) Actor

Collect public Facebook events by keyword and city, or straight from a page's events tab: name, date, venue address, online or in-person, ticket price line, host and attendance. Facebook's event search is the one search vertical still open to logged-out clients, and this actor uses it.

- **URL**: https://apify.com/fanndev/facebook-events-scraper.md
- **Developed by:** [Faisal Ahdan naufal](https://apify.com/fanndev) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.40 / 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 Events Scraper

Collect public Facebook events by keyword and city, or straight from a page's
events tab: name, date, venue address, online or in-person, ticket price line,
host and attendance.

No login, no cookies to paste, no proxy required.

### Location goes in the search term

Facebook's event search takes no location parameter a signed-out client can use.
It is, however, a genuinely good text search — putting the city in the query
works:

| Query | Result |
| --- | --- |
| `yoga new york` | New York and Brooklyn yoga classes |
| `konser jakarta` | Jakarta concerts |
| `live music london` | London gigs |

So this actor takes `searchTerms` and `locations` and combines them:
2 terms × 3 cities = 6 searches. Supply locations on their own and each becomes
a search in its own right.

This is the one Facebook search vertical still open to logged-out clients —
`/search/pages/`, `/search/groups/` and `/search/top/` all return HTTP 404.

### What you get

| Field | Example |
| --- | --- |
| `name`, `eventUrl` | `Yoga with Shape Up NYC` |
| `dayTimeSentence` | `Fri, 25 Sep at 11:00 EDT and 2 more` |
| `startsAtIso`, `startTimestamp` | `2026-08-28T15:00:00Z` |
| `placeAddress` | `2636 E 14th St, Brooklyn, NY, United States, New York 11235` |
| `placeName`, `city`, `latitude`, `longitude` | |
| `isOnline`, `isPast`, `isCanceled`, `eventKind` | |
| `priceRangeText` | ticketing line, where the event sells tickets |
| `hostName`, `hostUrl` | on page-tab events |
| `goingCount`, `interestedCount`, `attendanceText` | `1`, …, `1 going` |
| `coverPhotoUrl`, `coverPhotoCaption` | |

### Two date fields, and why

Facebook publishes a human sentence (`Sun, 20 Sep at 16:00 EDT`) and, on search
results, an exact timestamp. Both are emitted: a sentence cannot be sorted, a
timestamp cannot be read aloud, and the sentence is the **only** one of the two
that a page's events tab carries.

That has a consequence worth knowing: a `startsAfter` / `startsBefore` filter
**drops** page-tab events, because they have no timestamp to judge. The run log
says so when it happens. Guessing a date from an abbreviated sentence with no
year would be worse.

### Input example

```json
{
  "searchTerms": ["live music", "art exhibition"],
  "locations": ["new york", "london"],
  "maxEventsPerQuery": 60,
  "excludePast": true,
  "onlyInPerson": true,
  "exportFormats": ["csv"]
}
```

Or from specific pages:

```json
{
  "pages": ["MTV", "https://www.facebook.com/coachella"],
  "maxEventsPerQuery": 50
}
```

### Honest limits

- **The event detail page is not public.** `facebook.com/events/<id>/` returns a
  67 KB generic shell to logged-out visitors — the same one for real and
  invented ids. So there is no full description and no guest list, and this
  actor does not pretend otherwise. `coverPhotoCaption` — Facebook's own alt
  text for the poster — is the closest thing the public payload has to a
  description, and it often contains the poster's headline.
- **The search response comes at two levels of detail.** Sometimes every event
  carries its date, venue and photo; sometimes the same URL returns
  name-and-link stubs. The actor detects a stub-only response and refetches
  once, which in testing restored full detail on all 20 events. It refetches
  once, not in a loop, and reports what it got.
- `goingCount` is parsed from Facebook's attendance line, which abbreviates
  large numbers. `attendanceText` keeps the original.
- Most events use a free-text place with no separate venue name; `placeName` is
  then the first segment of the address the organiser typed.

### 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 events Facebook renders on the first page.

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.

# Actor input Schema

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

What to look for, e.g. 'yoga', 'live music', 'konser'. Combined with each location below.

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

City names, e.g. 'new york', 'jakarta', 'london'. Facebook's event search takes no location parameter a logged-out client can use, so the city is appended to the search term instead - which works: 'konser jakarta' returns Jakarta concerts. Supply locations on their own and each becomes a search in its own right.

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

Read a page's own events tab instead of searching. Vanity slugs ('MTV') or page URLs. Use this when you already know whose events you want.

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

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

## `maxEventsPerQuery` (type: `integer`):

Facebook renders roughly seven events per search page and this actor replays its pagination query for the rest.

## `excludePast` (type: `boolean`):

Drop events Facebook marks as finished.

## `excludeCanceled` (type: `boolean`):

Drop events Facebook marks as cancelled.

## `onlyOnline` (type: `boolean`):

Keep virtual events only. Cannot be combined with 'Only in-person events'.

## `onlyInPerson` (type: `boolean`):

Keep events with a physical venue only.

## `nameContains` (type: `string`):

Case-insensitive substring match against the event name.

## `placeContains` (type: `string`):

Case-insensitive substring match against the venue name, address and city - useful for narrowing a broad search to one neighbourhood.

## `startsAfter` (type: `string`):

YYYY-MM-DD. Events from a page's events tab carry a date sentence but no exact timestamp, so a date filter drops them rather than guessing. The log says when that happens.

## `startsBefore` (type: `string`):

YYYY-MM-DD.

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

Append one RUN\_SUMMARY record: events collected, online vs in-person, how many carry a venue and an exact start time, and the date range covered.

## `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 events Facebook renders on the first page. 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
{
  "searchTerms": [
    "live music"
  ],
  "locations": [
    "new york"
  ],
  "maxEventsPerQuery": 30,
  "excludePast": true,
  "excludeCanceled": true,
  "onlyOnline": false,
  "onlyInPerson": false,
  "emitSummary": true,
  "exportFormats": [],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Events found per query or page, 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 = {
    "searchTerms": [
        "live music"
    ],
    "locations": [
        "new york"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("fanndev/facebook-events-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 = {
    "searchTerms": ["live music"],
    "locations": ["new york"],
}

# Run the Actor and wait for it to finish
run = client.actor("fanndev/facebook-events-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 '{
  "searchTerms": [
    "live music"
  ],
  "locations": [
    "new york"
  ]
}' |
apify call fanndev/facebook-events-scraper --silent --output-dataset

```

## MCP server setup

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