# Luma Events Scraper: lu.ma Hosts & Tickets (`tortuga/luma-scraper`) Actor

Luma (lu.ma) events from any city, calendar, category or keyword: name, start and end time, venue address with coordinates, hosts with profile links, ticket price range, sold-out and waitlist status, spots left and guest count. Add full descriptions and ticket types. $0.50 per 1,000 events.

- **URL**: https://apify.com/tortuga/luma-scraper.md
- **Developed by:** [Trevor Ortega](https://apify.com/tortuga) (community)
- **Categories:** Lead generation, Social media
- **Features:** Limited permissions
- **Stats:** 4 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 1,000 events

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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: lu.ma Hosts & Tickets

Get the upcoming events of any Luma (luma.com, formerly lu.ma) city page, community calendar, category page or keyword search as one clean row each: name, start and end time with timezone, venue address with coordinates, organising calendar, hosts with their Luma profile links, ticket price range, sold-out and waitlist status, spots left and guest count. Turn on **Include event details** for the full description and every ticket type with its price.

The Actor reads Luma's own public JSON API, so there is no browser, login or cookie, and 100 events take a few seconds. **$0.50 per 1,000 events**, no start fee, nothing charged for empty runs.

**What you get**

- **Event:** name, URL, start and end time (UTC) with timezone, online or in person, cover image
- **Place:** venue name, full address, city, country, latitude / longitude, Google Place ID
- **Organisers:** calendar (name, website, verified flag) and hosts with Luma profile links
- **Host and guest socials** (optional, free): each host's bio and the Instagram, X, LinkedIn, TikTok, YouTube and website links shown on their Luma profile, plus the featured guests Luma shows on the event page
- **Tickets:** free or paid, price range and currency, sold out, waitlist, approval required, spots remaining, guest count
- **Details** (optional): full description as text, Markdown and HTML, every ticket type with price and capacity, categories

**Try it:** the input is prefilled with `https://luma.com/sf`. Click **Start** and San Francisco's upcoming events (usually under 100) arrive in about 10 seconds, for a few cents.

**Sample output** (one event, trimmed; the full field list and example follow below):

```json
{
  "name": "MAESE PLACE: A Spanish Affair",
  "url": "https://luma.com/13udy1ot",
  "startAt": "2026-11-05T21:30:00Z",
  "endAt": "2026-11-05T23:30:00Z",
  "timezone": "America/New_York",
  "venue": { "name": "DOORS NYC", "address": "DOORS NYC, 43 Mercer St, New York, NY 10013, USA", "latitude": 40.72157, "longitude": -74.00131 },
  "hosts": [{ "name": "DOORS NYC", "username": "doorsnyc", "url": "https://luma.com/user/doorsnyc" }],
  "isFree": true,
  "registrationStatus": "open",
  "spotsRemaining": 34,
  "guestCount": 216
}
```

### What data does Luma Events Scraper extract?

| Field | Description |
|---|---|
| `id` | Luma event id (`evt-...`) |
| `url`, `slug` | Event page, e.g. `https://luma.com/demo-night-sept2026` |
| `name` | Event title |
| `startAt`, `endAt` | ISO 8601 in UTC (`2026-09-15T00:30:00Z`) |
| `timezone` | Event timezone, e.g. `America/Los_Angeles` |
| `isOnline`, `locationType` | `offline`, `zoom`, `google_meet`, ... (`unknown` if the host has not set a location) |
| `venue` | `name`, `address`, `shortAddress`, `city`, `region`, `country`, `countryCode`, `latitude`, `longitude`, `googlePlaceId` |
| `addressHidden` | `true` when the host shows the address to registered guests only; then only city/region/country are filled |
| `calendar` | Organising calendar: `id`, `name`, `slug`, `url`, `website`, `isVerified`, `avatarUrl` |
| `hosts` | List of `{name, username, url}` (public Luma profile links). With **Include host social links** each host also has `bio`, `avatarUrl`, `instagram`, `twitter`, `linkedin`, `tiktok`, `youtube`, `website` (full URLs, `null` when the profile shows none) |
| `featuredGuests` | Only with **Include featured guests**: up to 10 guests Luma shows on the event page, each with the same fields as a host with details (`name`, `username`, `url`, `bio`, `avatarUrl` and social links) |
| `coverImageUrl` | Event cover image |
| `isFree`, `priceMin`, `priceMax`, `currency` | Ticket price range (0 for free events) |
| `isSoldOut`, `isWaitlist`, `registrationStatus` | `open`, `waitlist`, `sold_out`, ... |
| `spotsRemaining`, `isNearCapacity` | Capacity signals where Luma exposes them |
| `requiresApproval` | Registration needs host approval |
| `guestCount` | Aggregate "going" number, only when the host shows the guest list publicly |
| `tags` | Calendar tags (calendar pages) |
| `featuredCity`, `eventType`, `recurrenceId`, `visibility`, `platform` | Extra metadata. `platform` is `external` for events a calendar links to on another site |
| `sourceUrl`, `scrapedAt` | Where and when the item was scraped |

With **Include event details** on, each event also gets:

| Field | Description |
|---|---|
| `descriptionText`, `descriptionMarkdown`, `descriptionHtml` | Full description in three formats |
| `ticketTypes` | `{name, type, isFree, price, minPrice, isFlexiblePrice, currency, isSoldOut, isAvailable, requiresApproval, membersOnly, capacity, spotsRemaining, salesStartAt, salesEndAt, description}` |
| `ticketPriceMin`, `ticketPriceMax` | Range over available paid ticket types |
| `registrationQuestionsCount` | How many questions the registration form asks (never the answers) |
| `categories` | Luma categories, e.g. `AI`, `Tech`, `Food & Drink` |
| `waitlistEnabled`, `waitlistStatus`, `hasAvailableTickets`, `refundPolicy`, `socialImageUrl`, `locale` | Registration extras |

### How to scrape Luma events

1. Paste Luma links into **Start URLs**: a city (`https://luma.com/nyc`), a calendar (`https://luma.com/genai-sf`), a category (`https://luma.com/ai`), `https://luma.com/discover`, or event links. `lu.ma` links work too.
2. Or type city slugs into **Cities** (`sf`, `nyc`, `london`, `berlin`, `tokyo`, ...), or a keyword into **Search query**.
3. Set **Max events** to cap the run and the cost. Turn on **Include event details** if you need descriptions and ticket types.
4. Click **Start** and export the dataset as JSON, CSV or Excel, or read it through the API.

#### Supported inputs

| Input | What you get |
|---|---|
| City page `luma.com/sf` or Cities `["sf"]` | Every upcoming event Luma lists for the city |
| Calendar `luma.com/<calendar>` or `luma.com/calendar/cal-...` | All upcoming events of the calendar; past events too with **Include past events** |
| Category `luma.com/ai`, `luma.com/tech`, ... | Category events around each city in **Cities** (or around Luma's default city) |
| `luma.com/discover` | Events of each city in **Cities**, otherwise the city Luma picks for the server's location |
| Event `luma.com/abc123xy`, `luma.com/event/evt-...` | That event |
| Search query only | Luma-wide keyword search (Luma returns up to 50 events per keyword) |

### Input example

```json
{
  "startUrls": [
    { "url": "https://luma.com/sf" },
    { "url": "https://lu.ma/genai-sf" }
  ],
  "cities": ["london"],
  "searchQuery": "",
  "includePastEvents": false,
  "includeDetails": false,
  "maxItems": 200
}
```

### Output example

```json
{
  "id": "evt-0WzHsrNeVjAEwJV",
  "url": "https://luma.com/le6wfcyu",
  "slug": "le6wfcyu",
  "name": "YWS x Grand Cru Chicago: Deep-cut Northern Italian Grapes (night 1)",
  "startAt": "2026-09-16T00:00:00Z",
  "endAt": "2026-09-16T02:00:00Z",
  "timezone": "America/Chicago",
  "isOnline": false,
  "locationType": "offline",
  "venue": {
    "name": "Grand Cru Chicago",
    "address": "Grand Cru Chicago, 1119 W Grand Ave, Chicago, IL 60642, USA",
    "shortAddress": "1119 W Grand Ave, Chicago",
    "city": "Chicago",
    "cityState": "Chicago, IL",
    "sublocality": "West Loop",
    "region": "Illinois",
    "country": "United States",
    "countryCode": "US",
    "latitude": 41.8909047,
    "longitude": -87.655434,
    "googlePlaceId": "ChIJlaObfsMtDogR6Ho-WR5p5Tk"
  },
  "addressHidden": false,
  "calendar": {
    "id": "cal-DbejUUA2IVnrWqF",
    "name": "YWS Chicago",
    "slug": null,
    "url": "https://luma.com/calendar/cal-DbejUUA2IVnrWqF",
    "isPersonal": false,
    "website": "https://www.youngwinesociety.com/chicago",
    "isVerified": true,
    "avatarUrl": "https://images.lumacdn.com/calendars/bz/30910dcb-9089-4e2d-869b-748959c2605b.png"
  },
  "hosts": [
    { "name": "Young Wine Society Chicago", "username": "YWSChicago", "url": "https://luma.com/user/YWSChicago" }
  ],
  "coverImageUrl": "https://images.lumacdn.com/uploads/js/f338b4df-fb16-4336-a960-541ea5dabb53.jpg",
  "isFree": false,
  "priceMin": 38.25,
  "priceMax": 45.0,
  "currency": "USD",
  "isSoldOut": true,
  "isWaitlist": true,
  "registrationStatus": "waitlist",
  "spotsRemaining": 0,
  "isNearCapacity": false,
  "requiresApproval": false,
  "guestCount": null,
  "tags": [],
  "categories": ["Food & Drink"],
  "visibility": "public",
  "platform": "luma",
  "sourceUrl": "https://lu.ma/le6wfcyu",
  "scrapedAt": "2026-09-14T20:12:27+00:00",
  "descriptionText": "Deep-cut Northern Italian Grapes 🍷\nAs summer winds down, we're diving into Northern Italy's lesser-known grapes...",
  "ticketTypes": [
    { "name": "Standard", "type": "fiat-price", "isFree": false, "price": 45.0, "currency": "USD", "isAvailable": true, "membersOnly": false },
    { "name": "Vintage Member", "type": "fiat-price", "isFree": false, "price": 38.25, "currency": "USD", "isAvailable": false, "membersOnly": true }
  ],
  "registrationQuestionsCount": 0
}
```

### Monitor changes on a schedule

Turn on **Only new or changed items** to watch a city, calendar or search: each run remembers what earlier runs returned and outputs only events that are new or whose date and time, ticket price, sold-out flag, registration status (open, waitlist, sold out) or venue changed. Unchanged events are dropped before any event detail call, so they are not charged. **Max items** then sets how many events are checked per run, so set it high enough to cover the whole city or calendar (e.g. 200 for New York). Save the input as a task and add a Schedule in Apify (for example daily); give each watch its own **Monitoring key** if several schedules use the same input. Every output item has `changeType` (`new` or `changed`), and changed items have `previousValues` with the old values, e.g. `{"registrationStatus": "open"}` for an event that just moved to a waitlist.

### How much does it cost to scrape Luma?

Pay per event, no start fee and no monthly rental:

- **$0.0005 per event** saved (**$0.50 per 1,000 events**).
- **+$0.001 per event** when **Include event details** is on.

Apify's free plan ($5 of monthly credit) covers about 10,000 events a month, or about 3,300 with details. Platform usage is small because the actor only makes JSON API calls (one request per 50 events, plus one per event for details).

### Does it work without a Luma account?

Yes. Everything comes from Luma's public API, which the Luma website calls for logged-out visitors. You do not need a Luma account, cookies or an API key (Luma's official API requires a paid Luma Plus plan and only covers calendars you manage).

### How many events can I get from a city?

All of them: the actor follows Luma's pagination until the city's list ends (San Francisco lists about 80 upcoming events, New York about 110). For more, add more cities, add the city's big community calendars as start URLs, or scrape category pages around a city. Keyword search on its own is limited by Luma to 50 events per keyword.

### Can I scrape past events?

Yes, for calendars. Turn on **Include past events** and the actor scrapes the calendar's upcoming events and then its past events, newest first. City and category pages on Luma only show upcoming events.

### Can I get host social links and featured guests?

Yes. Turn on **Include host social links** to add each host's short bio and the Instagram, X, LinkedIn, TikTok, YouTube and website links that their Luma profile shows publicly. Turn on **Include featured guests** to add the up to 10 guests Luma shows on the event page (name, Luma profile link and the same public social links). Featured guests are mostly attendees, and speakers when the host adds them as guests; Luma shows them only on events whose host makes guests public. Both options read data Luma already returns with the event, so they cost no extra requests and no extra charge. Profiles that show no links give `null`.

### Can I get full attendee lists or emails?

No. The actor never collects the full guest list, registration answers, or anyone's email or phone number, and it never logs in. `guestCount` is the aggregate number Luma shows on public events.

### Integrations and API

Run it on a schedule and send new events to Google Sheets, Airtable, Slack, Zapier, Make or n8n, or call it from Python or Node.js with the Apify client. The **API** tab has ready-made snippets.

### Is it legal to scrape Luma?

This actor reads publicly visible event listings, the same information anyone sees on luma.com without logging in, and it skips full guest lists, emails and phone numbers. Host and guest names and social links are exported only when you turn on the options for them, and only as far as the person's Luma profile shows them publicly. You are responsible for how you use the data and for complying with Luma's terms and the laws that apply to you (for example GDPR if you process hosts' names in the EU).

### Support

Found a bug or need a field? Open an issue in the **Issues** tab. The actor is checked against the live site every day.

### Related scrapers

- [Viator Scraper](https://apify.com/tortuga/viator-scraper): Tours, Prices, Ratings & Reviews
- [Eventbrite Scraper](https://apify.com/tortuga/eventbrite-scraper): Events, Tickets & Organizers
- [Product Hunt Scraper](https://apify.com/tortuga/producthunt-scraper): Launches, Upvotes & Makers
- [Y Combinator Scraper](https://apify.com/tortuga/ycombinator-scraper): YC Companies & Founders
- [Crunchbase Scraper](https://apify.com/tortuga/crunchbase-scraper): Companies, Funding & Investors

### Found it useful?

A ★ review on this Actor's Apify Store page helps other users find it and tells us what to improve. Issues and feature requests are welcome in the Actor's **Issues** tab.

# Actor input Schema

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

Luma pages to scrape (luma.com and lu.ma links both work): city pages (https://luma.com/sf, https://lu.ma/nyc), calendar/community pages (https://luma.com/genai-sf, https://luma.com/calendar/cal-…), category pages (https://luma.com/ai, https://luma.com/tech; searched around the Cities below, or around Luma's default city), https://luma.com/discover, and single event URLs (https://luma.com/abc123xy or https://luma.com/event/evt-…). Optional if you fill in Cities or Search query.

## `cities` (type: `array`):

Luma city slugs, as in luma.com/<slug>: sf, nyc, london, berlin, chicago, toronto, singapore, bangalore, ... Every upcoming event Luma lists for the city is scraped. If a Start URL is a category page (e.g. luma.com/ai), the category is searched around these cities instead.

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

Keyword filter such as 'hackathon', 'yoga' or 'blockchain'. Applied to city, category and calendar pages. On its own (no Start URLs or Cities) it searches all of Luma; Luma returns at most 50 events per keyword search.

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

For calendar / community pages, also scrape past events (newest first) after the upcoming ones. City and category pages only list upcoming events.

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

Stop after this many events in total (across all inputs). Keeps cost predictable.

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

Also fetch every event for the full description (text, Markdown and HTML), ticket types with prices, currency and sold-out state, whether registration requires approval, the number of registration questions (never the answers), categories, and waitlist status. One extra request per event, charged as a separate 'detail' event.

## `includeHostDetails` (type: `boolean`):

Add each host's short bio, avatar and the social links shown publicly on their Luma profile (Instagram, X, LinkedIn, TikTok, YouTube, website). No extra requests and no extra charge. Off by default.

## `includeFeaturedGuests` (type: `boolean`):

Add the guests Luma shows on the event page (up to 10 per event): name, Luma profile link and the social links shown publicly on their profile. They are mostly attendees, and speakers when the host adds them. Only when the host shows guests publicly. No extra requests and no extra charge. Off by default.

## `onlyNewOrChanged` (type: `boolean`):

Remember what earlier runs of this search returned and output only new events or events whose date, ticket price, sold-out / waitlist status or venue changed. Use with a Schedule; unchanged events are not charged. With this on, Max items is the number of events checked per run, so set it to cover the whole city or calendar.

## `monitoringKey` (type: `string`):

Name for this watch, so several schedules on the same search stay separate; defaults to a key derived from the search input

## `proxyConfiguration` (type: `object`):

Luma's public API works from datacenter IPs, so the default Apify datacenter proxy is enough. Switch to RESIDENTIAL only if you see 403 or 429 errors.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://luma.com/sf"
    }
  ],
  "cities": [],
  "includePastEvents": false,
  "maxItems": 100,
  "includeDetails": false,
  "includeHostDetails": false,
  "includeFeaturedGuests": false,
  "onlyNewOrChanged": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (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 = {
    "startUrls": [
        {
            "url": "https://luma.com/sf"
        }
    ],
    "cities": [],
    "includeHostDetails": false,
    "includeFeaturedGuests": false,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("tortuga/luma-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": [{ "url": "https://luma.com/sf" }],
    "cities": [],
    "includeHostDetails": False,
    "includeFeaturedGuests": False,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("tortuga/luma-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": [
    {
      "url": "https://luma.com/sf"
    }
  ],
  "cities": [],
  "includeHostDetails": false,
  "includeFeaturedGuests": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call tortuga/luma-scraper --silent --output-dataset

```

## MCP server setup

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