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

Collects public events from Luma and returns event times, venue and location, ticket details, guest counts, calendar information, hosts and public profile links. Start from a city, category, calendar, single event or keyword search; data comes from Luma's unauthenticated JSON API.

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

## Pricing

from $5.05 / 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

**Returns:** one row per Luma event with `name`, `startAt`, `city`, `country`, `isFree`, `guestCount`, `hosts` and `url`.
**Input:** `{"startUrls":[{"url":"https://luma.com/sf"}],"maxItems":20,"includeDetails":true}`
**Best for:** building event lead lists, tracking tech and startup events in a city, monitoring organiser calendars and ticket prices.

```json
{
    "id": "evt-Gxrb7efa9lu5vw5",
    "name": "Fast Forward",
    "startAt": "2026-10-14T17:00:00.000Z",
    "city": "San Francisco",
    "isFree": true,
    "guestCount": 347,
    "url": "https://luma.com/fastforwardhack"
}
```

### What does Luma Events Scraper do?

Luma Events Scraper is a Luma scraper and Luma API alternative that collects public events from luma.com (formerly lu.ma). It returns one record per event with the name, start and end time, timezone, venue, address, coordinates, ticket information (free or paid, price, sold out, near capacity), guest count, the organising calendar with its socials and website, the hosts with their public profiles, and optionally the full description and ticket types.

You can start from the same places the site itself offers: a city page such as luma.com/sf, a category page such as luma.com/ai, a calendar page such as luma.com/genai-sf, a single event page, or a keyword search. You can also combine them, for example a category within a city, or a category around a latitude and longitude. No login is needed, and the Actor reads the public JSON data that the Luma website itself loads.

### What data can you get from Luma?

With details enabled, `registrationQuestions` contains public form definitions (id, label, type, required and options), never attendee answers. `locale` copies the event locale. `detailsFetched` is true after a detail response, false for listing-only or external rows and failed detail requests. An empty question array means no custom questions were published; null means details were unavailable.

With details enabled, each ticket type also includes its public `description`, copied verbatim. Missing or blank ticket descriptions are `null`; this text can explain what a ticket includes or how approval works.

Every record has the same set of fields. A value that Luma does not provide for an event is `null`. External events that a calendar links to (platform `external`) have no hosts, ticket types or description.

| Field | Description | Example |
|---|---|---|
| `id` | Stable Luma ID of the event (evt-...), or of the calendar item for external events. | evt-cQoVVZaVuGt0StV |
| `eventId` | Luma event API ID; null for external calendar entries. | evt-cQoVVZaVuGt0StV |
| `platform` | luma for events hosted on Luma, external for events a calendar links to elsewhere. | luma |
| `name` | Event name. | Open Intelligence Summit |
| `url` | Public event page (luma.com/slug), or the external URL for external events. | https://luma.com/digita-ghqh |
| `slug` | Event slug used in the Luma URL; null for external events. | digita-ghqh |
| `startAt` | Start time as ISO 8601 (UTC). | 2026-10-13T18:30:00.000Z |
| `endAt` | End time as ISO 8601 (UTC). | 2026-10-14T01:30:00.000Z |
| `timezone` | IANA timezone of the event. | America/Los_Angeles |
| `locationType` | offline, online or tbd. | offline |
| `eventType` | Luma event type, e.g. independent. | independent |
| `visibility` | Event visibility, public for listed events. | public |
| `venueName` | Venue name or street address when shown publicly. | Pier 48 |
| `fullAddress` | Full address when the host makes it public. | Pier 48, San Francisco, CA 94158, USA |
| `shortAddress` | Short address line. | Pier 48 |
| `city` | City of the event. | San Francisco |
| `region` | State or region. | California |
| `country` | Country name. | United States |
| `countryCode` | ISO country code. | US |
| `latitude` | Event latitude (approximate when the address is hidden). | 37.7469 |
| `longitude` | Event longitude (approximate when the address is hidden). | -122.3866 |
| `googlePlaceId` | Google place ID of the venue when public. | ChIJxxxxxxxx |
| `coverUrl` | URL of the event cover image. | https://images.lumacdn.com/uploads/example.png |
| `guestCount` | Number of guests registered, as reported by Luma. | 306 |
| `ticketCount` | Number of tickets issued, as reported by Luma. | 306 |
| `isFree` | True when the event is free. | true |
| `priceCents` | Lowest ticket price in minor currency units; null when free. | 2500 |
| `priceCurrency` | Currency code of the price. | usd |
| `priceIsFlexible` | True when guests choose what to pay. | false |
| `isSoldOut` | True when no tickets are left. | false |
| `spotsRemaining` | Tickets left when the host sets a capacity; null otherwise. | 12 |
| `isNearCapacity` | True when the event is almost full. | false |
| `requireApproval` | True when the host approves each guest. | true |
| `registrationAvailability` | Registration state, e.g. open. | open |
| `waitlistActive` | True when a waitlist is open. | false |
| `calendarId` | ID of the organising calendar. | cal-aibKRDXjMS2Dj9q |
| `calendarName` | Name of the organising calendar. | DigitalOcean Community Events |
| `calendarSlug` | Calendar slug; null for personal calendars. | digitalocean |
| `calendarUrl` | Link to the calendar page. | https://luma.com/digitalocean |
| `calendarIsPersonal` | True for a personal calendar. | false |
| `calendarIsVerified` | True when the calendar is verified by Luma. | false |
| `calendarPlan` | Luma plan of the calendar. | plus |
| `calendarDescription` | Short calendar description. | Keep track of all DigitalOcean events under one page |
| `calendarWebsite` | Calendar website. | https://www.digitalocean.com |
| `calendarInstagram` | Instagram handle. | thedigitalocean |
| `calendarLinkedin` | LinkedIn handle. | /company/digitalocean |
| `calendarTwitter` | Twitter/X handle. | digitalocean |
| `calendarYoutube` | YouTube handle. | d |
| `calendarTiktok` | TikTok handle. | example |
| `hosts` | Public hosts: id, name, username, profileUrl, bio, avatarUrl, isVerified, socials, website, timezone. | \[{"id": "usr-0qh333qMq4tTuNc", "name": "DigitalOcean", "username": "DigitalOcean"}] |
| `hostCount` | Number of hosts. | 1 |
| `detailsFetched` | Whether a full event detail response was received. | true |
| `locale` | Public event locale; null without details. | en |
| `registrationQuestions` | Public registration form definitions, without answers. | \[{"label":"Company","type":"text","required":true}] |
| `descriptionLinks` | Unique HTTP/HTTPS destinations in description link marks; null without details, empty when none. Destinations are not fetched. | \[] |
| `description` | Plain-text event description; null when includeDetails is off. | The argument is no longer ... |
| `ticketTypes` | Ticket types with price, capacity, spots remaining and nullable ticket-level description; null when includeDetails is off. | \[{"id": "ttype-FTaIGraJmLz3rQB", "name": "Standard", "type": "free"}] |
| `categories` | Luma categories of the event; null when includeDetails is off. | \[{"id": "cat-ai", "slug": "ai", "name": "AI"}] |
| `sourceKind` | Where the record came from: discover-place, category, calendar, event or global. | discover-place |
| `sourceSlug` | Slug of the city, category, calendar or event page that produced the record. | sf |
| `searchQuery` | Query input, echoed. | hackathon |
| `scrapedAt` | ISO timestamp of the run. | 2026-10-13T12:00:00.000Z |
| `sourceUrl` | Page the record came from. | https://luma.com/digita-ghqh |

### How to use Luma Events Scraper

1. Open the Actor in Apify Console and go to the Input tab.
2. Enter a start URL, or fill in a city, category, calendar or search query. With nothing filled in, the San Francisco city page is scraped.
3. Set `maxItems` to the number of events you want. The limit is shared by all sources in the run.
4. Leave `includeDetails` on if you want descriptions and ticket types; turn it off for a faster run.
5. Click Start, then export the dataset as JSON, CSV, Excel or XML when the run finishes.

City listings are upcoming. Categories combine with city or coordinates using `radiusKm`. Calendars support `period: "past"`. Search returns at most 50 matches per query.

### Input

| Field | Type | Required | Description |
|---|---|---|---|
| `startUrls` | array | No | Luma or lu.ma URLs: city, category, calendar or event pages. |
| `city` | string | No | Luma city slug or name such as `sf`, `london` or `San Francisco`. |
| `category` | string | No | One of ai, tech, crypto, climate, arts, books, family, fitness, food, games, running, wellness. |
| `calendar` | string | No | Calendar slug such as `genai-sf` or a `cal-` ID. |
| `query` | string | No | Free-text search over event names, at most 50 matches. |
| `queries` | string array | No | Additional searches, default empty; query runs first and all share maxItems. |
| `eventIds` | string array | No | Direct public evt- IDs, default empty; shares maxItems. |
| `period` | string | No | `future` (default) or `past`. Calendars only. |
| `latitude`, `longitude` | number | No | Centre for a category search without a city. |
| `radiusKm` | integer | No | Radius in km, 1-500, default 50. |
| `maxItems` | integer | No | Maximum events across all sources, 1-10000, default 100. |
| `includeDetails` | boolean | No | Fetch description, links, tickets, categories, locale and registration questions; default true. |
| `proxyConfiguration` | object | No | Proxy settings. Default: Apify Proxy. |

```json
{
    "city": "london",
    "category": "ai",
    "radiusKm": 50,
    "maxItems": 50,
    "includeDetails": true,
    "proxyConfiguration": { "useApifyProxy": true }
}
```

A page or city that does not exist is skipped with a clear message, and the run finishes with 0 items instead of failing. When several sources are given, they run in order and share the `maxItems` budget; the same event found twice is returned once.

Batch searches use `queries`, for example `{"queries": ["hackathon", "meetup"], "city": "london", "maxItems": 20}`. Each term uses the same source scope. `query` runs first when both fields are supplied, then additional terms in input order. Duplicate terms are removed without regard to case. The first search that produces an event supplies its `searchQuery`; an event matching later searches is saved only once.

For events already stored in your database, use `{"eventIds": ["evt-BlQwkRLguP9KuyU"], "maxItems": 1}`. Event IDs run after start URLs and before standalone sources. The `calendar` field accepts a calendar URL, slug or `cal-` ID. Neither form needs a login. A valid ID that no longer exists is skipped with a clear status message.

`descriptionLinks` contains the destinations of public HTTP/HTTPS links embedded in an event description. It preserves each destination as Luma returns it and removes repeats. It does not infer links from plain text, inspect external websites or extract private meeting links. Turn off `includeDetails` to make this field null; a fetched description with no links produces an empty array.

### Output

Each run writes one dataset item per event. This shortened record came from a local direct-ID run with details enabled. Seven questions were returned; only the first is shown:

```json
{
    "id": "evt-VMd5nQt9FGodKjX",
    "name": "Bay Area Frontier Research Club #27 | Robotics & Embodied AI: Feel or Think? (dinner + paper discussion @ Mission Robotics)",
    "startAt": "2026-10-15T00:30:00.000Z",
    "url": "https://luma.com/sxoqc4og",
    "detailsFetched": true,
    "locale": "en",
    "registrationQuestions": [
        {
            "id": "xk0vxjlw",
            "label": "Where do you work, and what's your role?",
            "type": "text",
            "required": true,
            "options": null
        }
    ],
    "sourceUrl": "https://luma.com/sxoqc4og"
}
```

The dataset can be exported as JSON, CSV, Excel, XML or RSS, or read through the API.

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

Luma Events Scraper is charged per result. You pay only for the events returned, and `maxItems` caps how many that can be. See the Pricing tab for the current price. Turning off `includeDetails` makes runs faster because it saves one request per event.

### Use with AI agents (MCP)

Connect Luma Events Scraper to Claude, Cursor or any MCP client through the Apify MCP server:

```json
{
    "mcpServers": {
        "apify": {
            "url": "https://mcp.apify.com/?tools=axiomworks/luma-events-scraper"
        }
    }
}
```

Example prompts:

1. "Use Luma Events Scraper to list the next 20 AI events in London with their start times and whether they are free."
2. "Get past events of the Luma calendar deepmind and tell me who hosted them."
3. "Search Luma for hackathon events and group them by city."

### Integrations and API

Run Luma Events Scraper from your own code with the Apify API. Set `APIFY_TOKEN` to your Apify API token (send it in the `Authorization` header, never in the URL).

**Python**

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("axiomworks/luma-events-scraper").call(run_input={"city": "london", "category": "ai", "maxItems": 50})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["name"], item["startAt"])
```

**JavaScript**

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });
const run = await client.actor('axiomworks/luma-events-scraper').call({ city: 'london', category: 'ai', maxItems: 50 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

**cURL**

```bash
curl -X POST "https://api.apify.com/v2/acts/axiomworks~luma-events-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"city": "london", "category": "ai", "maxItems": 50}'
```

Results can also be sent to Make, Zapier, n8n, Google Sheets or a webhook from the Integrations tab, and runs can be scheduled to track new events every day.

### FAQ

**How many events can I get?**
As many as Luma lists, up to 10,000 per run. Pagination stops at `maxItems` or the end of the feed.

**Why did my run return 0 results?**
The page, city or calendar you gave does not exist on Luma, or the search matched nothing. The status message of the run names the cause. Check the slug on luma.com and try again.

**Can I get past events?**
Yes, for calendars: set `calendar` (or a calendar start URL) and `period` to `past`. City, category and search results only show upcoming events.

**Are guests and attendees included?**
No. The Actor returns the public guest count, not the list of guests. Hosts and the organising calendar are included with their public profile data.

**Why are some fields null?**
Luma can hide addresses or omit profile fields. External events lack ticket and host data. Check `detailsFetched` for unavailable details.

**Does the address show the exact venue?**
Only when the host makes it public. Otherwise Luma shows the city and an approximate position, and the Actor returns exactly that.

**Do I need a proxy?**
Apify Proxy is on by default and is enough. Blocked requests are retried on a new IP automatically.

### Is it legal to scrape Luma?

The Actor collects only publicly available event data that Luma shows to anyone without logging in. Hosts and calendar owners appear with the public profile data shown on their event pages. You are responsible for using personal data such as host names and social handles in line with the laws that apply to you, including GDPR, and with Luma's terms. This is not legal advice.

Luma Events Scraper is an independent tool. It is not affiliated with, endorsed by or sponsored by Luma.

### Feedback

Found a bug or need a field that isn't here? Open an issue on the Issues tab and we'll look at it.

# Actor input Schema

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

Luma event, city, category or calendar pages, e.g. \[{"url":"https://luma.com/sf"}]. Also accepts URL strings or bare slugs such as sf. Sources share maxItems; use eventIds for evt- IDs. Omitted with no other source: San Francisco. Missing or blocked targets produce no error rows; try a known public page or retry later.

## `city` (type: `string`):

Luma city slug or name, e.g. sf, london or San Francisco. Omitted: no city filter; if all sources are omitted, San Francisco. Alone: upcoming city events. With category: that category within radiusKm. Unknown cities are skipped; try a city slug from Luma Discover.

## `category` (type: `string`):

Category slug, e.g. ai or tech; choose an enum value. Default empty: no category filter. Alone: worldwide upcoming events, soonest first. With city or both coordinates: within radiusKm. An empty result may need a wider radius or another category.

## `calendar` (type: `string`):

Public calendar slug, cal- ID or Luma calendar URL, e.g. genai-sf or https://luma.com/genai-sf. Omitted: no calendar source. Returns future events unless period=past. Missing or blocked calendars are skipped; try a known public calendar or another period.

## `query` (type: `string`):

Event-name search text, e.g. hackathon. Omitted: no keyword filter. Worldwide unless a city, category, calendar or start URL scopes it. Luma returns at most 50 matches per query; try a broader term or remove filters for empty results.

## `queries` (type: `array`):

Additional event-name searches, e.g. \["hackathon", "meetup"]. query runs first, then distinct queries in order, with the same city/category/calendar/URL scope. At most 50 matches per query from Luma; maxItems is shared and duplicate events are saved once. Default empty.

## `period` (type: `string`):

Calendar event period, e.g. past. Allowed: future (default) or past. Only filters calendars; discover and search remain upcoming. If a calendar has no future events, try past.

## `latitude` (type: `number`):

Category search centre latitude, e.g. 40.71; -90 to 90. Omitted: no coordinate centre. Requires longitude and a category; used only without city. With city, the city centre takes precedence.

## `longitude` (type: `number`):

Category search centre longitude, e.g. -74.0; -180 to 180. Omitted: no coordinate centre. Requires latitude and a category; used only without city. With city, the city centre takes precedence.

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

Category search radius in kilometres, e.g. 40; 1-500, default 50. Applies with city or both latitude and longitude. Does not filter a city-only listing. Increase it if a local category returns no events.

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

Total unique events to save across all URLs, eventIds, cities, categories, calendars and searches, e.g. 7; 1-10000, default 100. Stops at this shared limit when enough events exist; duplicate IDs are saved once. Only saved results are charged.

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

Whether to include event details, e.g. false for a faster listing. Default true: fetch description, descriptionLinks, ticketTypes, categories, locale and registrationQuestions. False leaves detail fields null. detailsFetched reports success. Direct event inputs need no extra request; external entries have none.

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

Proxy settings, e.g. {"useApifyProxy":true} (default). Uses Apify datacenter proxy for public Luma requests and retries blocks on fresh sessions. For local testing use {"useApifyProxy":false}; if requests remain blocked, retry later or change proxy settings.

## `eventIds` (type: `array`):

Public Luma evt- IDs to fetch directly, e.g. evt-BlQwkRLguP9KuyU. Default empty. Runs after startUrls and shares maxItems with all sources. Missing or blocked IDs are skipped; no placeholder records.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://luma.com/sf"
    }
  ],
  "category": "",
  "queries": [],
  "period": "future",
  "radiusKm": 50,
  "maxItems": 20,
  "includeDetails": true,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "eventIds": []
}
```

# Actor output Schema

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

Dataset with one item per result, in the order found.

# 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"
        }
    ],
    "maxItems": 20,
    "includeDetails": true,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

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

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

```

## MCP server setup

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