# Luma Events Scraper (`tortuga/luma-scraper`) Actor

Scrape Luma (lu.ma) events from city, calendar, category or event URLs: start/end time, timezone, venue and coordinates, hosts, ticket prices, sold-out status and cover image.

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

## Pricing

from $0.50 / 1,000 event scrapeds

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

Scrape public events from **Luma** (luma.com, formerly lu.ma): city pages like luma.com/sf, community calendars, category pages like luma.com/ai, keyword search and single event links. Every event comes with start and end time, timezone, venue and coordinates (when the host shows them), calendar, hosts, price range, sold-out and waitlist status, guest count and cover image. Turn on details to add the full description and every ticket type with its price.

It reads Luma's own public JSON API, the same one the website uses. No browser, no login and no cookies, so runs are fast and cheap: 100 events take a few seconds.

**No start fee.** You pay per event saved, and nothing for empty runs.

### 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) |
| `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
}
```

### 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 attendee lists or host emails?

No. The actor collects public event information only: the event, its venue, the organising calendar, and hosts' public display names with their Luma profile links. It never collects guest lists, attendee names, featured guests, registration answers, or anyone's email or phone number. `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 personal data such as guest lists. 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.

# 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, https://luma.com/london), 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.

## `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,
  "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": [],
    "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": [],
    "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": [],
  "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/2cYL5WMHmOTM5A2CN/openapi.json
