# Timeleft Scraper - Events, Dinners & Schedules in 200 Cities (`abotapi/timeleft-schedules-scraper`) Actor

Scrape Timeleft (timeleft.com) event schedules across 200 cities: dinners, drinks, coffees, runs, walks and brunches with dates, zones, group sizes, booking cutoffs and booking headcounts. Self-registers a free app account; no subscription needed for schedules.

- **URL**: https://apify.com/abotapi/timeleft-schedules-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 session 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

## Timeleft Schedules Scraper: City Event Calendars with Booking Headcounts

Timeleft Schedules Scraper turns timeleft.com into structured schedule data. Get every upcoming dinner, drinks, coffee, run, walk and brunch session across 200 cities with dates, zones, group sizes, booking cutoffs and booking headcounts. Search by city, filter by format, then export to JSON, CSV or Excel, or pull the results straight into your app through the API.

### Why This Scraper?

- **Every city, one run.** Sweep all 197 Timeleft cities or name the ones you care about (Paris, New York, London) and get roughly three weeks of scheduled sessions per city.
- **Booking momentum included.** Each session carries its live booking headcount, so you can track which formats and cities fill fastest.
- **No credentials needed.** Pick cities and run; access is handled automatically.
- **Built for schedules.** Incremental mode returns only new, changed and expired sessions on recurring runs, and a resume option continues one interrupted sweep without re-collecting rows.
- **Honest limits.** Venues, attendees and booking stay behind Timeleft's paid subscription, so this actor returns schedules only, and says so.

### Use Cases

- **Demand researchers:** track event volume and booking momentum across cities to spot where social-dining demand runs hottest.
- **Travel and relocation planners:** see which formats run in a destination city before a trip.
- **Competitive analysts:** monitor how a subscription-based experiences marketplace paces its supply.
- **Data teams:** feed a recurring schedule snapshot into dashboards via the API or scheduled runs.
- **Marketers:** time outreach around high-momentum formats and cities.

### Data You Get

> Sample shape: values are illustrative placeholders, not from a live record.

| Field | Example |
|---|---|
| `id` | e1df5a79-5cdc-47a5-a474-d4d59abbda1b |
| `city` | Paris |
| `country` | France |
| `cityLatitude` | 48.8666929 |
| `cityLongitude` | 2.3333353 |
| `cityUserCount` | 121637 |
| `cityImageUrl` | https://v2.timeleft.com/images/paris.jpg |
| `date` | 2026-10-08 |
| `eventType` | drinks |
| `status` | available |
| `zoneId` | "351" |
| `dayUsersBooked` | 176 |
| `groupSize` | 7 |
| `maxParticipants` | 80 |
| `bookingCutoffISO` | 2026-10-08T06:00:00.000+02:00 |
| `changeType` | NEW |
| `dayEventId` | 377a8308-b5f6-4e64-afb8-a643da1653a0 |
| `ageRestrictions` | 0 |
| `coverUrl` | https://cdn.timeleft.com/events/covers/timeleft_drink_cover.png |
| `introTitle` | Timeleft Drinks |
| `introDescription` | Spark new connections with a small group over drinks in a local bar. |
| `scrapedAt` | 2026-10-07T10:20:00+00:00 |
| `waitlistOnlyGenders` | man |
| `hasBookingGate` | false |
| `partnerImageUrl` | https://storage.googleapis.com/timeleft-cdn-assets/events/drinks_for_singles.png |

Each row is one bookable zone-session; a day-event with two zones yields two rows. `dayUsersBooked` is the day-level booking total shared by all sessions of that day-event (a 7-table does not seat 17 alone), populated when Fetch booking headcounts is on. `changeType`, `changedFields`, `firstSeenAt` and `lastSeenAt` appear in Incremental mode.

### How to Use

**Sweep three cities with headcounts:**

```json
{
  "cities": ["Paris", "New York", "London"],
  "maxItems": 200,
  "fetchHeadcounts": true
}
```

**Dinners in Paris only, schedules without headcounts:**

```json
{
  "cities": ["Paris"],
  "eventTypes": ["dinner"],
  "maxItems": 50,
  "fetchHeadcounts": false
}
```

**Weekly incremental monitor for London:**

```json
{
  "cities": ["London"],
  "maxItems": 0,
  "incrementalMode": true,
  "stateKey": "london-watch",
  "emitExpired": true
}
```

#### Run it from your code

**Python:**

```python
from apify_client import ApifyClient
client = ApifyClient("YOUR_API_TOKEN")
run = client.actor("abotapi/timeleft-schedules-scraper").call(run_input={"cities": ["Paris"], "maxItems": 50})
```

**JavaScript:**

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });
const run = await client.actor('abotapi/timeleft-schedules-scraper').call({ cities: ['Paris'], maxItems: 50 });
```

### Input Parameters

> Sample shape: values are illustrative placeholders, not from a live record.

| Parameter | Type | Default | Description |
|---|---|---|---|
| `cities` | string\[] | \[] (all 197) | City names or numeric ids; unknown names are skipped with a warning |
| `eventTypes` | string\[] | \[] (all) | dinner, drinks, coffee, run, walk, brunch |
| `maxItems` | integer | 20 | Stop after this many sessions; 0 = unlimited full sweep |
| `fetchHeadcounts` | boolean | true | Read per-event booking totals (one extra read per city) |
| `accountKey` | string | default | Gives each key its own saved state for multi-monitor fleets |
| `proxy` | object | residential | Connection used for the schedule reads |
| `resumeFromRunId` | string | empty | Continue one interrupted sweep from a run or dataset id |
| `incrementalMode` | boolean | false | Track NEW/UPDATED/UNCHANGED/REAPPEARED/EXPIRED across scheduled runs |
| `stateKey` | string | empty (auto) | Name for this monitor's saved state; empty keys the baseline to the exact scope |
| `emitUnchanged` | boolean | false | Also push UNCHANGED rows in incremental mode |
| `emitExpired` | boolean | false | Also push EXPIRED rows after a complete scan |
| `ignoreFieldsForChanges` | string\[] | \[] | Fields that must not mark a row UPDATED |
| `mcpConnectors` | string\[] | \[] | Pipe result summaries into Notion, Linear, Airtable or Apify |
| `notionParentPageUrl` | string | empty | Parent page for the Notion export |
| `maxNotifyListings` | integer | 50 | Cap on items written per connector |

### Output Example

> Sample shape: values are illustrative placeholders, not from a live record.

**One session in Paris:**

```json
{
  "id": "e1df5a79-5cdc-47a5-a474-d4d59abbda1b",
  "city": "Paris",
  "date": "2026-10-08",
  "eventType": "drinks",
  "zoneId": "351",
  "dayUsersBooked": 176,
  "groupSize": 7
}
```

### Plan Requirement

Paid plan recommended: the actor reads through the platform proxy, and free plans have limited proxy access. The scraped schedules themselves need no Timeleft subscription.

### Send results into your apps (MCP connectors)

Select `mcpConnectors` in the input to pipe a condensed, human-readable summary per session (title plus key fields, not the full JSON) into Notion, Linear, Airtable or Apify. Authorize a connector once under Apify, Settings, Integrations, then reference it here. Set `notionParentPageUrl` to choose the Notion parent page, and cap the per-connector volume with `maxNotifyListings` (default 50, maximum 1000). The complete record always stays in the dataset; connector export never affects it and never fails a run.

### FAQ

#### Is it legal to scrape Timeleft?

Scraping publicly visible schedule data for lawful use is generally permitted, but you are responsible for complying with applicable laws and Timeleft's terms. Keep usage respectful of the source.

#### Do I need an account or API key?

No. Just pick cities and run; no credentials needed.

#### Can it book dinners or show venues and attendees?

No. Booking, venues and attendee lists require Timeleft's paid subscription, which an actor cannot purchase. This actor returns schedules and booking headcounts only.

#### Why did my run return zero sessions?

Either every requested city name missed the catalog (check the run log for the unknown-cities warning), the scope filters excluded everything, or the source was temporarily unreachable, so rerun later.

#### How do scheduled runs work?

Turn on Incremental mode with a state key and schedule the actor: the first run tags everything NEW, later runs return only NEW, UPDATED and REAPPEARED sessions (plus EXPIRED when enabled) instead of the full snapshot.

#### Does it work with AI and MCP tools?

Yes. Select MCP connectors in the input to pipe per-session summaries into Notion, Linear, Airtable or Apify while the full JSON stays in the dataset.

**🔗 Pair with more event data.** Combine Timeleft schedules with these related scrapers from the same team:

- 🎟️ [Ticketmaster Events Scraper](https://apify.com/abotapi/ticketmaster-event-discovery) : concerts, festivals and sports with dates, venues and ticket tiers
- 🎫 [Eventim Scraper](https://apify.com/abotapi/eventim-de-event-scraper) : German live events, dates and tickets
- 🎸 [Concert Archives Scraper](https://apify.com/abotapi/concert-archives-scraper) : concert history, tours, venues and setlists

### 💬 Support & custom scrapers

- 🐞 **Found a bug or a missing field?** Open a ticket on the [Issues tab](https://apify.com/abotapi/timeleft-schedules-scraper/issues/open). We usually reply within hours.
- 🛠️ **Need another site, extra fields or a private build?** Email <contact@abotapi.com> or message [Telegram @abotapi](https://t.me/abotapi).
- ⭐ **Enjoying it?** A quick review on the actor page helps other users find it.

# Actor input Schema

## `cities` (type: `array`):

City names, numeric ids, or 'City, Country' form, e.g. 'Paris', '209', 'Paris, France'. Minor typos are tolerated and logged as read; abbreviations are not guessed. Every result holds up to ~3 weeks of scheduled sessions per city. Leave empty to sweep all 197 catalog cities (about 1,900 sessions). Unknown cities are skipped with a warning.

## `eventTypes` (type: `array`):

Pick one or more formats to include; leave empty for all formats.

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

Stop after this many sessions across all cities. 0 = unlimited full sweep of the scoped cities (about 1,900 sessions for all 197).

## `fetchHeadcounts` (type: `boolean`):

Also read per-event booking totals (one extra read per city) into dayUsersBooked (day-level booking totals). Turn off for a lighter run with schedules only.

## `accountKey` (type: `string`):

Gives each key its own saved state, so hundreds of monitors can run side by side without sharing or racing one. Leave default for single use.

## `proxy` (type: `object`):

The schedule API answers from any exit; residential is the default for consistency. The actor fails over gracefully when one is refused.

## `resumeFromRunId` (type: `string`):

Paste a previous run ID or dataset ID to continue one interrupted sweep. Sessions already collected there are skipped. Distinct from Incremental mode below, which tracks the same scope across scheduled runs by itself.

## `incrementalMode` (type: `boolean`):

When ON, the actor remembers its sessions from the previous run of the same scope and tags every row with changeType: NEW, UPDATED, UNCHANGED, REAPPEARED or EXPIRED. Use with the Apify Scheduler to monitor schedules over time.

## `stateKey` (type: `string`):

A name for this monitor's saved state, e.g. 'paris-dinners'. Leave empty to key the baseline automatically to your exact cities, event types and headcount toggle (changing the scope then starts fresh). Set a key to pin one baseline across runs; use distinct keys for independent monitors.

## `emitUnchanged` (type: `boolean`):

When ON, sessions with no detected change are still pushed (tagged UNCHANGED) instead of skipped. This returns, and bills, one extra row per unchanged session.

## `emitExpired` (type: `boolean`):

When ON, sessions tracked before but no longer scheduled after a complete, uncapped scan are pushed once tagged EXPIRED. Only fires on a run that scans its whole scope.

## `ignoreFieldsForChanges` (type: `array`):

Output field names that should NOT mark a session UPDATED. The scrape timestamp is always ignored. Add fields such as dayUsersBooked here if booking-count drift is not relevant to you.

## `mcpConnectors` (type: `array`):

Optionally send the results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize a connector once under Apify → Settings → Integrations, then select it here. The connector receives a condensed, human-readable summary per session, not the full JSON — the complete record stays in the dataset. Leave empty to skip. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com).

## `notionParentPageUrl` (type: `string`):

URL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors.

## `maxNotifyListings` (type: `integer`):

Cap on items written to each connector per run. Does not affect the dataset.

## Actor input object example

```json
{
  "cities": [
    "Paris",
    "New York",
    "London"
  ],
  "eventTypes": [
    "dinner",
    "drinks"
  ],
  "maxItems": 20,
  "fetchHeadcounts": true,
  "accountKey": "default",
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "maxNotifyListings": 50
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

## `changes` (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 = {
    "cities": [
        "Paris",
        "New York",
        "London"
    ],
    "eventTypes": [
        "dinner",
        "drinks"
    ],
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/timeleft-schedules-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 = {
    "cities": [
        "Paris",
        "New York",
        "London",
    ],
    "eventTypes": [
        "dinner",
        "drinks",
    ],
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/timeleft-schedules-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 '{
  "cities": [
    "Paris",
    "New York",
    "London"
  ],
  "eventTypes": [
    "dinner",
    "drinks"
  ],
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call abotapi/timeleft-schedules-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,abotapi/timeleft-schedules-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/hGBjvY7KliQpUiwiG/builds/0riiBfPZFW29aYYTl/openapi.json
