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

Collect public Luma events by city, category, calendar or exact URL, enrich event details, and track reliable NEW, UPDATED and confirmed ENDED changes.

- **URL**: https://apify.com/luminar/luma-events-scraper-monitor.md
- **Developed by:** [Luka](https://apify.com/luminar) (community)
- **Categories:** Social media, Marketing
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.05 / 1,000 luma 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?

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

Collect public Luma events by city, category, calendar, or exact event URL. Get clean event rows with stable identities, enrich public details, or safely track `NEW`, `UPDATED`, and confirmed `ENDED` changes across scheduled runs.

### 🚀 Start in 60 seconds

The default collects upcoming San Francisco events. Copy this input into the Actor, press **Start**, and open the Dataset:

```json
{
  "workflow": "collect",
  "citySlugs": ["sf"],
  "detailLevel": "core",
  "maxResults": 100
}
```

Every successful event has a stable `luma:event:<event-id>` identity, canonical URL, start/end time, timezone, location, registration context, organizer calendar, and source-published fields. Missing optional fields remain `null`; nothing is guessed.

### 🎯 Choose the right workflow

| Goal | Choose | Result |
|---|---|---|
| Export current events | `workflow: collect` + `detailLevel: core` | Fast normalized event rows |
| Get descriptions, categories and ticket types | `workflow: collect` + `detailLevel: detailed` | Public detail-enriched rows, up to 100 events |
| Track changes | `workflow: monitor` | Only delivered `NEW`, `UPDATED`, and confirmed `ENDED` changes |

For monitoring, schedule the same input and keep the same `stateNamespace`. The first run creates a baseline by default. Repeat runs compare the current complete scope with that baseline; one missing observation never ends an event.

### 📦 What you get

![Actual normalized Luma event rows with stable identities and explicit coverage](./assets/readme/luma-events-dataset.png)

| Group | Fields |
|---|---|
| Identity | `stableId`, `sourceId`, `eventId`, `slug`, `url` |
| Event | `title`, `description`, `startAt`, `endAt`, `timezone`, `eventType`, `visibility` |
| Location | `locationType`, `fullAddress`, `address`, `city`, `region`, `country`, `countryCode`, `latitude`, `longitude`, `virtualUrl` |
| Registration | `isFree`, `price`, `maxPrice`, `currency`, `isSoldOut`, `spotsRemaining`, `requiresApproval`, `registrationAvailability`, `waitlistActive` |
| Organizer | `calendarId`, `calendarName`, `calendarUrl`, public social links, `hosts` |
| Detail | `categoryNames`, `featuredGuests`, `ticketTypes`, media URLs |
| Audit | `observedAt`, `sourceTargets`, `sourceClass`, `coverageStatus` |

Example event:

```json
{
  "recordType": "event",
  "stableId": "luma:event:evt-NRWoIJ0rk2BEm8a",
  "url": "https://luma.com/a16zgrokbotbuildnight",
  "title": "Grok Bot build night for women",
  "startAt": "2026-09-04T00:00:00.000Z",
  "timezone": "America/Los_Angeles",
  "city": "San Francisco",
  "country": "United States",
  "latitude": 37.779409,
  "longitude": -122.3926127,
  "isFree": true,
  "calendarName": "SpaceXAI Community",
  "sourceClass": "PUBLIC_FIRST_PARTY"
}
```

### 🎛️ Input guide

- `citySlugs` — public city slugs such as `sf`, `nyc`, `london`, or `berlin`.
- `categorySlugs` — public categories such as `ai`, `climate`, or `startups`.
- `calendarUrls` — exact public Luma calendar URLs.
- `eventUrls` — exact public event URLs.
- `period` — upcoming, past, or both for calendar targets.
- `detailLevel` — Core is the low-cost default; Detailed opens one public detail response per event.
- Date, format, price, include-keyword, and exclude-keyword filters narrow delivered rows deterministically.
- `maxResults`, per-target pages, details, runtime, transfer, and buyer-charge guards stop surprise cost. A stopped walk reports `CAPPED`.

You may combine up to eight source targets. Duplicate events are merged by stable event ID. Exact URLs do not silently add the default city.

### 💰 Pricing

Core event rows cost **$0.05 per 1,000 events**, below the current category leader's advertised **$0.07 per 1,000 results**. A successful collection also has a **$0.001 verified-source charge per run**; failed or blocked runs do not pay it. At the 100-event default, the total is **$0.006**, versus about **$0.00705** for the leader.

| Paid event | Price |
|---|---:|
| Core event | $0.05 / 1,000 |
| Detailed event | $2.00 / 1,000 |
| Comparable monitoring scan | $0.004 / scan |
| Delivered change | $0.05 / 1,000 |

Detailed replaces the Core row price; the same row is not charged twice. Monitoring charges its scan only when coverage is complete and comparable. Coverage rows are free.

### ✅ Coverage you can trust

Every run returns a free coverage row and an `OUTPUT` summary:

- `COMPLETE` — the selected public window completed and is safe for state.
- `EMPTY_CONFIRMED` — the completed public source returned no events.
- `FILTERED` — useful filters were applied; absence is not comparable.
- `CAPPED` — a declared limit stopped a full walk.
- `PARTIAL`, `BLOCKED`, or `FAILED` — the scope is not safe for removal decisions.

Only `COMPLETE` or `EMPTY_CONFIRMED` with comparable target receipts may update monitoring state. `ENDED` requires two consecutive complete comparable misses. `FAILED`, `FILTERED`, `PARTIAL`, `CAPPED`, and `BLOCKED` never create false removals or commit degraded state.

### 🔌 API and automation

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('luminar/luma-events-scraper-monitor').call({
  workflow: 'collect',
  citySlugs: ['sf', 'nyc'],
  detailLevel: 'core',
  maxResults: 200
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

Use the Dataset views for event columns, changes, and coverage. Use KVS `OUTPUT` for counts, field coverage, limits, billing events, and the recommended next action. Sequential Apify schedules are the simplest reliable monitoring setup.

### ⚠️ Not yet supported

Private attendee lists, login-only event data, CAPTCHA solving, automatic email/SMS alerts, outbound messaging, and inferred popularity or investment scores are outside this Actor. Public field coverage varies by event; the Actor reports actual coverage instead of promising universal optional fields.

### ❓ FAQ and support

**Why is an event field null?**\
The selected public Luma surface did not publish it. Detailed mode may add public description, categories, ticket types, and calendar fields.

**Why did monitoring return no rows?**\
The first run normally seeds a quiet baseline. Later unchanged runs also return no paid changes; inspect the free coverage row and `OUTPUT`.

**Can a failed run end events?**\
No. Unsafe coverage never evaluates removals or advances state.

**How do I keep two monitors separate?**\
Give each scope a different `stateNamespace`, then keep each Task input unchanged between sequential runs.

For reproducible support, share the run ID, public input, coverage status, and `OUTPUT` summary. Never share account cookies or private attendee data.

# Actor input Schema

## `workflow` (type: `string`):

Collect returns current event rows. Track changes creates or compares a state baseline.

## `citySlugs` (type: `array`):

Public Luma city slugs such as sf, nyc, london or berlin.

## `categorySlugs` (type: `array`):

Public Luma category slugs such as ai, climate or startups. Category results are added to city results.

## `calendarUrls` (type: `array`):

Exact public Luma calendar URLs, for example https://luma.com/spacexai-community.

## `eventUrls` (type: `array`):

Exact public Luma event URLs. Useful for one-off detail collection.

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

Applies to calendar targets. City and category discovery return their current public window.

## `keywordsAny` (type: `array`):

Keep events matching at least one term in their public title, description, city, calendar, category or host.

## `keywordsAll` (type: `array`):

Keep only events matching every term.

## `excludeKeywords` (type: `array`):

Remove events matching any term.

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

Optional inclusive start date in YYYY-MM-DD.

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

Optional inclusive end date in YYYY-MM-DD.

## `eventFormat` (type: `string`):

Filter by the source-published location type.

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

Filter using the source-published free/paid flag.

## `detailLevel` (type: `string`):

Detailed can add descriptions, categories, ticket types, featured guests and calendar fields for up to 100 events.

## `firstRunBehavior` (type: `string`):

Seed-only prevents a first-run change flood. This choice does not create a different monitoring scope.

## `stateNamespace` (type: `string`):

Separates independent baselines. Keep it unchanged for repeat runs of the same scope.

## `maxResults` (type: `integer`):

Maximum unique current events across all targets.

## `maxResultsPerTarget` (type: `integer`):

Maximum events collected from each city, category or calendar.

## `maxPagesPerTarget` (type: `integer`):

Pagination cap per source target.

## `maxDetailRequests` (type: `integer`):

Hard cap for Detailed mode. Detailed maxResults cannot exceed this value.

## `maxBuyerChargeUsd` (type: `number`):

The Actor refuses to start if the active price worst case exceeds this amount.

## Actor input object example

```json
{
  "workflow": "collect",
  "citySlugs": [
    "sf"
  ],
  "period": "future",
  "eventFormat": "all",
  "pricing": "all",
  "detailLevel": "core",
  "firstRunBehavior": "seed_only",
  "stateNamespace": "default",
  "maxResults": 100,
  "maxResultsPerTarget": 100,
  "maxPagesPerTarget": 10,
  "maxDetailRequests": 100,
  "maxBuyerChargeUsd": 10
}
```

# Actor output Schema

## `dataset` (type: `string`):

All event, change and coverage rows.

## `events` (type: `string`):

Buyer-focused event fields.

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

NEW, UPDATED and confirmed ENDED change fields.

## `coverage` (type: `string`):

Completeness and monitoring safety.

## `runSummary` (type: `string`):

Counts, field coverage, limits and billing events.

# 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 = {
    "workflow": "collect",
    "citySlugs": [
        "sf"
    ],
    "period": "future",
    "eventFormat": "all",
    "pricing": "all",
    "detailLevel": "core",
    "firstRunBehavior": "seed_only",
    "stateNamespace": "default",
    "maxResults": 100,
    "maxResultsPerTarget": 100,
    "maxPagesPerTarget": 10,
    "maxDetailRequests": 100,
    "maxBuyerChargeUsd": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("luminar/luma-events-scraper-monitor").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 = {
    "workflow": "collect",
    "citySlugs": ["sf"],
    "period": "future",
    "eventFormat": "all",
    "pricing": "all",
    "detailLevel": "core",
    "firstRunBehavior": "seed_only",
    "stateNamespace": "default",
    "maxResults": 100,
    "maxResultsPerTarget": 100,
    "maxPagesPerTarget": 10,
    "maxDetailRequests": 100,
    "maxBuyerChargeUsd": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("luminar/luma-events-scraper-monitor").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 '{
  "workflow": "collect",
  "citySlugs": [
    "sf"
  ],
  "period": "future",
  "eventFormat": "all",
  "pricing": "all",
  "detailLevel": "core",
  "firstRunBehavior": "seed_only",
  "stateNamespace": "default",
  "maxResults": 100,
  "maxResultsPerTarget": 100,
  "maxPagesPerTarget": 10,
  "maxDetailRequests": 100,
  "maxBuyerChargeUsd": 10
}' |
apify call luminar/luma-events-scraper-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,luminar/luma-events-scraper-monitor"
        }
    }
}

```

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/3Hg0Wt9VwivhAk0RO/builds/9Y4UKtgpktmO9oBMm/openapi.json
