Luma Cli Lightweight avatar

Luma Cli Lightweight

Under maintenance

Pricing

from $10.00 / 1,000 results

Go to Apify Store
Luma Cli Lightweight

Luma Cli Lightweight

Under maintenance

Lightweight playwright based on Luma Scrapper. Optimized for agents and project modularity on Local and VPS environments.

Pricing

from $10.00 / 1,000 results

Rating

0.0

(0)

Developer

New Fish

New Fish

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

0

Monthly active users

4 days ago

Last modified

Share

luma-cli

A lightweight CLI tool for scraping event data and guest profiles from lu.ma.

Setup

Requires Node.js >= 18.3 and a cloned copy of this repo.

git clone git@github.com:profishional/luma-cli.git
cd luma-cli
npm install
npx playwright install chromium
npm link

npm link makes the luma command available globally. Do not move the directory after linking — the global command symlinks to this location.

Authentication

Some commands require a saved login session. Run this once per machine:

$luma auth

A browser window opens. Log in to lu.ma, then close the window. Your session is saved to luma-auth.json (gitignored, never committed).

Re-run luma auth if you see Auth session expired.

Commands

luma event <url> # Scrape event info (no auth required)
luma guests <url> # Scrape guest list
luma scrape <url> # Scrape event info + guests in one session
luma profile <url> # Scrape user profile (name, bio, stats, socials)
luma hosted-events <profile-url> # Scrape hosted events from a profile
luma calendar <url> # List events on a calendar (lu.ma/superteam) or location/community page (lu.ma/Lisbon).
[--period future|past|all] # Default: all. Use future for upcoming-only (much faster on big calendars).
# Auth optional; admins also see private events on calendars they own.
luma past-events [--status going|all] # Scrape your past attended events (default: going)
luma upcoming [--status going|all] # Scrape your upcoming events (default: going)
luma chats # List all your chats
luma chat-messages <partial-name> # Get messages from a chat by partial name
[--limit <n>] # Max messages to return (default: all)

All commands output JSON to stdout. Progress is printed to stderr.

Examples

luma event https://lu.ma/[slug]
luma guests https://lu.ma/[slug]
luma scrape https://lu.ma/[slug]
luma profile https://luma.com/user/[name]
luma hosted-events https://luma.com/user/[name]
luma calendar https://luma.com/[calendar-slug]
luma calendar https://luma.com/[calendar-slug] --period future # upcoming-only (skip past)
luma calendar https://luma.com/Lisbon --period future # location/community page
luma past-events
luma past-events --status all
luma chats
luma chat-messages "cursor"
luma chat-messages "cursor" --limit 50

Pipe to jq for filtering:

luma guests https://lu.ma/bf01c9oe | jq '.guests[].name'
luma scrape https://lu.ma/bf01c9oe | jq '.event.title'
luma past-events | jq '.events[] | select(.attendees > 100)'
luma calendar https://luma.com/[slug] | jq '. as $d | $d.events[] | select(.user_api_id != $d.calendar.personal_user_api_id) | {title, url, user_api_id}' # events whose creator differs from the calendar owner (ownership audit)
luma chats | jq '.chats[] | select(.unread)'
luma chat-messages "cursor" --limit 10 | jq '.messages[] | {author, authorUrl}'

Output Shapes

// luma event <url>
{ title, location, datetime, description, guestCount }
// datetime: "2026-03-21T10:00" (event's local timezone, minute precision)
// guestCount: total attendees on the event
// luma guests <url>
{
stats: {
count, // guests actually returned (≤ 10 when source="featured")
with_socials,
guestCount, // total attendees on the event (from SSR)
url, fetchedAt,
source // "api" = full list (user must be going) | "featured" = 10 max
},
guests: [{
name, url, api_id, username, bio, avatar_url, is_verified, timezone,
socials: { instagram, twitter, tiktok, linkedin, youtube, website }
}]
}
// luma scrape <url>
{
event: { title, location, datetime, description, guestCount },
stats: { count, with_socials, guestCount, url, fetchedAt, source },
guests: [{ name, url, api_id, username, bio, avatar_url, is_verified, timezone, socials: { ... } }]
}
// luma profile <url>
{
name,
bio, // bio text, null if empty/unset
stats: { hosted, attended, together },
socials: { instagram, twitter, tiktok, linkedin, youtube, website }
}
// luma hosted-events <profile-url>
{
stats: { count, url, fetchedAt },
events: [{
title, url, datetime, end_datetime, location,
api_id, cover_url, event_type, location_type, calendar_api_id
}]
}
// datetime/end_datetime are in the event's timezone, minute precision.
//
// Scope: this command returns events where the target user is a primary host
// on a publicly-listable event — the same set lu.ma itself shows in the "View
// All" modal on that profile. It does NOT include:
// - private/unlisted events (even when you're the host, logged in as yourself)
// - events on a calendar you admin but were created by someone else
// - events where you're a co-host on someone else's calendar
// The `event_hosted_count` badge on a Luma profile can be higher than this list
// for those reasons — that counter is inflated server-side and the modal shows
// fewer rows too. For calendar-scoped coverage (including private events on
// calendars you admin), use `luma calendar <calendar-url>`.
// luma past-events [--status going|all]
// luma upcoming [--status going|all]
{
stats: { count, statusFilter, url, fetchedAt },
events: [{
title, url, datetime, end_datetime, location, attendees, status,
api_id, cover_url, event_type, location_type, visibility,
calendar_api_id, user_api_id,
hosts: [{ name, url, api_id, username }] // minimal — use `luma profile <url>` to expand one
}]
}
// datetime/end_datetime: minute precision in the event's timezone
// attendees: exact guest_count from the event (not estimated)
// status: "Going" | "Invited" | "Waitlist" | "Pending" | "Declined" | null
// With --status going, only "Going" events are returned.
// visibility: "public" | "private" | "unlisted"
// user_api_id: the account that created the event (useful for ownership audits)
// luma calendar <url> [--period future|past|all]
//
// Two URL types are supported. The output has either `calendar` or `place` —
// never both — depending on which the URL points at:
//
// 1) Calendar pages (lu.ma/superteam, lu.ma/breakpoint):
{
calendar: {
name, slug, api_id, description_short,
access_level, // "public" | "private" | ...
personal_user_api_id, // the user who "owns" the calendar (null for non-personal calendars)
avatar_url, cover_image_url,
instagram_handle, twitter_handle, linkedin_handle, website
},
stats: { count, period, url, fetchedAt },
events: [{
title, url, datetime, end_datetime, location, attendees, status,
api_id, cover_url, event_type, location_type, visibility,
calendar_api_id, user_api_id,
hosts: [{ name, url, api_id, username }]
}]
}
// Anonymous access returns only public events. A logged-in calendar admin also
// sees private/unlisted events on that calendar.
// `user_api_id` is the data-quality hook: events where this differs from
// `calendar.personal_user_api_id` were created under someone's personal account
// rather than the calendar account.
//
// 2) Location / community discover pages (lu.ma/Lisbon, lu.ma/SF, …):
{
place: {
name, slug, api_id, // api_id starts with "discplace-"
description, timezone, event_count,
geo_continent, geo_continent_name,
avatar_url, cover_image_url
},
stats: { count, period, url, fetchedAt },
events: [ /* same shape as above */ ]
}
// Discover pages are fully public — auth makes no difference.
// `--period future` is the common case here ("what's coming up in Lisbon?")
// and avoids fetching the past-events backlog.
// luma chats
{
stats: { count, myUserId, fetchedAt },
chats: [{
name, eventUrl, // event URL for group chats, null for DMs
api_id, type, // type: "group" | "direct"
participants,
lastMessage, lastMessageAt, unread
}]
}
// luma chat-messages <partial-name> [--limit <n>]
{
stats: { count, query },
name, eventUrl, // event URL if group chat, null for DMs
messages: [{
author, // "me" or display name
authorUrl, // "https://lu.ma/<username>" or "https://lu.ma/user/<id>", null for self
text,
timestamp // "2026-04-16T10:21"
}]
}

On a New Machine

git clone git@github.com:profishional/luma-cli.git
cd luma-cli
npm install
npx playwright install chromium
npm link
luma auth

Notes

  • luma-auth.json stores your login session — treat it like a password, never commit it
  • Data is sourced from lu.ma's internal API and the page's __NEXT_DATA__ SSR payload, not DOM scraping — so output fields are typed and less likely to break on redesigns. The browser (Playwright + Chromium) is still needed to carry the session cookies into the API calls.
  • A 1.5s delay is added between paginated requests to avoid hammering their servers
  • Guest lists: ~100 per API page. A 1000-guest event takes ~15–30s. If you're not going to the event, only the 10 featured_guests from the page SSR are available (stats.source: "featured"); stats.guestCount still reports the true total.
  • Past/upcoming/hosted events: ~50 per API page. A user with 300+ past events takes ~20–40s. Private events the user can't see publicly are filtered out by lu.ma server-side.
  • luma calendar runs without auth for public calendars and location/community discover pages (e.g., lu.ma/Lisbon). For calendars you admin, pass luma-auth.json (automatic when the file exists) to also see private/unlisted events. On big calendars (Superteam has ~1700 past events) prefer --period future — it skips the past fetch entirely and finishes in seconds instead of minutes.

Apify Actor Pricing

Custom pay-per-event charges configured in Apify Console. Price increases require 14-day notice and can only change once per month. Decreases are instant.

Adding a new charge eventmain.mjs calls Actor.charge({ eventName: ... }). Every event name used there must exist in the Apify Console monetization panel before the actor runs, otherwise the run fails at the first Actor.charge call. When you add a new command that charges a new event (e.g., calendar-event was added with the calendar command), remember to add the row in the Apify Console too.

Event nameCharged whenPerPrice
event-infoevent or scrape command1 per run$0.01
guestguests or scrape command1 per guest$0.03
profileprofile command1 per run$0.02
hosted-eventhosted-events command1 per event$0.01
calendar-eventcalendar command1 per event$0.01
past-eventpast-events command1 per event$0.01
upcoming-eventupcoming command1 per event$0.01
chatchats command1 per chat$0.01
chat-messagechat-messages command1 per run$0.01
apify-actor-startany run1 per start (scales with RAM)$0.005

apify-default-dataset-item is disabled — charging is handled by custom events above.

Primary event: guest