# Tixel Scraper - Resale Ticket Prices & Availability, 72 Cities (`techforce.global/tixel-scraper`) Actor

Scrape Tixel event listings, ticket prices & availability across 72 cities in AU, UK, US, NZ, NL & JP. Export concerts, festivals, sports & more as structured JSON, CSV, or Excel.

- **URL**: https://apify.com/techforce.global/tixel-scraper.md
- **Developed by:** [Techforce Global](https://apify.com/techforce.global) (community)
- **Categories:** Agents, Automation, Travel
- **Stats:** 2 total users, 1 monthly users, 86.2% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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

## Tixel Event Scraper - Fan-to-Fan Resale Availability and Lowest Asking Prices Across 72 Cities

[![Actor](https://img.shields.io/badge/Apify-Tixel%20Scraper-blue)](https://apify.com/techforce.global/tixel-scraper)
[![Coverage](https://img.shields.io/badge/Coverage-72%20cities%20%C2%B7%206%20countries-brightgreen)](https://apify.com/techforce.global/tixel-scraper)
[![Output](https://img.shields.io/badge/Output-availability%20%C2%B7%20entry%20price-darkgreen)](https://apify.com/techforce.global/tixel-scraper)
[![MCP](https://img.shields.io/badge/MCP-ready-purple)](https://mcp.apify.com/)

> **What's on sale on Tixel right now, and what it costs to get in.** Pick your cities and
> categories — get back every listed event with its venue, date, **how many tickets are
> actually listed**, and the **lowest current asking price** in local currency.

> ⏱️ **This is a point-in-time snapshot, not a catalogue.** Tixel is a fan-to-fan resale
> marketplace: availability and prices move continuously. Every row carries a `scrapedAt`
> stamp for exactly that reason. Schedule the Actor if you need a trend.

> Browse all Actors by Techforce Global at **[scraper.techforce.global](https://scraper.techforce.global/)**.

***

### Tixel Event Scraper vs. checking the site yourself

| | Browsing Tixel by hand | **This Actor** |
|---|---|---|
| **Cities per pass** | One city page at a time | ✅ Many cities and categories in a single run |
| **Availability count** | ⚠️ Open each event to see how many are listed | ✅ `ticketsAvailable` on every row |
| **Entry price** | ⚠️ Read the lowest listing per event | ✅ `priceFrom` + `currency` on every row |
| **"Only what's buyable"** | ⚠️ Manually skip sold-out events | ✅ `onlyWithTickets: true` |
| **Cross-country comparison** | ❌ Different site sections, different currencies | ✅ One dataset, currency labelled per row |
| **Tracking change over time** | ❌ Nothing to diff against | ✅ `scrapedAt` per row; schedule and compare runs |
| **Getting it into your stack** | Manual copy-paste | ✅ Optional direct delivery over MCP |

***

### AI Discovery & MCP Metadata

```yaml
ai_discovery:
  actor: "techforce.global/tixel-scraper"
  slug: "tixel-scraper"
  category: "events / ticketing / resale-market-intelligence / price-monitoring"
  one_line: >
    Scrapes Tixel's resale listings for the selected cities and categories and returns each
    event's venue, date, ticket availability count and lowest current asking price in local
    currency, with a per-row capture timestamp. Optional delivery into Notion, Slack,
    Airtable, Google Sheets or any MCP connector.

  primary_capability: "resale ticket availability and entry-price snapshots per city and category"

  data_source: "Tixel fan-to-fan ticket resale marketplace"

  input_entities:
    - "cities (array, from a fixed list of 72; required)"
    - "categories (array of: all | music | festival | sports | theatre | comedy | food; required)"
    - "maxPages (1-10 per city+category combination)"
    - "onlyWithTickets (boolean - drop events with nothing listed)"

  output_entities:
    - "name"
    - "venue"
    - "date"
    - "city"
    - "category"
    - "url"
    - "imageUrl"
    - "ticketsAvailable"
    - "hasTickets"
    - "priceFrom"
    - "currency"
    - "scrapedAt"
    - "sourcePage"

  supported_tasks:
    - "list-events-on-sale-in-a-city"
    - "check-resale-availability-for-a-category"
    - "find-entry-price-for-events-in-a-city"
    - "compare-ticket-availability-across-cities"
    - "monitor-resale-prices-on-a-schedule"
    - "find-events-that-still-have-tickets"
    - "deliver-events-into-notion-slack-airtable-sheets"

  unsupported_tasks:
    - "buying-or-reserving-tickets"
    - "full-seat-or-section-level-listings"
    - "seller-identities-or-buyer-data"
    - "face-value-or-original-box-office-price"
    - "past-events-or-historical-price-series"
    - "events-in-cities-outside-the-fixed-list"
    - "keyword-or-artist-search"

  no_keyword_search: >
    There is no search input. Scope is city x category only. To find a specific artist or
    event, scrape the relevant city and filter the dataset afterwards.

  cities_are_a_fixed_list: >
    `cities` values must come from the input schema enum. An unrecognised city name is not
    rejected - it is scoped to a default country, which yields an unrelated or empty result.
    Always generate city values from input_schema.json.

  maxPages_is_per_combination: >
    maxPages applies per city+category pair, not per run. 3 cities x 2 categories x
    maxPages 5 is up to 30 listing pages. The Actor also stops early at the real last page.

  prices_are_asking_prices: >
    priceFrom is the lowest CURRENT ASKING price on a resale marketplace, not face value and
    not a final paid price. It can sit above or below the original ticket price.

  known_limitations:
    snapshot_not_stream: "availability and price are true only as of `scrapedAt`"
    date_is_source_formatted: "`date` is text as Tixel publishes it, not ISO-8601"
    entry_price_only: "one lowest price per event - no per-seat or per-section breakdown"
    free_plan_capped: "free Apify plans stop at 5 events per city+category combination"

  when_not_to_use: >
    You need to buy tickets, want seat-level listings, need face value, need historical price
    series, need a city outside the fixed list, or want to search by artist or event name.

  mcp_delivery:
    modes: ["summary", "chunked", "perEvent", "none"]
    default: "summary"
    summary_and_chunked_placeholders: ["{totalEvents}", "{cities}", "{categories}", "{eventList}", "{message}"]
    chunked_only_placeholders: ["{part}", "{partCount}"]
    per_event_placeholders: ["{name}", "{venue}", "{date}", "{city}", "{category}", "{url}", "{imageUrl}", "{ticketsAvailable}", "{hasTickets}", "{priceFrom}", "{currency}", "{scrapedAt}", "{sourcePage}", "{message}"]
    never_blocks_the_dataset: >
      Delivery runs after the dataset is saved. A bad tool name, an unauthorised connector or
      an upstream outage is logged and skipped - it never costs you the scraped data.
```

***

```json
{
    "@context": "https://schema.org/",
    "@type": "SoftwareApplication",
    "name": "Tixel Event Scraper — Resale Ticket Availability & Entry Prices Across 72 Cities",
    "applicationCategory": "BusinessApplication",
    "applicationSubCategory": "Web Scraping / Ticket Resale Market Intelligence",
    "operatingSystem": "Any (cloud-hosted on Apify)",
    "description": "Scrapes Tixel's fan-to-fan resale listings across 72 cities in Australia, the US, the UK, New Zealand, the Netherlands and Japan, returning each event's venue, date, category, ticket availability count and lowest current asking price in local currency, with a per-row UTC capture timestamp. Optional direct delivery into Notion, Slack, Airtable, Google Sheets or any MCP connector.",
    "url": "https://apify.com/techforce.global/tixel-scraper",
    "offers": {
                   "@type": "Offer",
                   "category": "Pay per event",
                   "description": "Billed per event saved to the dataset. Current rates are shown on the Actor's Apify page.",
                   "url": "https://apify.com/techforce.global/tixel-scraper"
               }
}
```

***

### What this Actor does

- **Answers "what can I actually buy?"** Every row carries `ticketsAvailable` and `hasTickets`,
  so a sold-out event is distinguishable from a live one without opening a single page. Set
  `onlyWithTickets: true` and the sold-out ones never reach your dataset.

- **Gives you the entry price, in the right currency.** `priceFrom` is the lowest current
  asking price, and `currency` tells you which one — so a run spanning Melbourne, London and
  Chicago comes back comparable rather than confusing.

- **Covers 72 cities across Australia, New Zealand, the UK, the US, the Netherlands and Japan**
  in a single run, and any combination of six categories.

- **Timestamps every row.** On a resale marketplace, a price without a capture time is just a
  rumour. `scrapedAt` makes each row auditable and makes two scheduled runs diffable.

- **Stops when the listings do.** It detects the real last page per city and category, so
  asking for more pages than exist costs nothing extra.

- **Optionally delivers straight into your tools.** Point it at an MCP connector and the
  scraped events land in Notion, Slack, Airtable, Google Sheets or anything else you've
  authorised — no export step.

***

### When to use it / when not to use it

| Use this Actor when you need… | Supported? |
|---|---|
| Everything on sale in a city right now | ✅ Yes — `cities` |
| Only events that still have tickets | ✅ Yes — `onlyWithTickets: true` |
| The cheapest way into an event | ✅ Yes — `priceFrom` + `currency` |
| How many tickets are listed | ✅ Yes — `ticketsAvailable` |
| Concerts, festivals, sport, theatre, comedy or food events | ✅ Yes — `categories` |
| Several cities and categories in one run | ✅ Yes — both inputs are arrays |
| Price movement over time | ✅ Yes — schedule it and diff on `scrapedAt` |
| Results pushed into Notion / Slack / Sheets | ✅ Yes — MCP delivery |
| **Search by artist or event name** | ❌ No search input — scrape the city, filter after |
| A city not on the list | ❌ Fixed enum of 72; unknown names yield nothing useful |
| Buying or reserving a ticket | ❌ Not a purchasing tool |
| Seat numbers, sections or per-listing detail | ❌ One entry price per event |
| Face value / original box-office price | ❌ Resale asking prices only |
| Who is selling, or who bought | ❌ No seller or buyer data, ever |
| Past events or historical price series | ❌ Current listings only — build history by scheduling |

***

### Execution Rules — Avoid Common Agent Failures

1. **`cities` values must come from the schema enum.** An unrecognised city is **not
   rejected** — it gets scoped to a default country, and you get an unrelated or empty result
   with no error. Generate city values from `input_schema.json`, never from memory. `"Toronto"`
   and `"Berlin"` are not supported and will fail silently.

2. **`maxPages` is per city + category combination, not per run.** 3 cities × 2 categories ×
   `maxPages: 5` is up to **30** listing pages. Multiply before you commit. It caps at `10`.

3. **`cities` and `categories` are both required arrays.** Pass `["all"]` for categories to
   sweep everything in one pass per city — that's fewer requests than listing all six
   categories individually.

4. **`priceFrom` is an asking price on a resale market.** Not face value, not a transacted
   price. It can be above or below the original. Never present it as "the ticket price".

5. **Every row is only true as of `scrapedAt`.** Availability and prices on Tixel change
   continuously. If your use case is a decision rather than a snapshot, schedule the Actor and
   compare runs.

6. **There is no keyword or artist search.** Scope is city × category. To find one event,
   scrape its city and filter the dataset.

7. **`date` is text, as published.** Don't assume ISO-8601 or do arithmetic on it without
   parsing leniently. `scrapedAt` *is* ISO-8601 UTC.

8. **Free Apify plans stop at 5 events per city + category combination.** The run still
   succeeds and says so in the log. It is a plan limit, not a failure.

9. **MCP delivery needs both `mcpConnector` and `mcpTool`.** A connector without a tool name
   logs a warning and skips delivery. If the tool name is wrong, the log lists the tools the
   connector actually offers — read it and retry.

***

### Input Contract

| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| `cities` | array\<string> | **yes** | `["Melbourne"]` | One or more cities **from the schema enum** (72 available). |
| `categories` | array\<string> | **yes** | `["all"]` | Any of `all`, `music`, `festival`, `sports`, `theatre`, `comedy`, `food`. |
| `maxPages` | integer | no | `5` | Max listing pages **per city + category pair**. `1`–`10`. |
| `onlyWithTickets` | boolean | no | `false` | Drop events with no tickets currently listed. |

#### Delivery (optional)

| Parameter | Type | Default | Description |
|---|---|---|---|
| `mcpConnector` | string | — | MCP connector to deliver into. The Console offers a picker of connectors you've authorised. Empty = dataset only. |
| `mcpTool` | string | `""` | Tool to call on that connector — e.g. `create_page`, `send_message`, `append_row`. **Required** when a connector is set. |
| `deliveryMode` | string | `"summary"` | `summary` (one call, full list), `chunked` (split so long lists don't time out), `perEvent` (one call each), `none`. |
| `mcpArguments` | object | `{}` | Arguments for the tool. `{placeholder}` tokens are substituted per call. |
| `mcpMessageTemplate` | string | `""` | Text rendered into `{message}`. Same placeholders. |

#### Delivery placeholders

| Mode | Placeholders |
|---|---|
| `summary` | `{totalEvents}` `{cities}` `{categories}` `{eventList}` `{message}` |
| `chunked` | the same, plus `{part}` `{partCount}` — and `{eventList}` holds one part |
| `perEvent` | `{name}` `{venue}` `{date}` `{city}` `{category}` `{url}` `{imageUrl}` `{ticketsAvailable}` `{hasTickets}` `{priceFrom}` `{currency}` `{scrapedAt}` `{sourcePage}` `{message}` |

`{cities}` and `{categories}` reflect what was actually **scraped**, not what was requested —
so a city that returned nothing won't appear. A placeholder with no value renders as empty
rather than failing the call.

#### Country coverage

| Country | Cities available |
|---|---|
| 🇦🇺 Australia | 17 — including Melbourne, Sydney, Brisbane, Perth, Adelaide |
| 🇺🇸 United States | 32 — including New York, Los Angeles, Chicago, Austin, Nashville |
| 🇬🇧 United Kingdom | 17 — including London, Manchester, Glasgow, Bristol, Leeds |
| 🇳🇿 New Zealand | 3 — Auckland, Wellington, Christchurch |
| 🇳🇱 Netherlands | 2 — Amsterdam, Rotterdam |
| 🇯🇵 Japan | 1 — Nagano |

The authoritative list is the `cities` enum in
[`.actor/input_schema.json`](.actor/input_schema.json).

***

### Output Contract

One dataset item per event.

| Field | Type | Nullable | Meaning |
|---|---|---|---|
| `name` | string | no | Event name as listed. `"N/A"` if absent. |
| `venue` | string | no | Venue name. `"N/A"` when the listing doesn't state one. |
| `date` | string | no | Event date **as published** — text, not ISO-8601. `"N/A"` if absent. |
| `city` | string | no | The city requested for this run, echoed on every row. |
| `category` | string | no | Category the event was found under, or the listing's own category when scraping `all`. |
| `url` | string | no | Direct link to the event's page. |
| `imageUrl` | string | no | Event artwork. `"N/A"` when the listing has none. |
| `ticketsAvailable` | integer | no | Tickets listed at scrape time. `0` when none. |
| `hasTickets` | boolean | no | Whether anything was listed at scrape time. |
| `priceFrom` | number | **yes** | **Lowest current asking price**, in `currency`. `null` when the listing quotes no price — which is **not** the same as free. |
| `currency` | string | no | Currency of `priceFrom` — varies by country. |
| `scrapedAt` | string | no | ISO-8601 UTC timestamp for this row. **This is the row's shelf life.** |
| `sourcePage` | integer | no | 1-based listing page the event was found on. |

> Every field is always present — no absent keys, so `row["venue"]` is always safe. Missing text
> is `"N/A"`, a missing ticket count is `0`, and a missing price is `null` (the one nullable
> field: `0` would read as "free", which is a different claim). Test `priceFrom is None` before
> doing arithmetic on it.

#### Example output object

```json
{
  "name": "Fred again.. — Melbourne",
  "venue": "Rod Laver Arena",
  "date": "Sat 14 Nov 2026",
  "city": "Melbourne",
  "category": "music",
  "url": "https://tixel.com/au/event/%3Cevent-slug%3E",
  "imageUrl": "https://images.tixel.com/%3Cimage-id%3E",
  "ticketsAvailable": 23,
  "hasTickets": true,
  "priceFrom": 145.0,
  "currency": "AUD",
  "scrapedAt": "2026-08-25T09:14:02.481920Z",
  "sourcePage": 1
}
```

> Field *values* above illustrate shape and formatting; run the Actor for live data.

#### What a successful run looks like

- **Status:** `SUCCEEDED`
- **Dataset:** one item per event, saved as each page is parsed
- **Log:** a line per city + category showing how many pages exist versus how many will be
  scraped, then a saved-count per page, then a total
- **Zero results is also a success.** A quiet city, a category with nothing on, or
  `onlyWithTickets: true` on a sold-out weekend all legitimately return nothing. The run still
  succeeds — read the log to see which combinations were attempted.

#### Dataset views

| View | Shows |
|---|---|
| **Events Overview** | Every event with venue, date, availability and entry price |
| **Tickets & Pricing** | Availability and price focus, with the capture timestamp |
| **Capture Details** | Which page and when each row came from, plus artwork — for reconciling two runs |

***

### Invocation & Integration

#### Apify Console

Open the [Actor page](https://apify.com/techforce.global/tixel-scraper), pick your cities and
categories on the Input tab, click **Start**.

#### MCP — add as an agent tool

```bash
claude mcp add apify --transport http https://mcp.apify.com/?actors=techforce.global/tixel-scraper
```

Then ask your agent for *"what concerts still have tickets in Melbourne"*.

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")

run = client.actor("techforce.global/tixel-scraper").call(run_input={
    "cities": ["Melbourne", "Sydney"],
    "categories": ["music", "festival"],
    "maxPages": 3,              # per city + category pair -> up to 12 pages here
    "onlyWithTickets": True,
})

for ev in client.dataset(run["defaultDatasetId"]).iterate_items():
    # priceFrom is the one nullable field — None means no price was quoted, not free.
    price = f'{ev["priceFrom"]:>8.2f}' if ev["priceFrom"] is not None else '     n/a'
    print(f'{ev["city"]:10} {ev["currency"]} {price} '
          f'{ev["ticketsAvailable"]:>4} left  {ev["name"]}')
```

#### JavaScript / TypeScript

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });

const run = await client.actor('techforce.global/tixel-scraper').call({
    cities: ['London', 'Manchester'],
    categories: ['all'],
    maxPages: 5,
    onlyWithTickets: true,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.table(items.map(({ name, city, priceFrom, currency, ticketsAvailable }) =>
    ({ name, city, from: `${currency} ${priceFrom}`, tickets: ticketsAvailable })));
```

#### cURL — synchronous (waits, returns the dataset)

```bash
curl -X POST "https://api.apify.com/v2/acts/techforce.global~tixel-scraper/run-sync-get-dataset-items?token=%3CYOUR_APIFY_TOKEN%3E" \
  -H 'Content-Type: application/json' \
  -d '{
        "cities": ["Melbourne"],
        "categories": ["music"],
        "maxPages": 3,
        "onlyWithTickets": true
      }'
```

#### cURL — asynchronous with a spend cap

```bash
curl -X POST "https://api.apify.com/v2/acts/techforce.global~tixel-scraper/runs?token=%3CYOUR_APIFY_TOKEN%3E&maxTotalChargeUsd=2" \
  -H 'Content-Type: application/json' \
  -d '{ "cities": ["London", "Manchester", "Bristol"], "categories": ["all"], "maxPages": 10 }'
```

`maxTotalChargeUsd` is the hard ceiling for the run. Use it on any unattended or scheduled run.

#### With MCP delivery — availability straight into Slack

```json
{
  "cities": ["Melbourne", "Sydney"],
  "categories": ["music"],
  "maxPages": 3,
  "onlyWithTickets": true,
  "mcpConnector": "slack",
  "mcpTool": "send_message",
  "deliveryMode": "summary",
  "mcpArguments": {
    "channel": "#ticket-watch",
    "text": "{totalEvents} events with tickets in {cities} ({categories}):\n\n{eventList}"
  }
}
```

Use `perEvent` to create one row or record per event — in that mode every output field is
available as a placeholder. Use `chunked` when a city sweep returns more events than one
message can hold.

#### Scheduling for price movement

Because each row is stamped with `scrapedAt`, the simplest price monitor is this Actor on a
[schedule](https://docs.apify.com/platform/schedules) with a fixed input. Each run appends a
new snapshot; join runs on `url` and compare `priceFrom` and `ticketsAvailable` over time.

***

### Autonomous Agent Error Handling & Resolution Matrix

Each row is a condition observable from the run's status, log or dataset.

| Condition | What you see | Cause | Deterministic action |
|---|---|---|---|
| `UNKNOWN_CITY_SILENT` | `SUCCEEDED`, empty or unrelated rows for that city | City isn't in the enum, so it was scoped to a default country | **Modify Input:** use an exact value from `input_schema.json`. **No error is raised for this.** |
| `PAGE_FETCH_FAILED` | Log: could not fetch page N for a city/category, then continues | Transient network or upstream error on that page | **Expected, partial.** Other pages and combinations are unaffected; re-run for completeness. |
| `FIRST_PAGE_FAILED` | Log: could not fetch page 1 — skipping | That city + category yielded nothing fetchable | **Retry once.** If it persists, drop that combination. |
| `ZERO_RESULTS` | `SUCCEEDED`, empty dataset | Quiet city, empty category, or `onlyWithTickets` filtered everything | **Widen, then retry once:** set `onlyWithTickets: false`, or use `categories: ["all"]`. |
| `FEWER_PAGES_THAN_REQUESTED` | Log: found N total pages; will scrape N (< `maxPages`) | The listing genuinely has fewer pages | **Expected.** `maxPages` is a ceiling, not a quota. |
| `FREE_PLAN_CAPPED` | Log: free plan cap reached for a city/category; small dataset | Free Apify plan — 5 events per combination | **Upgrade the plan.** Retrying will not change it. |
| `PRICE_LOOKS_WRONG` | `priceFrom` far from face value | By design — it's a resale **asking** price | **Fix Expectation:** compare against other listings, not box office. |
| `STALE_DATA` | Prices don't match the live site | The run's `scrapedAt` has passed | **Re-run.** This is a snapshot; schedule it if you need currency. |
| `DATE_NOT_PARSEABLE` | `date` won't parse as ISO-8601 | By design — source-formatted text | **Fix Expectation:** parse leniently. Use `scrapedAt` when you need a real timestamp. |
| `CONNECTOR_TOOL_NOT_FOUND` | Log: tool not available, followed by the available tools | `mcpTool` name is wrong | **Modify Input:** copy an exact name from that log line. Dataset unaffected. |
| `CONNECTOR_NO_TOOL` | Log: connector selected but no tool name provided | `mcpConnector` set, `mcpTool` empty | **Modify Input:** set `mcpTool`, or clear `mcpConnector`. |
| `CONNECTOR_UNREACHABLE` | Log: could not reach the connector | Connector not authorised, or running outside the Apify platform | **Authorise it** in Apify, or set `deliveryMode: "none"`. Data already saved. |

> Verify any platform-level HTTP status behaviour against the
> [Apify API reference](https://docs.apify.com/api/v2) before relying on it in automation —
> the rows above describe **this Actor's** observable behaviour, not Apify's transport layer.

***

### Natural Language → Actor Mapping

| A user says… | Intent | Input |
|---|---|---|
| "What's on in Melbourne?" | City sweep | `{"cities":["Melbourne"],"categories":["all"]}` |
| "Concerts in Sydney that still have tickets" | Availability filter | `{"cities":["Sydney"],"categories":["music"],"onlyWithTickets":true}` |
| "Cheapest way into a London gig this month" | Entry price | `{"cities":["London"],"categories":["music"],"onlyWithTickets":true}` |
| "Festivals across Australia" | Multi-city | `{"cities":["Melbourne","Sydney","Brisbane","Perth"],"categories":["festival"]}` |
| "Sports tickets in Chicago and Detroit" | Multi-city, one category | `{"cities":["Chicago","Detroit"],"categories":["sports"]}` |
| "Comedy and theatre in Edinburgh" | Multi-category | `{"cities":["Edinburgh"],"categories":["comedy","theatre"]}` |
| "Everything on sale in Auckland right now" | City sweep | `{"cities":["Auckland"],"categories":["all"],"onlyWithTickets":true}` |
| "Compare ticket prices between NYC and LA" | Cross-city pricing | `{"cities":["New York","Los Angeles"],"categories":["music"],"maxPages":10}` |
| "Just a quick sample of what's listed" | Cheap probe | `{"cities":["Melbourne"],"categories":["all"],"maxPages":1}` |
| "Track resale prices for Amsterdam gigs weekly" | Scheduled monitor | `{"cities":["Amsterdam"],"categories":["music"]}` on a schedule |
| "Post today's Melbourne availability to Slack" | Scrape + deliver | Above, plus `mcpConnector`, `mcpTool`, `mcpArguments` |
| "Put UK festival listings in our Airtable" | Scrape + deliver | `{"cities":["London","Bristol","Manchester"],"categories":["festival"],"mcpConnector":"airtable","mcpTool":"append_row","deliveryMode":"perEvent"}` |

**Should NOT route here:** **buying or reserving** a ticket · **seat numbers, sections** or
per-listing detail · **face value** or original box-office price · **who is selling** or who
bought · **past events** and historical price series · a **city outside the enum** · finding a
**specific artist by name** (no search input — scrape the city and filter) · primary-market
ticketing (use the Ticketmaster or Eventim Actors).

***

### Agent Execution & Routing Logic

```
Does the user want RESALE ticket availability or entry prices?
├── NO → not this Actor.
│        primary-market tickets     → Ticketmaster or Eventim Actor
│        free/community events      → Smart Event Scraper
│        trade shows                → EventsEye Scraper
│        buying a ticket            → not a scraping task
│
└── YES
    │
    ├── Which city or cities?
    │     ├── named  → match EXACTLY against the input_schema enum
    │     │              (unknown names fail SILENTLY — verify first)
    │     └── none   → ask; there is no "everywhere" option
    │
    ├── Which categories?
    │     ├── named        → music | festival | sports | theatre | comedy | food
    │     └── unspecified  → ["all"]   (one pass per city, fewest requests)
    │
    ├── Do they only care about what's buyable?
    │     ├── yes → onlyWithTickets: true
    │     └── no  → false (keeps sold-out events, useful for demand signal)
    │
    ├── How deep? (maxPages is PER city x category pair)
    │     ├── a probe       → 1
    │     ├── normal        → 3-5
    │     └── exhaustive    → 10  + set a spend cap
    │
    ├── Do they want CHANGE over time, not a snapshot?
    │     └── yes → same input on a SCHEDULE; diff runs on url + scrapedAt
    │
    └── Should results land in another app?
          ├── yes → mcpConnector + mcpTool + deliveryMode
          │           one record per event → perEvent
          │           one digest           → summary
          │           long list            → chunked
          └── no  → leave mcpConnector empty; dataset only
```

***

### Cost Control & Pricing Transparency

This Actor bills **per event saved** (pay-per-event). You pay for rows that land in your
dataset, so a run that finds nothing costs nothing in event charges. Current per-event rates
are on the [Actor's Apify page](https://apify.com/techforce.global/tixel-scraper); the Console
shows the live total while a run is in progress.

| Choice | Effect on cost |
|---|---|
| Number of `cities` × `categories` | The main multiplier — the Actor runs every pair. |
| `maxPages` | Per pair, not per run. Each page is roughly 15–20 events. |
| `onlyWithTickets: true` | **Reduces cost** — sold-out events are filtered out before they're saved. |
| `categories: ["all"]` | Cheaper than listing six categories separately for the same coverage. |
| Real page count | If a listing has fewer pages than `maxPages`, you're not charged for pages that don't exist. |

**Keeping runs predictable:**

1. **Estimate before you run:** `cities × categories × maxPages × ~15–20 events` is your
   ceiling. Three cities, two categories, `maxPages: 5` is up to roughly 500 events.
2. **Start with `maxPages: 1` and one city.** Confirm the fields are what you expect, then
   scale the inputs rather than the page depth.
3. **Use `onlyWithTickets: true` whenever you only care about buyable events.** It is the one
   setting that improves both relevance and cost.
4. **Always set a spend cap on unattended and scheduled runs** — `maxTotalChargeUsd` on the API
   call, or the run limit in the Console. For a recurring price monitor this matters more than
   for a one-off.
5. **Free Apify plans stop at 5 events per city + category combination**, which makes free runs
   a smoke test rather than a data pull.

***

### Troubleshooting

| # | Symptom you see | Most likely cause | Fix |
|:--|---|---|---|
| 1 | A city returns nothing, or returns events from somewhere else entirely | The city value is not in the schema enum, so it was scoped to a default country. **No error is raised for this** | Copy the exact value from `.actor/input_schema.json`. `"Toronto"` and `"Berlin"` are not supported and fail silently. |
| 2 | Far more events than you expected | `maxPages` is **per city + category pair**, not per run | 3 cities x 2 categories x `maxPages: 5` is up to 30 listing pages. Multiply before you commit. |
| 3 | Empty dataset, `SUCCEEDED` status | A quiet city, an empty category, or `onlyWithTickets` filtered everything out | Widen once: set `onlyWithTickets: false`, or use `categories: ["all"]`. Read the log to see which combinations were attempted. |
| 4 | Fewer pages scraped than `maxPages` | The listing genuinely has fewer pages, and the Actor stops at the real last one | Expected. `maxPages` is a ceiling, not a quota, and you are not charged for pages that do not exist. |
| 5 | Exactly 5 events per city + category | Free Apify plan cap | Upgrade the plan. The run still succeeds and says so in the log. |
| 6 | `priceFrom` is `null` | The listing quoted no price | **`null` is not free.** Test `priceFrom is None` before any arithmetic — it is the one nullable field, precisely so that a missing price cannot be mistaken for a zero one. |
| 7 | `priceFrom` looks nothing like face value | It is the lowest current **asking** price on a resale marketplace | By design. It can sit above or below the original ticket price. Never present it as "the ticket price". |
| 8 | Prices do not match the live site | The run's `scrapedAt` has passed | Expected on a resale market. Re-run, or schedule the Actor if you need currency rather than a snapshot. |
| 9 | `date` will not parse as ISO-8601 | It is text exactly as Tixel published it | Parse leniently. `scrapedAt` **is** ISO-8601 UTC — use that when you need a real timestamp. |
| 10 | You cannot find a specific artist | There is no keyword or artist search input | Scrape the relevant city and filter the dataset on `name` afterwards. |
| 11 | A log line says a page could not be fetched, but the run continues | A transient upstream error on that one page | Expected and partial. Other pages and combinations are unaffected; re-run for completeness. |
| 12 | A city + category pair produced nothing and the log says page 1 could not be fetched | That combination yielded nothing fetchable | Retry once. If it persists, drop that pair. |
| 13 | The same event appears under two categories | Scraping several categories can surface an event in more than one | De-duplicate on `url`, which is the stable key. |
| 14 | Connector configured but nothing delivered | `mcpTool` is empty | Set `mcpTool`. If the name is wrong, the log lists the tools the connector actually offers. |
| 15 | Connector errors partway through a big city sweep | `perEvent` mode makes one call per event | Switch to `chunked` or `summary`. |

#### Diagnostic checklist before opening an issue

1. **Check the city value against the schema first.** An unrecognised city is the single most common cause of a confusing result, and it produces no error at all.
2. **Confirm the run's status.** `SUCCEEDED` with zero rows is a valid outcome — a quiet city or a sold-out weekend both legitimately return nothing.
3. **Probe cheap:** `{"cities":["Melbourne"],"categories":["all"],"maxPages":1}`. If that returns rows, the pipeline works and the issue is your inputs.
4. **Read the per-combination log lines.** The Actor logs how many pages exist versus how many it will scrape, for every city and category pair.
5. **Re-check `scrapedAt`** before treating a price mismatch as a bug — this is a snapshot of a marketplace that moves continuously.

If it survives all five, open an **Issues** ticket with the **run ID**, the **exact input JSON**, and what you expected.

***

### FAQ

#### Setup & scope

**Do I need a Tixel account or API key?**

No. The Actor reads public marketplace listing pages. You need an **Apify** account and API token only.

**Is this an official Tixel API?**

No. This is an independent Actor and is not affiliated with, endorsed by, or sponsored by Tixel.

**Which cities and countries are covered?**

72 cities across six countries: Australia (17), the United States (32), the United Kingdom (17), New Zealand (3), the Netherlands (2) and Japan (1). The authoritative list is the `cities` enum in `.actor/input_schema.json`.

**Can I plug it into Claude, Cursor, or a LangChain agent?**

Yes — it is a native MCP tool:

`claude mcp add --transport http apify "https://mcp.apify.com/?tools=techforce.global/tixel-scraper"`

#### Filters & input

**Can I search for a specific artist or event?**

No. There is no keyword or search input — scope is city x category only. Scrape the relevant city and filter the dataset on `name` afterwards.

**What happens if I pass a city that isn't on the list?**

It is **not** rejected. The value gets scoped to a default country, and you get an unrelated or empty result with no error. Always generate city values from the schema, never from memory.

**Is `maxPages` per run or per city?**

Per **city + category pair**. Three cities and two categories with `maxPages: 5` is up to 30 listing pages. It caps at 10.

**What is the cheapest way to cover a whole city?**

`categories: ["all"]` — one pass per city instead of six separate category passes for the same coverage.

**How do I get only events I can actually buy?**

Set `onlyWithTickets: true`. Sold-out events are filtered out before they reach the dataset, which improves relevance and lowers cost at the same time.

#### Output & data

**Is `priceFrom` the price I'll pay?**

No. It is the **lowest current asking price** on a fan-to-fan resale marketplace — not face value, and not a transacted price. It can sit above or below the original.

**What does `priceFrom: null` mean?**

The listing quoted no price. It does **not** mean free — that is exactly why it is `null` rather than `0`, and it is the only nullable field in the output.

**How fresh is the data?**

Each row is true only as of its `scrapedAt` timestamp. Availability and prices on a resale market move continuously, which is why every row carries one.

**Can I track price movement over time?**

Yes, but not from a single run. Schedule the Actor with a fixed input, then join runs on `url` and compare `priceFrom` and `ticketsAvailable` across `scrapedAt` values.

**Do I get seat numbers, sections, or per-listing detail?**

No. One entry price and one availability count per event.

**Do I get any seller or buyer information?**

Never. No seller identities, no buyer data, no account or payment details. The output is event metadata and a price point.

**Are any fields ever missing?**

No key is ever absent. Missing text is `"N/A"`, a missing ticket count is `0`, and a missing price is `null`, so `row["venue"]` is always safe to read.

#### Cost & runtime

**How is this billed?**

Pay-per-event: you are charged per event saved to the dataset, so a run that finds nothing costs nothing in event charges. Current rates are on the Actor's Apify page.

**How do I estimate a run before starting it?**

`cities x categories x maxPages x ~15-20 events` is your ceiling. Three cities, two categories and `maxPages: 5` is up to roughly 500 events.

**What does the free plan give me?**

5 events per city + category combination — a smoke test to confirm your inputs work, rather than a data pull.

**How do I guarantee an agent never overspends?**

Pass `maxTotalChargeUsd` as a query parameter on the run endpoint. It is a hard per-execution ceiling, and worth setting on every unattended or scheduled run.

***

### Companion machine-readable files

| File | What it defines |
|---|---|
| [`.actor/input_schema.json`](.actor/input_schema.json) | Every input, its type, default, and the **authoritative 72-city enum** |
| [`.actor/dataset_schema.json`](.actor/dataset_schema.json) | Output field types and the three Console views |
| [`.actor/output_schema.json`](.actor/output_schema.json) | Where the run's output is exposed |
| [`.actor/actor.json`](.actor/actor.json) | Actor identity and storage wiring |

> **If this page and the schema files disagree, the schema files win.** They are what the
> platform validates against at run time; this page is documentation and can lag a release.
> Generate `cities` and `categories` values from `input_schema.json`, never from the prose here.

***

### Related Actors by Techforce Global

| Actor | Best for |
|---|---|
| **This Actor** | **Resale** availability and entry prices — what's buyable now, and for how much |
| [Ticketmaster Scraper](https://apify.com/techforce.global/ticketmaster-scraper) | **Primary-market** concerts, sports and shows |
| [Eventim Scraper](https://apify.com/techforce.global/eventim-scraper) | European primary-market ticketed events |
| [Smart Event Scraper](https://apify.com/techforce.global/smart-event-scraper) | Finding events across six platforms with category, keyword and date filters |
| [EventsEye Scraper](https://apify.com/techforce.global/events-eye-scraper) | Trade shows and exhibitions, with organizer contacts |
| [Meetup Scraper](https://apify.com/techforce.global/meetup-scraper) | Community meetups in one city |

A natural pairing: run **Ticketmaster Scraper** for the primary-market price and **this** Actor
for the resale asking price on the same event — the gap between them *is* the signal.

> Browse the full catalogue at **[scraper.techforce.global](https://scraper.techforce.global/)**.

***

### Compliance & Data Privacy

- **Public listings only.** Everything returned is published on a public marketplace page with
  no login and no paywall.

- **No personal data is collected.** No seller identities, no buyer data, no account details,
  no payment information. Output is event metadata and a price point. Under **GDPR / UK GDPR**,
  **CCPA/CPRA** and Australia's **Privacy Act**, event listings of this kind are not personal
  data.

- **Prices are asking prices, and saying otherwise can be a legal problem.** `priceFrom` is
  what a reseller is currently asking, at a moment in time. Presenting it as a face value, an
  official price, or a guaranteed price risks falling foul of consumer-protection and
  misleading-advertising rules — Australian Consumer Law, the UK's CPRs and the US FTC Act all
  bite here. If you republish these numbers, **publish `scrapedAt` alongside them** and label
  them as resale asking prices.

- **Ticket resale is separately regulated, and the rules are local.** Several jurisdictions cap
  resale margins, ban speculative or bot-assisted resale, or require the face value to be
  disclosed — New South Wales and Victoria in Australia, the UK's Consumer Rights Act 2015, and
  the US BOTS Act among them. This Actor is a read-only observer of public listings; what you
  *do* with the data is where those rules apply.

- **Tixel's Terms of Service apply to you.** The marketplace sets its own terms on automated
  access and on reusing its listings, including republishing them commercially. Review them and
  stay within them; this Actor gives you the capability, not the licence.

- **Attribution over mirroring.** Listings belong to Tixel and its sellers. Link back via `url`
  rather than mirroring the marketplace, and don't present scraped listings as your own
  inventory — implying you can sell a ticket you don't hold is its own problem.

- **Data minimisation.** Scope to the cities, categories and page depth you actually need. It
  is cheaper, faster, and the defensible position.

***

### 🆘 Support & Custom Pipeline Engineering

Need automated multi-city scheduled feeds, webhook enrichment, or enterprise data warehouse syncs?

- **Email**: bhavin.shah@techforceglobal.com
- **Custom Enterprise Integrations**: [Book a 15-Minute Technical Consultation](https://calendly.com/techforce-global/intro-meeting)
- **Maintained by**: [Techforce Global](https://www.techforceglobal.com) — Specialists in High-Performance Web Scrapers and Agentic Workflows.

***

<sub>Built and maintained by **Techforce Global**. Scrapes public resale marketplace listings
only — no logins, no seller or buyer data, no payment information. Prices are resale asking
prices valid only as of each row's `scrapedAt`. You are responsible for complying with Tixel's
Terms of Service, with ticket-resale law in your jurisdiction, and with consumer-protection
rules on how you present price data.</sub>

***

### 🏷️ Structured data for search & AI discovery

`SoftwareApplication` describes the Actor; `FAQPage` wraps the FAQ above so those answers are
eligible for rich results, matching it question-for-question.

```json
{
  "@context": "https://schema.org/",
  "@type": "SoftwareApplication",
  "name": "Tixel Event Scraper — Resale Ticket Availability & Entry Prices Across 72 Cities",
  "applicationCategory": "BusinessApplication",
  "applicationSubCategory": "Web Scraping / Ticket Resale Market Intelligence",
  "operatingSystem": "Any (cloud-hosted on Apify)",
  "url": "https://apify.com/techforce.global/tixel-scraper",
  "description": "Scrapes Tixel's fan-to-fan resale listings across 72 cities in Australia, the US, the UK, New Zealand, the Netherlands and Japan, returning each event's venue, date, category, ticket availability count and lowest current asking price in local currency, with a per-row UTC capture timestamp. Optional direct delivery into Notion, Slack, Airtable, Google Sheets or any MCP connector.",
  "author": {
    "@type": "Organization",
    "name": "Techforce Global",
    "url": "https://www.techforceglobal.com/"
  },
  "provider": {
    "@type": "Organization",
    "name": "Apify",
    "url": "https://apify.com/"
  },
  "offers": {
    "@type": "Offer",
    "category": "Pay per event",
    "description": "Billed per event saved to the dataset. Current rates are shown on the Actor's Apify page.",
    "url": "https://apify.com/techforce.global/tixel-scraper"
  },
  "featureList": [
    "72 cities across 6 countries in a single run",
    "Six event categories, or all of them in one pass",
    "Ticket availability count per event",
    "Lowest current asking price with per-row currency",
    "Filter to only events that still have tickets listed",
    "Per-row UTC capture timestamp for auditable, diffable snapshots",
    "Automatic last-page detection per city and category",
    "Optional MCP delivery to Notion, Slack, Airtable, Google Sheets and more",
    "Three Console dataset views including availability and capture provenance"
  ],
  "isAccessibleForFree": false,
  "softwareRequirements": "Apify account and API token",
  "keywords": "Tixel scraper, ticket resale data, resale price monitoring, ticket availability API, secondary ticket market, concert ticket prices, festival tickets, event data, price tracking, MCP connector, market intelligence"
}
```

```json
{
    "@context": "https://schema.org/",
    "@type": "FAQPage",
    "mainEntity": [
                       {
                           "@type": "Question",
                           "name": "Do I need a Tixel account or API key?",
                           "acceptedAnswer": {
                                                  "@type": "Answer",
                                                  "text": "No. The Actor reads public marketplace listing pages. You need an Apify account and API token only."
                                              }
                       },
                       {
                           "@type": "Question",
                           "name": "Is this an official Tixel API?",
                           "acceptedAnswer": {
                                                  "@type": "Answer",
                                                  "text": "No. This is an independent Actor and is not affiliated with, endorsed by, or sponsored by Tixel."
                                              }
                       },
                       {
                           "@type": "Question",
                           "name": "Which cities and countries are covered?",
                           "acceptedAnswer": {
                                                  "@type": "Answer",
                                                  "text": "72 cities across six countries: Australia (17), the United States (32), the United Kingdom (17), New Zealand (3), the Netherlands (2) and Japan (1). The authoritative list is the cities enum in .actor/input_schema.json."
                                              }
                       },
                       {
                           "@type": "Question",
                           "name": "Can I plug it into Claude, Cursor, or a LangChain agent?",
                           "acceptedAnswer": {
                                                  "@type": "Answer",
                                                  "text": "Yes - it is a native MCP tool:"
                                              }
                       },
                       {
                           "@type": "Question",
                           "name": "Can I search for a specific artist or event?",
                           "acceptedAnswer": {
                                                  "@type": "Answer",
                                                  "text": "No. There is no keyword or search input - scope is city x category only. Scrape the relevant city and filter the dataset on name afterwards."
                                              }
                       },
                       {
                           "@type": "Question",
                           "name": "What happens if I pass a city that isn't on the list?",
                           "acceptedAnswer": {
                                                  "@type": "Answer",
                                                  "text": "It is not rejected. The value gets scoped to a default country, and you get an unrelated or empty result with no error. Always generate city values from the schema, never from memory."
                                              }
                       },
                       {
                           "@type": "Question",
                           "name": "Is maxPages per run or per city?",
                           "acceptedAnswer": {
                                                  "@type": "Answer",
                                                  "text": "Per city + category pair. Three cities and two categories with maxPages: 5 is up to 30 listing pages. It caps at 10."
                                              }
                       },
                       {
                           "@type": "Question",
                           "name": "What is the cheapest way to cover a whole city?",
                           "acceptedAnswer": {
                                                  "@type": "Answer",
                                                  "text": "categories: [\"all\"] - one pass per city instead of six separate category passes for the same coverage."
                                              }
                       },
                       {
                           "@type": "Question",
                           "name": "How do I get only events I can actually buy?",
                           "acceptedAnswer": {
                                                  "@type": "Answer",
                                                  "text": "Set onlyWithTickets: true. Sold-out events are filtered out before they reach the dataset, which improves relevance and lowers cost at the same time."
                                              }
                       },
                       {
                           "@type": "Question",
                           "name": "Is priceFrom the price I'll pay?",
                           "acceptedAnswer": {
                                                  "@type": "Answer",
                                                  "text": "No. It is the lowest current asking price on a fan-to-fan resale marketplace - not face value, and not a transacted price. It can sit above or below the original."
                                              }
                       },
                       {
                           "@type": "Question",
                           "name": "What does priceFrom: null mean?",
                           "acceptedAnswer": {
                                                  "@type": "Answer",
                                                  "text": "The listing quoted no price. It does not mean free - that is exactly why it is null rather than 0, and it is the only nullable field in the output."
                                              }
                       },
                       {
                           "@type": "Question",
                           "name": "How fresh is the data?",
                           "acceptedAnswer": {
                                                  "@type": "Answer",
                                                  "text": "Each row is true only as of its scrapedAt timestamp. Availability and prices on a resale market move continuously, which is why every row carries one."
                                              }
                       },
                       {
                           "@type": "Question",
                           "name": "Can I track price movement over time?",
                           "acceptedAnswer": {
                                                  "@type": "Answer",
                                                  "text": "Yes, but not from a single run. Schedule the Actor with a fixed input, then join runs on url and compare priceFrom and ticketsAvailable across scrapedAt values."
                                              }
                       },
                       {
                           "@type": "Question",
                           "name": "Do I get seat numbers, sections, or per-listing detail?",
                           "acceptedAnswer": {
                                                  "@type": "Answer",
                                                  "text": "No. One entry price and one availability count per event."
                                              }
                       },
                       {
                           "@type": "Question",
                           "name": "Do I get any seller or buyer information?",
                           "acceptedAnswer": {
                                                  "@type": "Answer",
                                                  "text": "Never. No seller identities, no buyer data, no account or payment details. The output is event metadata and a price point."
                                              }
                       },
                       {
                           "@type": "Question",
                           "name": "Are any fields ever missing?",
                           "acceptedAnswer": {
                                                  "@type": "Answer",
                                                  "text": "No key is ever absent. Missing text is \"N/A\", a missing ticket count is 0, and a missing price is null, so row[\"venue\"] is always safe to read."
                                              }
                       },
                       {
                           "@type": "Question",
                           "name": "How is this billed?",
                           "acceptedAnswer": {
                                                  "@type": "Answer",
                                                  "text": "Pay-per-event: you are charged per event saved to the dataset, so a run that finds nothing costs nothing in event charges. Current rates are on the Actor's Apify page."
                                              }
                       },
                       {
                           "@type": "Question",
                           "name": "How do I estimate a run before starting it?",
                           "acceptedAnswer": {
                                                  "@type": "Answer",
                                                  "text": "cities x categories x maxPages x ~15-20 events is your ceiling. Three cities, two categories and maxPages: 5 is up to roughly 500 events."
                                              }
                       },
                       {
                           "@type": "Question",
                           "name": "What does the free plan give me?",
                           "acceptedAnswer": {
                                                  "@type": "Answer",
                                                  "text": "5 events per city + category combination - a smoke test to confirm your inputs work, rather than a data pull."
                                              }
                       },
                       {
                           "@type": "Question",
                           "name": "How do I guarantee an agent never overspends?",
                           "acceptedAnswer": {
                                                  "@type": "Answer",
                                                  "text": "Pass maxTotalChargeUsd as a query parameter on the run endpoint. It is a hard per-execution ceiling, and worth setting on every unattended or scheduled run."
                                              }
                       }
                   ]
}
```

# Actor input Schema

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

Select one or more cities to scrape events from.

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

Select which event categories to scrape.

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

Maximum pages to scrape per city + category combo. Each page has ~15–20 events. Maximum: 10.

## `onlyWithTickets` (type: `boolean`):

When enabled, skips events that have no tickets currently listed on Tixel.

## `mcpConnector` (type: `string`):

Optionally deliver scraped events into a connector you have authorized — Notion, Slack, Airtable, Google Sheets, or any MCP-compatible connector. Leave empty to only save results to the dataset.

## `deliveryMode` (type: `string`):

How to deliver to the connector: 'summary' (one call with an aggregate summary and the full event list), 'chunked' (split a large event list across multiple calls so services like Notion never time out), 'perEvent' (one call per scraped event), or 'none' (save to dataset only).

## `mcpTool` (type: `string`):

Name of the tool to call on the connector (e.g. 'create\_page' for Notion, 'send\_message' for Slack, 'append\_row' for Google Sheets/Airtable). If unsure, run once with a connector selected — the log lists the connector's available tools.

## `mcpArguments` (type: `object`):

Arguments passed to the connector tool. String values support {placeholders}. In 'summary' and 'chunked' modes: {totalEvents}, {cities}, {categories}, {eventList} (formatted list of events — in 'chunked' mode this holds one part), {part}/{partCount} (chunked mode only), and {message} (the rendered template below). In 'perEvent' mode: {name}, {venue}, {date}, {city}, {category}, {url}, {imageUrl}, {ticketsAvailable}, {hasTickets}, {priceFrom}, {currency}, {scrapedAt}, {sourcePage}, and {message}. Example for Slack: {"channel": "#tixel-events", "text": "{message}"}. Example for Notion (perEvent): {"parent": {"database\_id": "YOUR\_DB\_ID"}, "properties": {"Name": {"title": \[{"text": {"content": "{name}"}}]}}}.

## `mcpMessageTemplate` (type: `string`):

Optional template rendered and exposed as the {message} placeholder in the tool arguments. Summary example: 'Found {totalEvents} events across {cities} ({categories}):\n\n{eventList}'. Per-event example: '{name} at {venue}, {city} on {date} — from {currency} {priceFrom} ({ticketsAvailable} tickets) — {url}'.

## Actor input object example

```json
{
  "cities": [
    "Melbourne"
  ],
  "categories": [
    "all"
  ],
  "maxPages": 5,
  "onlyWithTickets": false,
  "deliveryMode": "summary",
  "mcpTool": "",
  "mcpArguments": {},
  "mcpMessageTemplate": ""
}
```

# Actor output Schema

## `results` (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": [
        "Melbourne"
    ],
    "categories": [
        "all"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("techforce.global/tixel-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": ["Melbourne"],
    "categories": ["all"],
}

# Run the Actor and wait for it to finish
run = client.actor("techforce.global/tixel-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": [
    "Melbourne"
  ],
  "categories": [
    "all"
  ]
}' |
apify call techforce.global/tixel-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,techforce.global/tixel-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/W3zaOISrz6drtU3Jr/builds/6DM5Ydd32Newa1fky/openapi.json
