# Luma Event Scraper (`studious_allergy_mig/luma-event-scraper`) Actor

Extract structured event data from lu.ma public event and calendar pages — name, dates, venue, price, organizer and more. One dataset item per event.

- **URL**: https://apify.com/studious\_allergy\_mig/luma-event-scraper.md
- **Developed by:** [Conor G](https://apify.com/studious_allergy_mig) (community)
- **Categories:** Lead generation, Automation, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

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

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Luma Event Scraper — scrape lu.ma events into structured data

A Luma event scraper that turns lu.ma into structured data: event pages, organizer calendars, and city pages, all in one run. Give it an event link, an organizer's calendar link, or a city page like `lu.ma/sf`, and get back one dataset row per event: name, dates, venue, price, organizer, tags, and more.

Built for **reliability first**. It reads the same structured data lu.ma's own app renders from — not brittle CSS selectors — so it keeps working as the site's visual design changes.

### What it extracts

For every event, you get:

| Field | Description |
|---|---|
| `url` | Canonical event page URL |
| `eventId` | Luma's internal event ID |
| `name` | Event title |
| `description` | Full event description as plain text |
| `startAt` / `endAt` | ISO 8601 start/end datetimes |
| `timezone` | IANA timezone of the event |
| `isVirtual` | Whether the event is online/hybrid |
| `venueName`, `address`, `city`, `region`, `country` | Location details, when public |
| `coverImageUrl` | Event cover image |
| `isFree`, `priceDisplay`, `spotsRemaining`, `isSoldOut` | Ticket/pricing info as shown on the page |
| `organizerName`, `organizerSlug`, `organizerWebsite` | The hosting calendar/organizer |
| `organizerSocials` | Public organizer social handles (Twitter/X, Instagram, LinkedIn, TikTok, YouTube) |
| `tags` | Category tags (e.g. Tech, Crypto, Music) |
| `scrapedAt` | Timestamp of extraction |

#### Sample output

```json
{
  "url": "https://lu.ma/runway-i8gw",
  "eventId": "evt-A7mOelcMzgsO5kt",
  "name": "Inside Runway: NYC Industry Night",
  "description": "Join us for a night of mingling, pizza and drinks at Runway's NYC office. Meet the Runway team and network with other creatives and industry talent.",
  "startAt": "2026-07-29T22:00:00.000Z",
  "endAt": "2026-07-30T00:00:00.000Z",
  "timezone": "America/New_York",
  "isVirtual": false,
  "venueName": null,
  "address": null,
  "city": "New York",
  "region": "New York",
  "country": "United States",
  "coverImageUrl": "https://images.lumacdn.com/uploads/mu/475dfd13-54a9-44e9-8b2c-d0dd723c6a35.png",
  "isFree": false,
  "priceDisplay": "Free",
  "spotsRemaining": null,
  "isSoldOut": false,
  "organizerName": "Runway",
  "organizerSlug": "runway",
  "organizerWebsite": "https://runwayml.com",
  "organizerSocials": {
    "twitter": "runwayml",
    "instagram": "runwayapp",
    "linkedin": "/company/runwayml",
    "youtube": "runwayml"
  },
  "tags": ["Tech"],
  "scrapedAt": "2026-07-29T07:55:37.400Z"
}
```

This is real output from a live run against `lu.ma/runway-i8gw`. Note `venueName` and `address` are `null` here — the organizer didn't make the exact address public on the page, so the actor doesn't have it either. That's typical, not a bug.

### Input

| Field | Type | Description |
|---|---|---|
| `startUrls` | array (required) | lu.ma URLs to scrape. See below for the three supported kinds. |
| `maxEvents` | integer | Stop after this many unique events have been scraped. Leave empty for no limit. |
| `dateFrom` / `dateTo` | string | Optional ISO date bounds — only events starting in this window are kept. |
| `maxConcurrency` | integer | Parallel page fetches (default 5). Kept modest to be respectful of lu.ma. |
| `maxRequestRetries` | integer | Retries per page before it's skipped with a warning (default 3). |

#### Supported URL types

1. **Event pages** — `https://lu.ma/on-mercury-sf` — scraped directly.
2. **Calendar / organizer pages** — `https://lu.ma/mercuryevents` — the actor discovers that organizer's listed events and scrapes each one.
3. **City or category discovery pages** — `https://lu.ma/sf`, `https://lu.ma/tech` — the actor discovers the events shown on that page and scrapes each one.

Mix and match all three in one `startUrls` list.

#### Example input

```json
{
  "startUrls": [
    { "url": "https://lu.ma/sf" },
    { "url": "https://lu.ma/mercuryevents" }
  ],
  "maxEvents": 100,
  "maxConcurrency": 5
}
```

### Use cases

- **Event marketing** — find relevant tech/community events in a city to sponsor, speak at, or exhibit at.
- **Community research** — track what a specific organizer, accelerator, or DAO is running over time.
- **Market mapping** — build a dataset of event density, pricing, and topics across cities or categories.
- **Lead generation** — identify active event organizers in a niche as partnership or outreach targets.

### How it works (and why it's reliable)

Lu.ma is built on Next.js and server-renders each public page with a full JSON snapshot of the page's data embedded in a `__NEXT_DATA__` script tag. This actor reads that JSON directly instead of scraping visible HTML/CSS. That means:

- It survives lu.ma redesigning its page layout or CSS classes.
- Field extraction (dates, prices, organizer info) is exact — it comes from the same data lu.ma's own frontend renders from, not fragile text parsing.
- No headless browser is required for the documented page types, which makes runs faster and cheaper.

Every page fetch is retried on failure; a page that can't be parsed is skipped with a logged warning rather than crashing the run. Events are deduplicated by their lu.ma event ID, so the same event linked from multiple discovery pages is only saved once. The run ends with a summary log of events scraped vs. pages that failed or were skipped, and only exits with a failure status if **every** input page failed.

### Limitations (honest, by design)

- **No attendee/guest-list data.** This actor only reads public event/calendar/discovery pages. It does not, and will not, extract guest lists, RSVPs, or any data behind a login.
- **No login, no CAPTCHA bypassing.** Private or invite-only events are out of scope.
- **Discovery pages return what lu.ma renders server-side.** Very large calendars/cities that lu.ma paginates client-side may not surface every historical event in one page load; re-run periodically to pick up new listings, or supply direct event/calendar URLs for anything missed.
- **Fields depend on what the organizer made public.** If an organizer hides the exact address or ticket price, this actor won't have it either — it reads only what lu.ma itself shows to a visitor.

### FAQ

**Is it legal to scrape lu.ma?**
This actor only reads public pages — the same event, calendar, and city pages anyone can open in a browser without logging in. It doesn't access private events, guest lists, or anything behind authentication. You're responsible for how you use the data (e.g. respecting an organizer's own terms if you republish their content), but the extraction itself is limited to public information by design.

**What does it cost to run?**
You pay per event returned (pay-per-result), not per page crawled. See the Pricing tab on this actor's page for the current rate. A run against a single event page or a small calendar costs very little; a large discovery page with hundreds of events costs proportionally more.

**How do I run this on a schedule?**
In the Apify Console, open this actor, save an input as a **Task**, then add a **Schedule** to that task (e.g. daily or weekly). Each scheduled run appends new events to a fresh dataset, so you can diff runs to see what's new.

**Can I get a field that isn't listed here?**
Only if lu.ma itself shows it on the public page — this actor doesn't invent data. If you need a specific field lu.ma displays that isn't in the output above, open an Issue on the actor's Issues tab and it'll get evaluated.

**Does it work on lu.ma calendars outside tech (music, sports, etc.)?**
Yes — the actor doesn't filter by category. Any public lu.ma event, calendar, or discovery page works the same way; `lu.ma/tech` and `lu.ma/sf` are just examples.

### Output

One dataset item per event — pay-per-result friendly. Use the **Events** dataset view in the Apify Console for a quick table (name, dates, city, price, organizer), or export the full dataset as JSON/CSV/Excel for further analysis.

# Actor input Schema

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

lu.ma URLs to scrape. Supports three kinds: (1) individual event pages, e.g. https://lu.ma/on-mercury-sf, (2) calendar/organizer pages, e.g. https://lu.ma/mercuryevents, and (3) city or category discovery pages, e.g. https://lu.ma/sf or https://lu.ma/tech. Calendar and discovery pages are crawled for event links, which are then scraped individually.

## `maxEvents` (type: `integer`):

Maximum number of distinct events to scrape across the whole run. Once this many unique events have been saved, the run stops enqueuing new event pages. Defaults to 100 so a first run stays fast and predictable; clear it for no limit.

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

Only keep events starting on or after this date. Accepts an ISO date/datetime, e.g. 2026-01-01 or 2026-01-01T00:00:00Z.

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

Only keep events starting on or before this date. Accepts an ISO date/datetime, e.g. 2026-12-31.

## `maxConcurrency` (type: `integer`):

Maximum number of pages fetched in parallel. Kept modest by default to be respectful of lu.ma's servers.

## `maxRequestRetries` (type: `integer`):

How many times to retry a page that fails to load or parse before skipping it with a warning.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://lu.ma/sf"
    }
  ],
  "maxEvents": 100,
  "maxConcurrency": 5,
  "maxRequestRetries": 3
}
```

# 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://lu.ma/sf"
        }
    ],
    "maxEvents": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("studious_allergy_mig/luma-event-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://lu.ma/sf" }],
    "maxEvents": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("studious_allergy_mig/luma-event-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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://lu.ma/sf"
    }
  ],
  "maxEvents": 100
}' |
apify call studious_allergy_mig/luma-event-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=studious_allergy_mig/luma-event-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/3kC2S9JH4yQcpgHJY/builds/E6ergRfaLzlufqWtq/openapi.json
