# Eventim Scraper - DE Events, Dates and Tickets (`abotapi/eventim-de-event-scraper`) Actor

Scrape CTS Eventim Germany and EU event catalogue: concerts, festivals, comedy, sports, dates, venues, prices and availability. Search by city, keyword, category and date, or paste event links. Incremental monitoring with NEW, UPDATED, REAPPEARED, EXPIRED, resume and MCP export.

- **URL**: https://apify.com/abotapi/eventim-de-event-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Features:** Limited permissions
- **Stats:** 1 total users, 0 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.20 / 1,000 event records

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

## Eventim.de Scraper: Concerts, Festivals and Ticket Prices in Germany and the EU

Eventim.de Scraper turns the CTS Eventim catalogue, Europe's largest ticket shop, into structured event data. Get concerts, festivals, comedy, classical, sports and leisure events across Germany and the EU with dates, venues, prices in EUR and ticket availability. Search by city, keyword, category and date, or paste Eventim links for a specific event, city or venue, then export to JSON, CSV or Excel, or pull results straight into your app through the API.

### Why This Scraper?

- **Two ways to find events.** Search by city, keyword, category and date window, or paste Eventim event, city and venue links directly.
- **Wide catalogue coverage.** A search run walks every city and category combination you give it, not just one narrow query, and the coverage note below explains how to widen it further.
- **Detail on demand.** Switch on event detail reads to add the full venue address, price span and per-ticket-tier prices with availability (and the event page's own description and image), and pay the enrichment charge only for the events you actually read.
- **Built for schedules.** Incremental mode returns only new, updated and reappeared events on recurring runs, and can mark events that disappeared as expired (read the Max items caveat under "Resume and recurring updates" before turning that on).
- **Resume support.** Continue a large, interrupted pull without paying to recollect events you already have.
- **Export anywhere.** Download JSON, CSV or Excel, or pipe results into the apps you already use through MCP connectors.
- **Fails loudly, not quietly.** If the catalogue refuses every request, the run stops with a clear message instead of shipping an empty dataset that looks like "no events today".

### Use Cases

- **Ticket resellers and price trackers:** watch `priceFrom`, `priceHigh` and `ticketAvailability` across venues and cities for pricing and stock changes.
- **Event discovery apps:** feed concerts, festivals, comedy and sports dates into your own calendar, bot or notification tool.
- **Tour and artist tracking:** run a keyword search on a schedule with incremental mode to catch new tour dates as they go on sale.
- **Venue and promoter research:** collect venue addresses and promoter names for a city or category.
- **Market research and reporting:** build a dataset of event volume, categories and pricing across German cities over time.

### Data You Get

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

| Field | Example |
| --- | --- |
| `eventId` / `recordId` | `"00000000"` |
| `title` | `"Sample Artist Live"` |
| `eventType` / `eventStatus` | `"LiveEntertainment"` / `"Available"` |
| `startDate` / `endDate` | `"2027-05-01T20:00:00+02:00"` / `"2027-05-01T22:30:00+02:00"` |
| `venueName` / `venueCity` | `"Sample Arena"` / `"Berlin"` |
| `venueStreet` / `venuePostalCode` / `venueRegion` / `venueCountry` | `"Sample Platz 1"` / `"10115"` / `"Berlin"` / `"DE"` (detail mode only) |
| `venueUrl` | Eventim venue page link (detail mode only) |
| `priceFrom` / `priceHigh` | `49.9` / `99.9` |
| `priceCurrency` | `"EUR"` |
| `priceTiers` | per-ticket-tier category, price and availability (detail mode only); also exposed as `priceCategories` |
| `ticketAvailability` | `"in_stock"` (also `"out_of_stock"`, `"sold_out"`) |
| `promoterName` | `"Sample Promoter GmbH"` |
| `categories` / `tags` | `["Concerts", "Music"]` / `["TICKETDIRECT"]` |
| `description` / `imageUrl` | description text and image link: taken from the catalogue listing when it carries them (not every event does), with markup removed so it is plain text; with detail mode on, the event page value replaces the listing value, and when an event page cannot be read the stored value from your previous run is kept |
| `validFrom` | ticket offer validity start (detail mode only) |
| `productGroupId` | `"g00000000"` (also `eventSeries.id`) |
| `url` | Eventim link to the event |
| `kind` | `"event"` |
| `attractions` | `["Sample Artist"]` (performers listed on the event) |
| `rating` | `{"average": 4.5, "count": 12}` |
| `inStock` / `hasRecommendation` / `fromPrice` / `fromPriceDisplay` / `currency` | `true` / `false` / `49.9` / `"49.90 EUR"` / `"EUR"` |
| `eventName` / `eventUrl` / `type` / `status` | alternate names for `title` / `url` / `eventType` / `eventStatus` |
| `scrapedAt` | time the row was collected |
| `changeType` | `"NEW"` (incremental mode only; also `UPDATED`, `UNCHANGED`, `REAPPEARED`, `EXPIRED`) |
| `changedFields` / `firstSeenAt` / `lastSeenAt` | changed field names, first-seen and last-seen timestamps (incremental mode only) |

All text (`title`, `description`, `categories`) comes back in English: the actor reads Eventim's English-language catalogue pages. Prices are always in EUR.

### How to Use

1. Pick a **mode**: `search` (by city, keyword, category, date) or `url` (paste Eventim links).
2. Fill in the search filters for that mode, or paste event, city or venue links.
3. Turn on **Fetch event details** if you need the full address and per-tier prices, set **Max items**, then click **Start**.
4. Download the dataset as JSON, CSV or Excel, or read it through the API.

**Search Berlin concerts:**

```json
{
  "mode": "search",
  "cities": ["Berlin"],
  "categories": ["Concerts"],
  "maxItems": 20
}
```

**Keyword search across all cities, in a date window, tickets in stock only:**

```json
{
  "mode": "search",
  "query": "Sample Artist",
  "dateFrom": "2027-05-01",
  "dateTo": "2027-08-31",
  "inStockOnly": true,
  "maxItems": 50
}
```

**Supported link shapes (URL mode):**

| Link shape | Example | Result |
|---|---|---|
| City page | `https://www.eventim.de/en/city/berlin-1/` | the city's events |
| City page without `/en/` | `https://www.eventim.de/city/berlin-1/` | the city's events |
| City page with `?pnum=N` | `https://www.eventim.de/en/city/berlin-1/?pnum=2` | the whole city scope (page parameter ignored, warned) |
| Event page | `https://www.eventim.de/en/event/bsv-eintracht-mahlsdorf-nofv-oberliga-nord-sportplatz-am-rosenhag-21994953/` | that event |
| Venue page | `https://www.eventim.de/en/city/berlin-1/venue/admiralspalast-berlin-702/` | the venue's whole city scope (warned) |
| Artist, series and other pages | | skipped with a warning |

URL mode with the **Eventim links** field left untouched now reads the three example links (city, event, venue) instead of failing with no input. Pass an explicit list to read your own links. Misspelled city or category names in search mode log a warning that nothing matched.

**Paste Eventim links (event, city, venue), with full detail:**

```json
{
  "mode": "url",
  "urls": [
    "https://www.eventim.de/en/event/sample-artist-live-berlin-00000000/",
    "https://www.eventim.de/en/city/hamburg-2/"
  ],
  "fetchDetails": true
}
```

**Recurring monitoring across three cities:**

```json
{
  "mode": "search",
  "cities": ["Berlin", "Hamburg", "Munich"],
  "categories": ["Concerts"],
  "incrementalMode": true,
  "stateKey": "berlin-hamburg-munich-concerts",
  "emitExpired": true,
  "maxItems": 0
}
```

#### Run it from your code

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/eventim-de-event-scraper").call(
    run_input={"mode": "search", "cities": ["Berlin"], "categories": ["Concerts"]})
for event in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(event["title"], event["startDate"], event["priceFrom"], event["priceCurrency"])
```

JavaScript:

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

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/eventim-de-event-scraper').call({
  mode: 'search', cities: ['Berlin'], categories: ['Concerts'],
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the **Integrations** tab.

#### Coverage and the scope cap

Each city and category combination is one catalogue read that serves up to 50 events; the catalogue does not serve pages beyond that for a single combination. Combine cities with categories and a date window to widen coverage, since each combination is read on its own. With several combinations and a **Max items** cap, the cap is split evenly across them, so each city or category contributes its share rather than the run returning only the newest events globally; a low cap over many combinations can leave some headroom unused rather than concentrate it on the first combination. Set **Max scopes** to bound how many combinations are walked at all.

#### Resume and recurring updates

- **Resume** (`resumeFromRunId`) continues one interrupted run: paste its run or dataset id and the actor skips every event id already present there, so you do not pay to recollect them. This only works when the referenced dataset carries this actor's own `eventId` field on every row. Pointed at a dataset in a different shape (a hand-built dataset, or one that never went through this actor), it silently seeds nothing, logs a quiet "0 event id(s) seeded" line, and the run continues as if it were the first pull, recollecting and rebilling every event. Only point it at a run or dataset this actor produced.
- **Incremental mode** (`incrementalMode`) is for scheduled runs over the same search or link setup. Each event is classified `NEW`, `UPDATED` (with `changedFields`), `UNCHANGED` (suppressed and not billed unless `emitUnchanged` is on), `REAPPEARED` or `EXPIRED` (only with `emitExpired`, and never on a run that was resumed, hit the run-wide **Max items** total or **Max scopes**, or had any city, category or link fail). `stateKey` names or shares the stored state. With incremental mode off, output is exactly as before.
- **Ignore fields when detecting changes** (`ignoreFieldsForChanges`, incremental mode only): field names (or dotted paths such as `priceTiers.availability`) that never make an event `UPDATED`. Always ignored: `raw`, `imageUrl` and the added convenience fields (`eventName`, `eventUrl`, `type`, `status`, `currency`, `fromPrice`, `fromPriceDisplay`, `inStock`, `hasRecommendation`, `attractions`, `venue`, `rating`, `priceCategories`, `eventSeries`, `scrapedAt`), so a change in rating, attractions or venue coordinates alone never makes an event `UPDATED`. Your own names and dotted paths apply to the core fields only (for example `priceTiers.availability`, `tags`, `promoterName`), not to those added fields. A `description` that was empty in the stored baseline and is filled now is treated as the one-time fill, not as a change; a later edit to it reads `UPDATED`. Ignored fields are still returned in the output.
- **Using Resume and Incremental mode together in the same run:** events the resume step skips (already collected in the run you resumed from) are deduplicated for that run but are not added to the incremental baseline, since they never reach the classification step. A later scheduled run without `resumeFromRunId` over the same `stateKey` will not recognize them as already known, and will report and bill them again as `NEW`. In other words, under incremental mode the resume saving is postponed, not kept: the skipped events are paid for again on the next plain incremental run, just as they would have been had you run incremental mode without resuming. The first incremental run on any new `stateKey` always reports every event it finds as `NEW`, so plan for that one full-price run whichever way you start.
- **Expired rows are not capped by Max items.** Once a run qualifies to tombstone, every event still in the tracked baseline but no longer found is returned and billed as `EXPIRED`, regardless of how low **Max items** is set. On a monitoring campaign that tracks a large number of events, a big shift in what the scope returns can emit a correspondingly large batch of `EXPIRED` rows in a single run.
- **Known issue: with Emit expired on, keep Max items at `0` (no limit).** The expiry check is only skipped when the run as a whole reaches **Max items**. A run can stop reading a city or category early because of its share of the cap without reaching that total: unchanged events that are suppressed still use up their scope's share, and a cap that does not divide evenly across combinations (for example 20 over 3 cities) never adds up to the total. Such a run treats every tracked event it did not get to read as gone, and returns and bills them as `EXPIRED` even though they are still on sale; the next full run then bills them again as `REAPPEARED`. For example, with 50 tracked events that are all still listed, a run with **Max items** `10` returns 40 false `EXPIRED` rows. Incremental runs with **Emit expired** off are not affected.

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

Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step **after** the scrape: the Apify dataset is never changed.

**What gets written to the connector:** a condensed, human-readable **summary** of each event, not the full JSON. Each item becomes one entry with a **title** and its key fields flattened to plain text. The **complete record always stays in the Apify dataset**.

1. Authorize a connector once under **Apify → Settings → Integrations** (Notion, Linear, Airtable, or Apify).
2. Select it in the **"Pipe results into your apps"** input field. (If the picker is empty, you have not authorized a connector yet.)
3. For **Notion**, also set `notionParentPageUrl` to the page where items should be created.

The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.

### Input Parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `mode` | string | `search` | `search` (query the catalogue) or `url` (paste Eventim links). |
| `cities` | array | (empty; prefilled `["Berlin"]`) | Search mode: city names, one per line. Empty searches all cities. |
| `query` | string | (empty) | Search mode: optional keyword, an artist, event or venue name. |
| `categories` | array | (empty, all categories) | Search mode: event categories, for example Concerts, Comedy, Classical, Sports. |
| `searchTerm` / `city` | string | (empty) | API-only alternate names for `query` and one entry of `cities`. |
| `dateFrom` | string | (empty, no lower bound) | Only events on or after this date, `YYYY-MM-DD`. |
| `dateTo` | string | (empty, no upper bound) | Only events on or before this date, `YYYY-MM-DD`. |
| `inStockOnly` | boolean | `false` | Return only events whose tickets are currently bookable. |
| `sort` | string | `DateAsc` | `DateAsc`, `DateDesc`, `NameAsc`, `NameDesc`, `Rating`, or `Recommendation`. `sortBy` is an API-only alternate name, used when `sort` is left at `DateAsc`. |
| `postalCode` | string | (empty) | Search mode: events around a German postal code (PLZ); the catalogue applies its own fixed radius. |
| `artist` | string | (empty) | Search mode: artist name, appended to the keyword search (the catalogue has no separate artist filter). |
| `venue` | array | (empty) | Search mode: exact venue names as Eventim lists them, one per line; a partial name matches nothing. |
| `priceMin` | integer | (empty) | Search mode: from-price lower bound in euros; must not exceed `priceMax`. |
| `priceMax` | integer | (empty) | Search mode: from-price upper bound in euros. |
| `eventSeriesIds` | array | (empty) | Search mode: earlier `productGroupId` values, one per line; each id is its own scope. |
| `urls` | array | three example links (one city, one event, one venue) | URL mode: Eventim event, city or venue links, one per line. With the field untouched, URL mode reads the three example links. |
| `fetchDetails` | boolean | `false` | Read each event's own page for description, image, full venue address, price span and per-tier prices. Adds a per-event surcharge. |
| `maxItems` | integer | `20` | Stop after this many events (`0` = no limit). `maxResults` is an API-only alternate name, used when `maxItems` is not set or left at `20`. |
| `maxPages` | integer | `0` | Upper bound on how many city and category combinations are walked (`0` = no limit). |
| `resumeFromRunId` | string | (none) | A previous run id or dataset id to continue without recollecting its events. |
| `incrementalMode` | boolean | `false` | Return only new and changed events on scheduled runs. |
| `stateKey` | string | (none) | Name or share an incremental-mode state; derived automatically when left empty. |
| `emitUnchanged` | boolean | `false` | Also return (and bill) unchanged events. |
| `emitExpired` | boolean | `false` | Also return (and bill) expired events. |
| `ignoreFieldsForChanges` | array | (none) | Incremental mode: field names or dotted paths that never make an event `UPDATED` (see Resume and recurring updates). |
| `mcpConnectors` | array | (none) | Optional: send a summary of each event to apps you authorized under Integrations. |
| `notionParentPageUrl` | string | (none) | Notion connector only: page under which event pages are created. |
| `maxNotifyListings` | integer | `50` | Cap on items written to each connector per run. |
| `proxyConfiguration` | object | Apify Proxy | Connection settings. Apify Proxy by default; see Plan Requirement for what free plans can reach. |

**Dataset views:** the dataset has four saved views in the Console: Overview (core columns), Detail (venue, price tiers and description, filled in detail mode), Changes (change type and changed fields, incremental mode) and Series (the series id columns, `productGroupId` and `eventSeries`, next to each event; the rows are not grouped).

**API-only alternate names:** `searchTerm`, `city`, `sortBy` and `maxResults` are accepted through the API as alternate names for `query`, `cities`, `sort` and `maxItems`; they are not shown in the Console form.

### Output Example

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

```json
{
  "kind": "event",
  "recordId": "00000000",
  "eventId": "00000000",
  "productGroupId": "g00000000",
  "url": "https://www.eventim.de/en/event/sample-artist-live-berlin-00000000/",
  "title": "Sample Artist Live",
  "startDate": "2027-05-01T20:00:00+02:00",
  "endDate": "2027-05-01T22:30:00+02:00",
  "eventStatus": "Available",
  "eventType": "LiveEntertainment",
  "venueName": "Sample Arena",
  "venueUrl": "https://www.eventim.de/en/city/berlin-1/venue/sample-arena-1/",
  "venueStreet": "Sample Platz 1",
  "venueCity": "Berlin",
  "venueRegion": "Berlin",
  "venuePostalCode": "10115",
  "venueCountry": "DE",
  "priceFrom": 49.9,
  "priceHigh": 99.9,
  "priceCurrency": "EUR",
  "priceTiers": [
    { "category": "Standing", "price": 49.9, "priceCurrency": "EUR", "availability": "in_stock" },
    { "category": "Seated", "price": 99.9, "priceCurrency": "EUR", "availability": "in_stock" }
  ],
  "ticketAvailability": "in_stock",
  "promoterName": "Sample Promoter GmbH",
  "categories": ["Concerts", "Music"],
  "tags": ["TICKETDIRECT"],
  "description": "A sample show description.",
  "imageUrl": "https://www.eventim.de/obj/media/sample-image.jpg",
  "validFrom": "2026-11-01T10:00:00+01:00"
}
```

### Plan Requirement

The scraper reads Eventim through Apify Proxy and checks which proxy tiers your account is allowed to use as it goes. Catalogue searches start on the default connection; event detail pages (with **Fetch event details** on, or pasted event links) are refused by ordinary connections, so those reads escalate automatically through an alternate Apify Proxy pool, then residential and backup connections, and the first one that serves the pages is reused for the rest of the run.

- **Paid Apify plan:** the full ladder is available and all input options work.
- **Free Apify plan:** Apify free plans do not include residential proxies, and some free accounts have no Apify Proxy access at all. The run logs "Apify free plans do not include residential proxies" and continues on a backup connection, so some pages may still be unavailable. If every connection is refused the run stops with a clear message ("The proxy connection was refused for this account ... a paid plan is required") instead of returning an empty dataset. If only the backup connection was tried and it could not load the pages, the message is "No results: residential proxies are unavailable on this run". If requests simply fail, the message is "Could not load any results page ... This is a connection problem, not an empty search."
- **Your own proxy URLs:** requests are sent exactly as given, with no escalation.

Eventim's protection can change at any time, so availability on a given tier is observed at run time, not guaranteed.

### FAQ

#### How much does it cost?

You pay per event returned, with the detail enrichment charged only for events whose detail page was read (**Fetch event details** on, or pasted event links), plus one run-start charge. The **Pricing** tab shows the current rates. Use **Max items** to cap the cost of any run, with the expired-row note below in mind for incremental monitoring runs.

#### Is it legal to scrape Eventim.de?

This actor collects only publicly available catalogue data (dates, venues, prices and availability). You are responsible for how you use it: follow Eventim's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution.

#### Why does a search return at most 50 events per city or category?

That is the most common surprise: the catalogue serves at most 50 events for a single city and category combination and does not page deeper for it. Add more cities, categories or narrow the date window so the run covers the catalogue through more combinations instead of one large one. The "Coverage and the scope cap" note above has the details.

#### Can I get only new or changed events on a schedule?

Yes. Schedule the actor from the **Schedules** tab and turn on **Incremental mode**. Each run then returns only new, updated and reappeared events, and unchanged ones are not billed unless you turn on **Emit unchanged**. If you also turn on **Emit expired**, set **Max items** to `0` (see the known issue above).

#### Why did my run fail instead of returning an empty dataset?

If every scope or pasted link is rejected, the run stops with a clear message so "no matching events" is never confused with "nothing could be read". Run it again in a few minutes. If only some cities, categories or links could be read, you still get what was found, and the run succeeds with a status message naming what was skipped.

#### Why did an incremental run return far more rows than Max items?

`EXPIRED` rows are not counted against **Max items**: once a run qualifies to tombstone (not resumed, run-wide Max items total or Max scopes not reached, every scope finished), it returns every tracked event no longer found, however many that is. There is also a known issue: if **Max items** stopped a city or category early without the run reaching its total, the events it did not read are wrongly returned as `EXPIRED` (and come back as `REAPPEARED` on the next full run). With **Emit expired** on, set **Max items** to `0`. Lower genuine expiry volume by narrowing the tracked scope (fewer cities or categories per `stateKey`) or by leaving **Emit expired** off on very large monitoring campaigns.

#### Why didn't Resume skip events I already collected?

Two known causes. First, `resumeFromRunId` only recognizes rows carrying this actor's own `eventId` field; a dataset from any other source seeds nothing, silently. Second, combining `resumeFromRunId` with **Incremental mode** in the same run deduplicates the resumed events for that run only, without adding them to the incremental baseline, so a later scheduled run can report them as `NEW` again. See "Resume and recurring updates" above for details.

#### Can I use it with AI agents or MCP?

Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear or Airtable.

### 🔗 Want more sports data?

Pair this actor with these related scrapers from the same team:

<table>
<tr><td>⚽ <a href="https://apify.com/abotapi/bookmyshow-scraper"><b>BookMyShow Scraper</b></a><br>Scrape BookMyShow movies and live events by city, category or URL. Extract genres...</td><td>⚽ <a href="https://apify.com/abotapi/sportsbook-odds-scraper"><b>Sportsbook Odds Scraper (1xBet, Melbet, Linebet, Paripulse)</b></a><br>Collect live and prematch betting odds from 1xBet, Melbet, Linebet and Paripulse. Give it...</td></tr>
<tr><td>⚽ <a href="https://apify.com/abotapi/globo-ge"><b>Globo Esporte Scraper</b></a><br>Scrape public sports content from ge.globo.com, including news, videos, matches and feed...</td><td>⚽ <a href="https://apify.com/abotapi/fotmob-scraper"><b>FotMob Scraper ⚽ Match Details, Stats, Lineups &amp; Players</b></a><br>Pull structured football data from FotMob: match details with scores, team stats, events...</td></tr>
<tr><td>⚽ <a href="https://apify.com/abotapi/sofascore-scraper"><b>SofaScore Scraper ⚽ Live Scores, Stats, Players &amp; Odds</b></a><br>Pull structured sports data from SofaScore across football, basketball, tennis, and 20+...</td><td>⚽ <a href="https://apify.com/abotapi/hotstar-com-scraper"><b>JioHotstar Scraper</b></a><br>Scrape the JioHotstar catalog by content type or URL. Extract shows, movies, episodes...</td></tr>
</table>

👉 [Browse all abotapi scrapers](https://apify.com/abotapi)

### 💬 Support

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

# Actor input Schema

## `mode` (type: `string`):

Search reads Eventim by city, keyword, category and date. URL mode reads specific Eventim pages you paste.

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

Search mode: city names to cover, one per line, for example Berlin, Hamburg, Munich. Each city is one catalogue scope. Leave empty to search all cities.

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

Search mode: optional keyword, for example an artist, event or venue name. Applied inside every city and category scope.

## `categories` (type: `array`):

Search mode: event categories, one per line, for example Concerts, Comedy, Classical, Sports. Each category multiplies the city scopes. Leave empty for all categories.

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

Only events on or after this date, format YYYY-MM-DD. Applies in search mode and to pasted city and venue links. Leave empty for no lower bound.

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

Only events on or before this date, format YYYY-MM-DD. Applies in search mode and to pasted city and venue links. Leave empty for no upper bound.

## `inStockOnly` (type: `boolean`):

Return only events whose tickets are currently bookable. Applies in search mode and to pasted city and venue links.

## `sort` (type: `string`):

Ordering inside every scope: search mode, and pasted city or venue links.

## `postalCode` (type: `string`):

Search mode: events around this German postal code (PLZ), for example 10117; the catalogue applies its own fixed radius. Applied inside every city and category scope. Leave empty for no postal filter.

## `artist` (type: `string`):

Search mode: artist or performer name. It is appended to the keyword, so the catalogue keyword search runs on both together (there is no separate artist filter). Leave empty to skip.

## `venue` (type: `array`):

Search mode: exact venue names as Eventim lists them, one per line, for example Uber Arena Berlin. Names must match exactly; a partial name returns nothing. Leave empty for all venues.

## `priceMin` (type: `integer`):

Search mode: from-price lower bound in euros. Leave empty for no lower bound.

## `priceMax` (type: `integer`):

Search mode: from-price upper bound in euros. Must not be below the minimum price. Leave empty for no upper bound.

## `eventSeriesIds` (type: `array`):

Search mode: event series (product group) IDs, one per line, as shown in the productGroupId output field. Each ID is its own scope, so the cities and categories fan out once per series. Leave empty for all series.

## `urls` (type: `array`):

URL mode: Eventim pages to read, one per line. Event links are read as single records; city and venue links read that city's catalogue scope. Multi-value supported. Left untouched in URL mode, the three example links below are read (one event, one city, one venue). Unsupported links (artist, series) are skipped with a warning.

## `fetchDetails` (type: `boolean`):

Read each event's own page to add the full venue address, price span and per-tier prices with availability, plus the event page's own description and image (the listing's are used otherwise). Detail pages need the slower alternate connection (about 16 seconds per event), so this is off by default. Adds a per-event surcharge (see the section caption below).

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

Stop after this many events (0 = no limit; the run then stops when the scopes run out).

## `maxPages` (type: `integer`):

Upper bound on how many city and category scopes are walked (0 = no limit). Each scope serves up to 50 events, so Max items is the cap that normally stops a run first.

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

Apify Proxy settings. Apify Proxy by default; free Apify plans have no residential proxies, so some pages may be unavailable there.

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

Paste a previous run ID or dataset ID to continue a large pull without returning events already collected there.

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

Turn this on for daily or recurring monitoring. The first run returns every matching event as NEW. Later runs normally return only NEW, UPDATED and REAPPEARED events. Turn on Emit unchanged or Emit expired only when you also want those rows returned (and billed). State is kept separately for each search and link setup; use State key to name or deliberately share a monitoring campaign.

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

Optional. Name this monitoring campaign to keep its state stable, or deliberately share state across differently configured runs. Leave empty to let the actor derive a key automatically from the search and link settings.

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

Off by default. Turn on to also return events that have not changed since the last run, marked UNCHANGED. This returns, and bills, extra rows you already have.

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

Off by default. Turn on to also return events that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned the tracked search.

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

Output field names that should NOT make an event count as UPDATED. Always ignored: raw (the verbatim upstream product data) and imageUrl (a CDN address that can rotate without the picture changing). Add fields such as tags or promoterName here if changes to them are not relevant to you. Use a dotted path (for example priceTiers.availability) to ignore a field inside a nested object or list. Ignored fields are still returned in the output.

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

Optionally send results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize one under Apify, Settings, API and Integrations, then select it here. Notion gets a rich page-per-item export; other connectors get a best-effort write or digest. Leave empty to skip; never changes the dataset output.

## `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
{
  "mode": "search",
  "cities": [
    "Berlin"
  ],
  "categories": [],
  "dateFrom": "",
  "dateTo": "",
  "inStockOnly": false,
  "sort": "DateAsc",
  "urls": [
    "https://www.eventim.de/en/city/berlin-1/",
    "https://www.eventim.de/en/event/bsv-eintracht-mahlsdorf-nofv-oberliga-nord-sportplatz-am-rosenhag-21994953/",
    "https://www.eventim.de/en/city/berlin-1/venue/admiralspalast-berlin-702/"
  ],
  "fetchDetails": false,
  "maxItems": 20,
  "maxPages": 0,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "maxNotifyListings": 50
}
```

# Actor output Schema

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

No description

## `detail` (type: `string`):

No description

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

No description

## `series` (type: `string`):

No description

## `summary` (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 = {
    "mode": "search",
    "cities": [
        "Berlin"
    ],
    "categories": [],
    "dateFrom": "",
    "dateTo": "",
    "inStockOnly": false,
    "sort": "DateAsc",
    "urls": [
        "https://www.eventim.de/en/city/berlin-1/",
        "https://www.eventim.de/en/event/bsv-eintracht-mahlsdorf-nofv-oberliga-nord-sportplatz-am-rosenhag-21994953/",
        "https://www.eventim.de/en/city/berlin-1/venue/admiralspalast-berlin-702/"
    ],
    "fetchDetails": false,
    "maxItems": 20,
    "maxPages": 0,
    "proxyConfiguration": {
        "useApifyProxy": true
    },
    "incrementalMode": false,
    "emitUnchanged": false,
    "emitExpired": false,
    "maxNotifyListings": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/eventim-de-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 = {
    "mode": "search",
    "cities": ["Berlin"],
    "categories": [],
    "dateFrom": "",
    "dateTo": "",
    "inStockOnly": False,
    "sort": "DateAsc",
    "urls": [
        "https://www.eventim.de/en/city/berlin-1/",
        "https://www.eventim.de/en/event/bsv-eintracht-mahlsdorf-nofv-oberliga-nord-sportplatz-am-rosenhag-21994953/",
        "https://www.eventim.de/en/city/berlin-1/venue/admiralspalast-berlin-702/",
    ],
    "fetchDetails": False,
    "maxItems": 20,
    "maxPages": 0,
    "proxyConfiguration": { "useApifyProxy": True },
    "incrementalMode": False,
    "emitUnchanged": False,
    "emitExpired": False,
    "maxNotifyListings": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/eventim-de-event-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 '{
  "mode": "search",
  "cities": [
    "Berlin"
  ],
  "categories": [],
  "dateFrom": "",
  "dateTo": "",
  "inStockOnly": false,
  "sort": "DateAsc",
  "urls": [
    "https://www.eventim.de/en/city/berlin-1/",
    "https://www.eventim.de/en/event/bsv-eintracht-mahlsdorf-nofv-oberliga-nord-sportplatz-am-rosenhag-21994953/",
    "https://www.eventim.de/en/city/berlin-1/venue/admiralspalast-berlin-702/"
  ],
  "fetchDetails": false,
  "maxItems": 20,
  "maxPages": 0,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "maxNotifyListings": 50
}' |
apify call abotapi/eventim-de-event-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,abotapi/eventim-de-event-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/CZm9yzubYlFe2P4td/builds/GZ2eyrdOVHqDkNSfX/openapi.json
