# Luma Events Scraper & Monitor (`zerolag/luma-events-scraper`) Actor

Scrape Luma (lu.ma) events by city, calendar, category or search: date, venue, price, tickets, sold-out status and organizer. A city gives far more events than its short Luma page. On a schedule it can return only new, changed, sold-out and cancelled events.

- **URL**: https://apify.com/zerolag/luma-events-scraper.md
- **Developed by:** [ZeroLag Data](https://apify.com/zerolag) (community)
- **Categories:** Automation, Lead generation, Developer tools
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.80 / 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.
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

Luma events scraper for cities, calendars and categories. It reads public Luma data and gives you each event with date, venue, price, ticket types, sold-out status and organizer as clean rows. Run it once for a list, or on a schedule to get only new, changed, sold-out and cancelled events.

- **Price:** $4.00 per 1,000 events on the Free plan, $2.80 on Business. Platform usage is included.
- **Input:** city, calendar, category or event links, coordinates for any place, or search phrases.
- **Output:** one row per event, with filters for dates, category, price and keywords. Host and guest names are left out.
- **Measured:** 1,112 events around San Francisco with descriptions and ticket types in 281 seconds on Apify. Luma's own city page listed 82 that day.

Found a bug, need a field, or want a new Actor? Open an issue on the **Issues** tab. If it works well for you, a short review helps others find it.

### How to scrape Luma events

1. Add what you want to read to **Luma pages**.
2. Set filters if you need them. A filtered event is not charged.
3. Set **Maximum results** and click **Start**.
4. Export the results as JSON, CSV or Excel.

No login, cookies, proxy or API key are needed. Old `lu.ma` links work too.

| You enter | You get |
| --- | --- |
| A city: `https://luma.com/london`, `sf` or `San Francisco` | Upcoming events within about 70 km, far more than the city page shows |
| Coordinates: `54.6872,25.2797` | The same for any place, also without a Luma city page |
| A calendar: `https://luma.com/superteam` | Upcoming events of that community, and past ones if you ask |
| A category: `https://luma.com/ai` | That category in all 87 Luma cities, busiest city first |
| `https://luma.com/discover` | All events in all 87 Luma cities, busiest city first |
| An event: `https://luma.com/banff` | That one event |
| A phrase in **Search phrases**: `hackathon` | Up to 50 best matches from Luma's own search |

With **Add description, ticket types and categories** off, a category run over all 87 cities saved 2,752 Tech events in 196 seconds.

Example input:

```json
{
    "sources": ["https://luma.com/london", "https://luma.com/superteam"],
    "dateTo": "30 days",
    "pricing": "free",
    "excludeSoldOut": true,
    "maxItems": 200
}
```

On 6 November 2026 this input saved 200 events in 60 seconds, all from London, because sources are read in order. To spread a limit over your sources, set **Maximum results per source**.

### What data you get

Every event has the same fields. A value Luma does not show is `null`.

| Field | What it holds |
| --- | --- |
| `eventId`, `url`, `name` | Event ID, link and name |
| `startAt`, `endAt` | Start and end in UTC |
| `startAtLocal`, `timezone` | Start in the event's own time zone |
| `eventType`, `onlinePlatform` | `in-person`, `online` or `unknown`, then `zoom`, `meet` and similar |
| `venue`, `address`, `neighborhood`, `city`, `region`, `country`, `countryCode` | Place, as far as the host shows it |
| `addressHidden`, `latitude`, `longitude` | `addressHidden` is true when only guests see the address, and the coordinates are then approximate |
| `organizerName`, `organizerUrl`, `organizerWebsite` | The community or company calendar behind the event |
| `isFree`, `priceMin`, `priceMax`, `currency` | Price range in the event's own currency |
| `registrationStatus`, `isSoldOut`, `isNearCapacity`, `spotsRemaining`, `waitlistActive`, `requiresApproval` | Whether you can still get in, and how |
| `guestCount` | Guests going, the number on the event page, also when the host hides the guest list but ticket types show the count |
| `categories`, `language` | Luma categories and the language of the page |
| `description` | The organizer's text as plain text |
| `ticketTypes` | Name, price with tax as on the event page, capacity, registered guests, spots left, sales dates and whether it is on sale now |
| `registrationQuestions` | What guests are asked when they register |
| `coverImageUrl` | Link to the cover image |
| `changeType`, `changedFields`, `previousValues` | What changed since the last run |
| `source`, `sourceType`, `detailsFetched`, `retrievedAt` | Where the row came from and when |

A line that could not be used gets a free `notice` row that says why, and the run goes on.

One real row:

```json
{
    "recordType": "event",
    "eventId": "evt-PIL1ePXism2Ryt9",
    "url": "https://luma.com/banff",
    "name": "Banff Mountain Film Festival World Tour - San Francisco",
    "startAt": "2026-12-15T01:00:00.000Z",
    "endAt": "2026-12-15T04:30:00.000Z",
    "startAtLocal": "2026-12-14 17:00",
    "timezone": "America/Los_Angeles",
    "eventType": "in-person",
    "onlinePlatform": null,
    "venue": "Palace of Fine Arts Theatre",
    "address": "Palace of Fine Arts Theatre, 3301 Lyon St, San Francisco, CA 94123, USA",
    "addressHidden": false,
    "neighborhood": "Marina District",
    "city": "San Francisco",
    "region": "California",
    "country": "United States",
    "countryCode": "US",
    "latitude": 37.8018942,
    "longitude": -122.4483494,
    "organizerName": "WorkOS Events",
    "organizerUrl": "https://luma.com/calendar/cal-Z1tslEBMjjCh4fd",
    "organizerWebsite": "https://workos.com",
    "isFree": false,
    "priceMin": 30,
    "priceMax": 30,
    "currency": "USD",
    "registrationStatus": "open",
    "isSoldOut": false,
    "isNearCapacity": false,
    "spotsRemaining": null,
    "requiresApproval": false,
    "waitlistActive": false,
    "guestCount": 222,
    "categories": [
        "Arts & Culture"
    ],
    "description": "Welcome to the Banff Mountain Film Festival! Get ready for a night of jaw-dropping adventure films that will leave you inspired to conquer the great outdoors.\n\nThis in-person event will be held at the Palace of Fine Arts Theatre, where you can immerse yourself in stories of epic climbs, daring descents, and awe-inspiring landscapes. Grab your friends, grab some popcorn, and get ready for a cinematic journey like no other!\n\n--\n\nAdventure Report is a community of outdoor enthusiast storytellers. If you would like to get involved and volunteer for this event, please email info@adventure.report.\n\nAll sales are final. No refunds.\n\n--\n\nPresented by WorkOS\nWorkOS Event Code of Conduct",
    "ticketTypes": [
        {
            "name": "Standard",
            "isFree": false,
            "price": 30,
            "currency": "USD",
            "capacity": null,
            "registered": 222,
            "spotsRemaining": null,
            "isAvailable": true,
            "requiresApproval": false,
            "salesStartAt": null,
            "salesEndAt": null
        }
    ],
    "registrationQuestions": [
        {
            "label": "By registering, I agree to the WorkOS Event Code of Conduct.",
            "type": "terms",
            "required": true
        }
    ],
    "language": "en",
    "coverImageUrl": "https://images.lumacdn.com/uploads/gq/041b5623-3912-4e86-a832-5edfc7afaf42.jpg",
    "detailsFetched": true,
    "source": "https://luma.com/banff",
    "sourceType": "event",
    "changeType": null,
    "changedFields": [],
    "previousValues": null,
    "retrievedAt": "2026-11-06T03:26:43.875Z"
}
```

### How much does it cost?

You pay for each saved event. Description, ticket types and categories cost nothing extra. `notice` rows and cancelled events are free. Each run also has a start charge of $0.00005.

| Plan | Price per 1,000 events |
| --- | --- |
| Free | $4.00 |
| Starter | $3.60 |
| Scale | $3.20 |
| Business | $2.80 |

Example: all 1,112 San Francisco events cost $4.45 on the Free plan. After that first run, a daily check with 20 changes a day is 600 events a month, which costs $2.40.

Apify's Free plan includes $5 of credit every month. Use **Maximum results** and the maximum cost per run to stay within your budget.

### How to get new, sold-out and cancelled events every day

1. Add your cities or calendars to **Luma pages**.
2. Turn on **Only new, changed, sold-out and cancelled events**.
3. Set a **Monitor name**, for example `sf-events`. Use a different name for each list of sources or filters.
4. Save the input as a task and add a schedule.

The first run returns all matching events as `new`. Each later run returns only the differences, and you pay only for those. If a run stops at a limit, the next run returns what it missed.

In a test on 6 November 2026, the second San Francisco run half an hour after the first returned 3 rows: 2 events that had just filled up and 1 new event.

| `changeType` | What happened |
| --- | --- |
| `new` | The event is listed for the first time, or passes your filters for the first time |
| `changed` | The name, time, place, price, approval rule or near-capacity flag changed. `changedFields` and `previousValues` show what it was |
| `soldOut` | Registration moved from open to sold out or waitlist |
| `reopened` | Registration is open again |
| `cancelled` | Luma no longer has the event. This row is free |

Guest counts and spots left do not count as a change, because they move all day.

### How to find AI events in Berlin for the next month

Add `berlin` to **Luma pages**, pick AI in **Categories**, and set **Last day** to `30 days`. For a closer match add words to **Keywords**, for example `founder` or `hackathon`. Keywords look at the event name and the organizer.

On 6 November 2026 this gave 75 events in 23 seconds.

### Limits

- A city or coordinates cover about 70 km, so towns around the city are included. In the San Francisco run the farthest event was 68 km away. Use the `city` field to narrow the rows.
- After heavy use Luma can ask for a human check on its area search. This Actor does not solve such checks. It says so in a `notice` row, cities go on from their shorter city pages, and coordinates and categories are skipped for that run. Run it again later, or read fewer cities per run.
- Hosts, guests and their social accounts are left out on purpose. An event run from a person's own calendar has no organizer fields, which was 31% of the San Francisco run. The description is the organizer's own text and can mention people.
- Many hosts show the address to guests only, which was 36% of the San Francisco run. Online meeting links are never public.
- Picking a category is optional for hosts, so 14% of the San Francisco events had none.
- Cities show upcoming public events only. Past events come from calendars.
- Search phrases are ranked by the location of the server that runs the Actor.

### API and integrations

Start runs and read results through the [Apify API](https://docs.apify.com/api/v2), or connect the Actor to your tools with [integrations](https://docs.apify.com/platform/integrations). With change tracking on a schedule, a webhook can send each change to your own system.

### FAQ

**Do I need a Luma account?** No. The Actor reads public data without a login.

**Can I get host names, guest lists or contact details?** No. They are left out on purpose.

**Is this allowed?** The Actor reads public event data without a login. Luma's terms limit access to its supported interfaces, so check that your use fits them and the law where you work.

*This Actor is an independent tool with no connection to Luma. All trademarks belong to their owners.*

# Actor input Schema

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

City, calendar, category or event pages, one per line. Links and short forms both work: <code>https://luma.com/london</code>, <code>sf</code>, <code>San Francisco</code>, <code>https://luma.com/superteam</code>. For a place without a Luma city page use coordinates such as <code>54.6872,25.2797</code>. A city or coordinates return the events within about 70 km. A category page, or <code>https://luma.com/discover</code> for everything, is read across all Luma cities.

## `searchQueries` (type: `array`):

Phrases for Luma's own search, such as <code>AI hackathon</code>. Each phrase returns up to 50 best matches. Luma ranks them by the location of the server that runs this Actor, so use Luma pages and Keywords when you need one city.

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

The run stops after saving this many rows, so this also caps your cost. With change tracking, anything not saved is reported in the next run.

## `maxItemsPerSource` (type: `integer`):

Save at most this many rows from each city, calendar or search. A category or whole-Luma run counts each city separately. Use 0 for no limit.

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

Only events in these Luma categories. Applies to cities, coordinates and whole-Luma runs. Calendars and single events are not filtered by category.

## `dateFrom` (type: `string`):

Only events starting on or after this day, in the event's own time zone. Pick a date, or a length such as <code>7 days</code> to count forward from today.

## `dateTo` (type: `string`):

Only events starting on or before this day, in the event's own time zone. A length such as <code>30 days</code> gives a window that moves with a scheduled run.

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

In-person or online events. City feeds list in-person events, online events come from calendars and search.

## `pricing` (type: `string`):

Free or paid events. Luma counts an event as free when it has a free ticket, even if paid tickets exist too.

## `keywords` (type: `array`):

Keep only events whose name or organizer contains one of these words. Case does not matter.

## `excludeSoldOut` (type: `boolean`):

Leave out events that are sold out or only take a waitlist.

## `includeDetails` (type: `boolean`):

Reads each saved event once more for its full description, ticket types, categories, registration questions and language, at no extra charge. Turn it off for a faster run with fewer fields.

## `includePastEvents` (type: `boolean`):

Also reads the past events of each calendar. Cities show upcoming events only. Ignored with change tracking.

## `changesOnly` (type: `boolean`):

Compare each source with the previous run and return only the differences. The first run returns all matching events as new. The comparison is stored in a named key-value store in your own account.

## `monitorId` (type: `string`):

Name of the stored comparison. Use a different name for each schedule that has different sources or filters. If you change the filters, use a new name.

## Actor input object example

```json
{
  "sources": [
    "https://luma.com/london"
  ],
  "maxItems": 20,
  "maxItemsPerSource": 0,
  "eventType": "all",
  "pricing": "all",
  "excludeSoldOut": false,
  "includeDetails": true,
  "includePastEvents": false,
  "changesOnly": false,
  "monitorId": "default"
}
```

# Actor output Schema

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

No description

## `changes` (type: `string`):

No description

# 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 = {
    "sources": [
        "https://luma.com/london"
    ],
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("zerolag/luma-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 = {
    "sources": ["https://luma.com/london"],
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("zerolag/luma-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 '{
  "sources": [
    "https://luma.com/london"
  ],
  "maxItems": 20
}' |
apify call zerolag/luma-events-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,zerolag/luma-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/beFcTMbzRIaCgjs4y/builds/8lUOhGdBP6fxOM4eX/openapi.json
