# Eventbrite API, Meetup Scraper API - Organizers, Prices, Dates (`snow_leo_data/eventbrite-scraper`) Actor

11,802 events from 14 day windows where one Eventbrite query stops at 1000, measured. 62 columns: venue coordinates, ticket prices, organizers, Meetup RSVP counts. Eventbrite data scraper and upcoming events API, 20 categories and 19 formats filtered inside the request.

- **URL**: https://apify.com/snow\_leo\_data/eventbrite-scraper.md
- **Developed by:** [Snow Leo Data](https://apify.com/snow_leo_data) (community)
- **Categories:** Travel, News, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.90 / 1,000 events

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?

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

## Eventbrite + Meetup Events Scraper

An **Eventbrite scraper** and a **Meetup scraper** in one Actor. Give it a city
and a phrase and it returns **event data** from both platforms as one table:
conferences, concerts, workshops, classes, networking nights and community
meetups, each with a parsed venue address, coordinates, **ticket prices**, the
**organizer**, and — where Meetup publishes it — the **RSVP count**.

No API key, no login, no proxy, no headless browser. Both platforms are read
through the same public endpoints their own websites use, so a run costs a few
requests and a few seconds rather than a browser session per page.

#### What this Actor is for

Event marketers building a calendar of everything happening in a city this
month. Sponsorship and sales teams looking for **conferences** and trade nights
worth showing up to. Community managers watching what competing **meetups** are
running. Venue and ticketing analysts tracking **ticket price** ranges by
category. Anyone who needs **event listings** as rows instead of as a web page.

#### The number that matters: one query stops at 1000 events

This is the single reason the Actor exists in this shape.

Ask Eventbrite for everything happening in New York and it answers, in its own
pagination block, that it found **10000** events. Then it hands over **49
pages** of 20. Page 50 still works. Page 51 returns an **empty list** — not an
error, not a warning, just nothing. A scraper that trusts the `object_count`
number and keeps paging quietly stops at a thousand rows and reports success.

Measured on 2026-09-12 against the live endpoint:

| What we asked | What the source promised | What it actually hands over |
| --- | --- | --- |
| All New York events, page 1 | `object_count` 10000 | `page_count` 49, 20 per page |
| Page 50 | — | 20 events |
| Page 51 | — | **0 events, no error** |

The way past it is that **every date window gets its own cap**. Walk the period
one day at a time and each day is a fresh query with a fresh thousand. Same
city, same endpoint, fourteen days:

| Strategy | Events reachable |
| --- | --- |
| One plain query | 1000 |
| 14 day windows | **11802** |

That is **11.8 times more** events out of the same source, with no proxy and no
browser. The walk is on by default (`breakPageCap`); turn it off when you want
the single fastest query and a thousand rows is enough.

The online catalogue has the same ceiling and the same cure: **50 pages, 1000
unique** online events per query, walked day by day when you ask for a period.

#### Two platforms, one table

Every competing Actor in this niche scrapes one platform. This one scrapes two
and merges them into a single schema, so `platform` is just a column. Rows from
Eventbrite carry the ticket price range and the parsed postal address; rows from
Meetup carry the attendance count and the size of the community behind the
event. Fields a platform does not publish are `null` — never invented.

| | Eventbrite | Meetup |
| --- | --- | --- |
| Keyword search | yes | yes |
| Location | bounding box from your radius | latitude, longitude, radius |
| Date range | yes, and it drives the cap walk | yes |
| Category filter | **20** categories, sent inside the request | not offered by the platform |
| Format filter | **19** formats, sent inside the request | not offered by the platform |
| Free / paid filter | yes, sent inside the request | price returned, filtered here |
| Online events | separate catalogue (see limitations) | native filter |
| Attendance | not published | `attendees_going` |
| Community size | organizer followers, verified badge, events hosted | `group_members` |
| Full description | with `includeDescription` | always |
| Groups mode | — | yes |

#### How the location works

You type `Berlin`, `Austin, TX` or `Greater London`. The Actor resolves it to
coordinates first, then sends a bounding box to Eventbrite and the same distance
in miles to Meetup. Ten cities on four continents were checked live and all ten
resolved. An invented place resolves to nothing, and the run says so out loud
instead of silently returning the whole planet — that failure has an
`empty_reason` of its own. You can skip the lookup entirely by passing
`latitude` and `longitude`.

#### Input

| Field | What it does |
| --- | --- |
| `searchQuery` | Words to match. Empty means browse everything on Eventbrite. |
| `location` | City or place to search around. |
| `latitude`, `longitude` | Exact point, replaces the city lookup. |
| `radiusKm` | How far around the point to look, 1 to 500. |
| `sources` | `eventbrite`, `meetup`, or both. Empty means both. |
| `mode` | `events`, or `groups` for Meetup communities. |
| `startDate`, `endDate` | Period as `YYYY-MM-DD`. |
| `daysAhead` | Period length when no end date is given. |
| `breakPageCap` | Walk the period day by day to pass the 1000 cap. |
| `categories` | Twenty Eventbrite categories, sent inside the request. |
| `formats` | Nineteen Eventbrite formats: conference, concert, class and so on. |
| `eventType` | `any`, `in_person`, `online`, `hybrid`. |
| `priceFilter` | `any`, `free`, `paid`. |
| `sortBy` | Meetup order: `relevance` or `date`. |
| `minAttendees` | Drop events with fewer people going. |
| `titleContains` | Keep only events matching these words. |
| `excludeKeywords` | Drop events matching these words. |
| `eventUrls` | Scrape these exact Eventbrite event pages instead of searching. |
| `includeDescription` | Open each Eventbrite page for the full text and price range. |
| `includeOrganizer` | Add the organizer track record. One request per unique organizer. |
| `maxItems` | Stop after this many delivered rows. `0` means no limit. |
| `onlyNew` | Return only what is new or changed since earlier runs. |
| `emitUnchanged` | In that mode, also return unchanged events. |
| `compactOutput` | Seventeen columns instead of the full record. |
| `excludeEmptyFields` | Leave empty fields out of the JSON. |

#### Output

Sixty-two columns, the same shape for both platforms.

Identity and text: `platform`, `record_type`, `event_id`, `title`, `summary`,
`description`, `description_html`, `url`, `tickets_url`, `image`, `tags`.

Time: `start_at`, `end_at`, `timezone`, `duration_minutes`, `published_at`,
`scraped_at`.

Place: `venue_name`, `address`, `city`, `region`, `postal_code`, `country`,
`neighborhood`, `latitude`, `longitude`, `is_online`.

Money: `is_free`, `price_min`, `price_max`, `currency`.

People: `organizer_name`, `organizer_url`, `organizer_id`,
`organizer_followers`, `organizer_website`, `organizer_twitter`,
`organizer_facebook`, `organizer_verified`, `organizer_total_events`,
`organizer_upcoming_events`, `organizer_hosting_years`,
`organizer_attendees_hosted`, `organizer_attendees_number`, `group_name`,
`group_url`, `group_members`, `attendees_going`, `capacity`.

Classification and state: `category`, `subcategory`, `format`,
`age_restriction`, `language`, `series_id`, `is_sold_out`, `status`,
`is_cancelled`, `change_type`, `search_query`, `search_location`,
`search_window`.

Every column may be `null`, and the dataset schema says so. That is not
sloppiness: Apify validates the dataset schema on a live run, and a column
declared as a plain string that arrives empty fails the whole batch, so the
buyer gets nothing.

#### The address is parsed, not a label

Eventbrite hands back the venue broken into street, city, region, postal code,
country and coordinates, plus a place hierarchy that goes down to the
neighbourhood. All of it is kept in separate columns. Meetup gives street, city,
state, postal code and coordinates, and those land in the same columns. You can
group by `city`, filter by `postal_code` or plot `latitude`/`longitude` without
parsing a display string first.

#### Prices are numbers

`price_min` and `price_max` are numbers or `null` — never an empty string,
never a marketing sentence. A column of floats with `""` in it breaks Excel,
BigQuery and pandas alike, so an unknown price is `null` and stays `null`.
On Eventbrite the range comes from the ticket availability block, and
`includeDescription` cross-checks it against the price schema published on the
event page itself.

#### Who is behind the event

Turn on `includeOrganizer` and every Eventbrite row gains the organizer's track
record: whether Eventbrite has **verified** them, how many events they have run
in total, how many are still upcoming, how long they have been hosting, and how
many attendees they have hosted. Together with the website, X and Facebook links
that come free with the search, that is enough to sort organizers by seriousness
before you contact any of them.

Two details worth stating plainly. The request is made **once per unique
organizer per run**, not once per event, so a city sweep where one promoter runs
forty parties costs one extra page, not forty. And the attendee count is
published by Eventbrite already rounded, as `98k`: the rounded string is kept
in `organizer_attendees_hosted` exactly as shown, and
`organizer_attendees_number` holds the same figure as an integer for sorting.
Neither pretends to a precision the source does not have.

#### Monitoring without paying twice

Turn on `onlyNew` and the Actor remembers every event it has already delivered
in a **named** key-value store, which survives between runs. The next run
returns only what is new or what changed — a moved date, a renamed event, a
cancellation. Unchanged events are counted and skipped, so a scheduled watch on
a city costs a fraction of the first run.

The fingerprint behind that comparison is built only from fields that arrive in
**every** mode: title, start time, venue and the cancellation flag. Description
and price are deliberately excluded, because they only appear when
`includeDescription` is on — including them would make the same event look
"changed" every time you flipped that switch.

An incremental run that returns nothing is not a failure, and the Actor says
which kind of nothing it is: the report carries an `empty_reason` of
`nothing-changed`, `filtered-out`, `unknown-location`,
`source-returned-nothing` or `charge-limit-reached`, and a matching warning goes
into the log. Silence is the one thing it will not do.

#### maxItems limits delivery, not crawling

If `maxItems` stopped the crawl instead of the output, a filter could eat your
entire order: the Actor would collect thirty rows, your filter would remove all
thirty, and you would get an empty dataset from a green run. Here the crawl
keeps going until the number of **delivered** rows is reached, with a bounded
reserve so a rare filter cannot run up your bill either.

Duplicates are dropped before billing, not after. Meetup returns the same event
on more than one page — measured: 157 rows arrived, 150 were distinct — and
without deduplication you would pay for the difference.

#### Run report

Every run writes a `REPORT` record: how many day windows were walked, how many
requests each platform took, how many raw rows arrived, how many were duplicates,
how many each filter removed, whether a query hit the 1000 ceiling, and which
platform failed if one did. When something returns less than you expected, the
report says why.

#### Honest limitations

Things a competing Actor offers that this one does not, named rather than
hidden:

- **Eventbrite online events cannot be filtered inside the search request.**
  The endpoint accepts `online_events_only` and silently ignores it — measured:
  twenty rows came back with the online flag false on every one. Choosing
  `Online` therefore switches Eventbrite to its online catalogue, which is a
  different listing with the same 1000-event ceiling. In that catalogue the
  source also refuses to combine a keyword with a date range: it drops the
  dates. The Actor puts the keyword in the request and applies your dates to the
  rows afterwards, so the filter you asked for is really applied.
- **Meetup has no category taxonomy in event search.** `categories` narrows
  Eventbrite only. Use `searchQuery` and `titleContains` for Meetup.
- **Meetup sorts by relevance or date only.** There is no sort by attendance;
  the platform does not offer one, and inventing it would mean sorting a page at
  a time and calling it global.
- **Meetup returns nothing for an empty phrase.** A neutral word is substituted
  and the log says so.
- **Attendance is Meetup-only.** Eventbrite does not publish how many people are
  going, so `attendees_going` is `null` there and `minAttendees` deliberately
  keeps those rows instead of deleting them.
- **`eventUrls` accepts Eventbrite pages only.** A Meetup event address is
  skipped and named in the log.
- **`formats` and `categories` narrow Eventbrite only.** Meetup has neither
  taxonomy in its event search.
- **No country picker with 238 entries.** Location is a place name or a point
  plus a radius, which is both more precise and easier to schedule.
- **No built-in delivery to Notion or Slack.** Use Apify's own integrations on
  the dataset.

#### Cost

Billing is per row delivered, so the filters above cost you nothing: rows
removed before the dataset is written are never charged. The crawl itself is
cheap because it is plain HTTP — one handshake page, then one request per page
of twenty events, plus one extra request per event only if you asked for the
full description.

#### FAQ

#### Do I need an Eventbrite or Meetup API key?

No. Both platforms are read through the public endpoints their own websites
call. There is nothing to register and nothing to renew.

#### Does it need proxies or a browser?

No. The Actor is plain Python on the standard library, and it runs in 512 MB.
That is why it is cheap enough to schedule hourly.

#### How do I get more than a thousand events?

Leave `breakPageCap` on and widen the period. Each day in the range is a
separate query with its own thousand-event ceiling; fourteen days of New York
reached 11802 events where a single query gives 1000. Narrowing by `categories`
or by `searchQuery` also creates fresh caps, because the ceiling is per query,
not per city.

#### Why does the report say `hit_cap`?

Because one of your queries found more events than the source will hand over.
It is a hint, not an error: split the period into shorter windows, or add a
category, and the same events become reachable.

#### Can I scrape one specific event page?

Yes. Put its address into `eventUrls`. Each page is read in full: description,
price range, age restriction, duration, category, format and sales status.

#### Can I get Meetup groups instead of events?

Set `mode` to `groups`. You get community name, link, description, city,
coordinates, member count, topic category and the founding date, in the same
table shape with `record_type` set to `group`.

#### How often should I schedule it?

For a city watch, once or twice a day with `onlyNew` on. Event listings do not
change by the minute, and incremental mode means you only pay for movement.

#### What happens if one platform is down?

The other one still runs. The failure is recorded in the report under that
platform's name, and the log says what went wrong. A half-broken run returns
half the data instead of nothing.

#### Is the data ordered?

Rows arrive in the order the platforms return them: Eventbrite first, window by
window, then Meetup. Sort in the dataset view or downstream — `start_at` is a
plain ISO timestamp.

#### Which categories are available?

Business & Professional, Science & Technology, Music, Film, Media &
Entertainment, Performing & Visual Arts, Fashion & Beauty, Health & Wellness,
Sports & Fitness, Travel & Outdoor, Food & Drink, Charity & Causes, Government &
Politics, Community & Culture, Religion & Spirituality, Family & Education,
Seasonal & Holiday, Home & Lifestyle, Auto, Boat & Air, Hobbies & Special
Interest, and Other. All twenty were checked against the live source and all
twenty return events.

#### Which formats are available?

Conference, Seminar or Talk, Tradeshow, Consumer Show, or Expo, Convention,
Festival or Fair, Concert or Performance, Screening, Dinner or Gala, Class,
Training, or Workshop, Meeting or Networking Event, Party or Social Gathering,
Rally, Tournament, Game or Competition, Race or Endurance Event, Tour,
Attraction, Camp, Trip, or Retreat, and Appearance or Signing.
All nineteen formats were checked live and every one returns events.

# Actor input Schema

## `searchQuery` (type: `string`):

Words to look for in event titles and descriptions, for example 'startup pitch' or 'salsa'. Leave empty to browse everything around the location on Eventbrite; Meetup returns nothing for an empty phrase, so a neutral word is used there instead.

## `location` (type: `string`):

City, region or address to search around, for example 'Berlin', 'Austin, TX' or 'Greater London'. Resolved to coordinates before the search; if the place is unknown the run says so instead of quietly returning the whole world.

## `latitude` (type: `string`):

Exact latitude to search around. Given together with longitude, it replaces the city lookup entirely. Half a point is worse than none, so both values are needed.

## `longitude` (type: `string`):

Exact longitude to search around. Given together with latitude, it replaces the city lookup entirely.

## `radiusKm` (type: `integer`):

How far from the point to look. Eventbrite receives a bounding box built from this radius, Meetup receives the same distance converted to miles.

## `sources` (type: `array`):

Which platforms to search. Leaving this empty means both of them, never none.

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

Events, or Meetup community groups with member counts and topics. Groups exist on Meetup only, so that mode ignores Eventbrite.

## `startDate` (type: `string`):

First day to collect, as YYYY-MM-DD. Defaults to today. Dates in the past are pulled forward because neither platform lists events that already happened.

## `endDate` (type: `string`):

Last day to collect, as YYYY-MM-DD. Defaults to the first day plus the number of days below. A reversed range is swapped silently.

## `daysAhead` (type: `integer`):

How far into the future to look when no last day is given. Every extra day is one more window past the per-query cap, so a longer period returns more events, not just later ones.

## `breakPageCap` (type: `boolean`):

One Eventbrite query returns at most 1000 events however many it found, and says nothing about it. With this on, the period is split into day windows, each with its own cap. Turn it off for the fastest possible single query.

## `categories` (type: `array`):

Limit Eventbrite to these categories. The condition goes into the request itself, so it narrows what is fetched instead of throwing rows away afterwards. Meetup has no matching taxonomy and is not filtered by it.

## `formats` (type: `array`):

Limit Eventbrite to these event formats - conference, concert, class and so on. Like categories, the condition goes into the request itself. Meetup has no format taxonomy and is not filtered by it.

## `eventType` (type: `string`):

In-person, online or hybrid. Meetup understands this in the request. Eventbrite does not expose online events through its search at all, so picking 'Online' switches that platform to its online catalogue.

## `priceFilter` (type: `string`):

Free events, paid events or both. On Eventbrite the condition goes into the request; rows whose price is unknown are kept rather than dropped.

## `sortBy` (type: `string`):

Order Meetup results by relevance or by date. Those are the only two orders the platform offers.

## `minAttendees` (type: `integer`):

Drop events with fewer people going. Only Meetup publishes attendance, so Eventbrite rows are kept: a missing number means unknown, not zero.

## `titleContains` (type: `array`):

Keep only events whose title or summary contains one of these words.

## `excludeKeywords` (type: `array`):

Drop events whose title or summary contains any of these words.

## `eventUrls` (type: `array`):

Scrape these exact Eventbrite event pages instead of searching. Each one is read in full: description, price range, age limit and duration.

## `includeDescription` (type: `boolean`):

Open every Eventbrite event page to add the full description, the price range, the age limit and the duration. Costs one extra request per event, so it is off by default. Meetup descriptions always come with the search.

## `includeOrganizer` (type: `boolean`):

Open each Eventbrite organizer profile to add whether they are verified, how many events they have run, how long they have been hosting and how many attendees they have hosted. One request per unique organizer per run, not one per event.

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

Stop after this many rows have actually been delivered - not collected. Filters never eat your order: the crawl keeps going until the delivered count is reached.

## `onlyNew` (type: `boolean`):

Remember what earlier runs delivered and return only events that are new or that changed since. This is what makes a scheduled watch cheap: you are not charged twice for the same listing.

## `emitUnchanged` (type: `boolean`):

In incremental mode, return unchanged events too, marked as UNCHANGED. Off by default because you would pay for them again.

## `compactOutput` (type: `boolean`):

Return a short row of seventeen fields instead of the full record. Handy for AI agents and for spreadsheets.

## `excludeEmptyFields` (type: `boolean`):

Leave out fields that are empty for a given event, so the JSON stays small.

## Actor input object example

```json
{
  "searchQuery": "technology",
  "location": "New York",
  "radiusKm": 40,
  "sources": [
    "eventbrite",
    "meetup"
  ],
  "mode": "events",
  "daysAhead": 30,
  "breakPageCap": true,
  "eventType": "any",
  "priceFilter": "any",
  "sortBy": "relevance",
  "minAttendees": 0,
  "includeDescription": false,
  "includeOrganizer": false,
  "maxItems": 100,
  "onlyNew": false,
  "emitUnchanged": false,
  "compactOutput": false,
  "excludeEmptyFields": false
}
```

# Actor output Schema

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

All collected 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 = {
    "searchQuery": "technology",
    "location": "New York"
};

// Run the Actor and wait for it to finish
const run = await client.actor("snow_leo_data/eventbrite-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 = {
    "searchQuery": "technology",
    "location": "New York",
}

# Run the Actor and wait for it to finish
run = client.actor("snow_leo_data/eventbrite-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 '{
  "searchQuery": "technology",
  "location": "New York"
}' |
apify call snow_leo_data/eventbrite-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,snow_leo_data/eventbrite-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/L47rQmYRdYFonQMkD/builds/1T2mbrKq1anj75QmG/openapi.json
