Universal Event Scraper avatar

Universal Event Scraper

Pricing

Pay per event + usage

Go to Apify Store
Universal Event Scraper

Universal Event Scraper

The Universal Event Scraper is an Apify Actor that combines four specialized scrapers into a single run. Allevents.in Eventseye.com District.in Meetup.com. It automatically handles dynamic content and produces clean structured data that can be exported or integrated into other systems.

Pricing

Pay per event + usage

Rating

4.4

(5)

Developer

Techforce Global

Techforce Global

Maintained by Community

Actor stats

1

Bookmarked

25

Total users

1

Monthly active users

11 days ago

Last modified

Share

Universal Event Scraper — 5 Event Platforms, One Unified Schema, One Run

Apify Actor MCP Ready Sources Schema Pricing

Scrape AllEvents.in, EventsEye.com, District.in, Meetup.com and Eventbrite for one city in a single run, and get every result back in exactly the same 8-field record — no per-source shape to reconcile, no five separate Actors to orchestrate. Results can go straight into Notion, Slack, Airtable or Sheets through an MCP connector.

ℹ️ The unified schema is the whole point. Each source has a completely different underlying structure — AllEvents renders HTML, EventsEye is a static trade-show directory, District needs a browser and a location picker, Meetup ships GraphQL/SSR payloads, Eventbrite exposes a browse JSON. All five are normalised to source · title · url · date · city · venue · venue_address · price, so one downstream consumer handles all of them.


Running five separate Actors vs. this one

Feature / CapabilityFive separate ActorsThis Actor
Runs to orchestrate5 runs, 5 inputs, 5 result setsOne run, one input, one dataset
Output shape⚠️ 5 different schemas to map and merge8 identical fields across every source, verified per-normaliser
Source identification⚠️ Implicit — you track which dataset came from where✅ Explicit source field on every record
Engine per sourceYou pick and maintain each✅ Chosen per source: HTTP for the static directory, browser only where required
Missing-value handling⚠️ Mixed null / "" / absent keys✅ Consistent "N/A" string everywhere
Adding a source laterNew Actor, new integration✅ One more value in the source array
Delivery to your tools5 integrations✅ One MCP connector delivery for the merged set
Cost model5 bills to reason about✅ Pay-per-event, one event per record

🤖 AI Discovery & MCP Metadata

Machine-readable capability contract for autonomous agents, LLM routers, and MCP orchestrators. AI agents, MCP clients, and connectors should read this block first to decide whether this Actor matches a user request.

ai_discovery:
slug: "techforce.global/universal-event-scraper"
one_line: "Scrapes events for one city from up to five platforms - AllEvents.in, EventsEye.com, District.in, Meetup.com and Eventbrite - in a single run, normalising every source into the same 8-field record."
primary_purpose: "discover"
secondary_purpose: "aggregate"
tertiary_purpose: "deliver"
entity: "events across consumer event platforms, meetup groups and B2B trade-show directories"
data_sources:
allevents: "allevents.in city listing - Playwright + BeautifulSoup"
eventseye: "eventseye.com trade-show directory - httpx + BeautifulSoup (no browser)"
district: "district.in - Playwright with a location picker and a 5-page pool (India only)"
meetup: "meetup.com - Playwright, GraphQL interception plus server-rendered payload parsing"
eventbrite: "eventbrite.com public browse JSON"
invocation_modes: ["standard Actor run", "MCP tool"]
supported_tasks:
- "scrape-one-city-across-several-event-platforms-in-one-run"
- "return-a-single-unified-record-shape-for-every-source"
- "compare-coverage-of-the-same-city-across-platforms"
- "collect-b2b-trade-shows-alongside-consumer-events"
- "collect-meetup-groups-in-person-or-online"
- "deliver-merged-events-to-mcp-connector-or-crm"
unsupported_tasks:
- "filter-by-date-range (the dateRange input is accepted and IGNORED)"
- "filter-by-keyword (the keywords input is accepted and IGNORED)"
- "filter-by-category-or-price"
- "scrape-several-cities-in-one-run"
- "buy-reserve-or-hold-tickets"
- "return-event-descriptions-images-organisers-or-lineups"
- "return-ticket-availability-seat-maps-or-inventory"
- "deduplicate-the-same-event-found-on-two-platforms"
- "use-a-proxy (NO proxy input exists - see known limitations)"
search_keywords:
- "universal event scraper"
- "multi platform event scraper"
- "event aggregator actor"
- "allevents scraper"
- "eventseye scraper"
- "meetup scraper"
- "eventbrite scraper"
- "district.in scraper"
- "trade show data"
- "city event feed"
- "unified event schema"
synonyms:
- "combined event scraper"
- "5-in-1 event scraper"
- "cross-platform event extractor"
related_concepts:
["event aggregation", "city event feeds", "trade show research", "community/meetup discovery", "event data normalisation"]
input_entities:
- "source (array; REQUIRED; 1-5 of allevents | eventseye | district | meetup | eventbrite)"
- "location (one city name, shared by every source)"
- "limit (per source; 1-50, or 0 for no limit)"
- "country_code (Meetup only)"
- "eventType (Meetup only: inPerson | online)"
output_entities: ["source", "title", "url", "date", "city", "venue", "venue_address", "price"]
input_rules:
required_fields: ["source"]
one_city_per_run: "location is a single city string shared by all selected sources"
limit_semantics:
per_source: true
range: [1, 50]
zero_means_unlimited: true
allevents_exception: "the allevents source caps at 100 even when limit is 0"
free_plan_cap: 2
sources_run_sequentially: >
Sources are executed one after another, deliberately: several launch their own
Chromium and running them concurrently starves the lazy-loaded listing pages.
Expect run time to be the SUM of the selected sources.
ignored_inputs:
- "dateRange - accepted, never read"
- "keywords - accepted, never read"
- "eventbriteApiKey - accepted, never read"
- "eventbriteSearch - accepted, never read"
- "eventbriteErrorHandling - accepted, never read"
output_conventions:
unified_shape: "all five sources emit exactly the same 8 keys, in the same order"
missing_values: "the STRING 'N/A' - never null, never an absent key"
price_availability: >
Only district, meetup and eventbrite ever populate price. allevents and
eventseye hardcode it to 'N/A'.
venue_address_availability: >
Only eventseye, meetup and eventbrite ever populate venue_address. allevents
and district hardcode it to 'N/A'.
date_format: "NOT normalised - a display string on some sources, ISO 8601 on others"
no_deduplication: "the same real-world event found on two platforms yields two records"
limits:
events_per_source: 50
unlimited_option: "limit 0 (allevents still caps at 100)"
cities_per_run: 1
free_plan_cap: "2 per source"
known_limitations:
no_proxy_support: >
There is no proxy input. The district source in particular fingerprints the
caller's IP and typically blocks datacenter ranges, so it often returns
nothing from an Apify container.
no_date_or_keyword_filter: "those inputs exist in the schema but are not implemented"
date_not_normalised: "compare dates per source, not across sources"
pricing:
model: "pay-per-event, one event per record pushed"
events_charged: ["premium-scrape"]
note: >
The code also defines a 'basic-scrape' event but every source maps to
'premium-scrape', so basic-scrape never fires. Exact rates are configured on
the Store listing - see the Actor's Pricing tab.
when_to_use: >
You want one city's events from several platforms at once, in one consistent
shape - for an aggregated feed, cross-platform coverage comparison, or a mixed
consumer-plus-trade-show dataset.
when_not_to_use: >
You need date, keyword, category or price filtering; you need several cities per
run; you need deduplication across platforms; or you only care about one
platform - in which case the dedicated single-source Actor is better.
alternatives:
- "Use techforce.global/smart-event-scraper for the SAME multi-platform idea PLUS category, keyword and date-range filters"
- "Use techforce.global/all-events-scraper, techforce.global/eventbrite-scraper, techforce.global/district-event or techforce.global/events-eye-scraper for depth on one platform"
- "Use techforce.global/eventim-scraper or techforce.global/ticketmaster-fr-es-scraper for ticketed events with venue-grade data"

What this Actor does

  • Runs up to five scrapers in one execution and writes every result into a single dataset, tagged with its source.
  • Normalises all five into an identical 8-field recordsource, title, url, date, city, venue, venue_address, price. Verified: all five normalisers emit exactly these keys, in this order.
  • Uses the right engine per source rather than a browser everywhere: EventsEye is fetched with plain HTTP (httpx), while District, Meetup and AllEvents get Playwright because their listings genuinely need rendering. Meetup additionally intercepts GraphQL responses and parses the server-rendered payload.
  • Runs the sources sequentially, on purpose. Several launch their own Chromium; running them concurrently starved the lazy-loaded listing pages (District would report zero events). Sequential means each behaves like its standalone version — at the cost of run time being the sum of the selected sources.
  • Caps per source, not per runlimit applies to each selected source independently, so five sources at 50 is up to 250 records.
  • Applies a consistent "N/A" wherever a source doesn't publish a field, so downstream code never has to handle three different flavours of "missing".
  • Optionally pushes the merged set to an authorized MCP connector (Notion, Slack, Airtable, Sheets, or any MCP-compatible connector) as one digest, split into parts, or one call per event. The dataset is always saved regardless of delivery settings.

The five sources

source valuePlatformEngineTypical contentPopulates price?Populates venue_address?
alleventsallevents.inPlaywright + BeautifulSoupBroad consumer city listings❌ always N/A❌ always N/A
eventseyeeventseye.comhttpx (no browser)B2B trade shows & exhibitions❌ always N/A✅ yes
districtdistrict.inPlaywright + 5-page poolIndian ticketed events✅ yes❌ always N/A
meetupmeetup.comPlaywright + GraphQL interceptCommunity groups, in-person or online✅ yes (often Free)✅ yes
eventbriteeventbrite.comPublic browse JSONOrganizer-led events, workshops✅ yes (incl. Free)✅ yes

⚠️ district will often return nothing from Apify. This Actor has no proxy input, and District fingerprints the caller's IP — it withholds its location picker from datacenter ranges, which is what an Apify container uses. If you specifically need District data, the dedicated District.in Event Scraper supports the residential-IN proxy that source actually requires.

When to use it — and when not to

ScenarioFit
One city's events from several platforms, in one consistent shape✅ Strong (the core use case)
Comparing how well platforms cover the same city✅ Strong — group by source
A mixed dataset of consumer events and B2B trade shows✅ Strong — allevents + eventseye
Community/meetup discovery alongside ticketed events✅ Strong — meetup + eventbrite
Feeding a merged feed into Notion / Airtable / Slack✅ Strong (deliveryMode)
Trade shows only, no browser cost✅ Strong — ["eventseye"] alone is HTTP-only
Filtering by date range or keyword❌ Those inputs exist but are not implemented — ➡️ Smart Event Scraper
Filtering by category or price❌ No such input — ➡️ Smart Event Scraper
Several cities in one run❌ One location per run — loop from your side
Deduplicating an event that appears on two platforms❌ Not done — you get two records
Only one platform matters to you⚠️ A dedicated single-source Actor gives more fields and options
District.in data specifically⚠️ No proxy support here — use District.in Event Scraper
Comparing date values across sources⚠️ date is not normalised — formats differ per source
Event descriptions, images, organisers, lineups❌ Eight fields only
Ticket availability, seat maps, inventory❌ Not returned
Buying or reserving tickets❌ Read-only

⚡ Execution Rules (Avoid Common Agent Failures)

  1. source is required and is an array. Pass one to five of allevents, eventseye, district, meetup, eventbrite. An unrecognised value is skipped with a warning, not an error — so a typo yields a quietly empty run.
  2. limit is per source, not per run. Five sources at 50 is up to 250 records, and 250 billable events.
  3. limit: 0 means no limit — it bypasses the schema's maximum of 50 entirely. Use a spend cap with it. Note the exception: the allevents source caps at 100 even when limit is 0.
  4. Free Apify plans are capped at 2 records per source — so a 5-source run returns up to 10 items. That's a successful run.
  5. dateRange and keywords are accepted and silently ignored. No source filters by either. If you need that filtering, use Smart Event Scraper; otherwise filter the dataset afterwards.
  6. Three more inputs are inert: eventbriteApiKey, eventbriteSearch and eventbriteErrorHandling. Selecting eventbrite in source is what enables that scraper.
  7. Sources run sequentially, so run time is the sum of them. Five sources with browsers is a multi-minute run — use the async endpoint, not the 300s synchronous one.
  8. Every missing value is the string "N/A", never null. if (event.price) is always truthy; test === "N/A" explicitly.
  9. date is not normalised across sources. Meetup can give ISO 8601 with a timezone; AllEvents and District give display strings. Parse per source, don't sort the merged set by raw date and trust it.
  10. price is only ever populated by district, meetup and eventbrite. allevents and eventseye hardcode "N/A" — that is not a scraping failure.
  11. venue_address is only ever populated by eventseye, meetup and eventbrite. allevents and district hardcode "N/A".
  12. No deduplication. The same real-world event on two platforms produces two records with different urls. Dedupe on title + date yourself if you need to.
  13. district usually returns nothing here — no proxy support, and District blocks datacenter IPs. Don't read an empty district set as a bug in your input.
  14. country_code and eventType affect Meetup only, and country_code must match your location's country or Meetup returns nothing (location: "Dubai" needs country_code: "ae", not the default "in").
  15. One city per run. location is a single string shared by every source.
  16. deliveryMode defaults to summary, not none — one connector call per run. perEvent on a 250-event run makes 250 calls.
dependencies:
- rule: "source is required and must contain a known value"
on_violation: "unknown values are skipped with a warning; an all-typo input yields an empty successful run"
- rule: "limit is per source and 0 disables the cap"
on_violation: "volume and cost under-estimated by a factor of the source count"
- rule: "allevents caps at 100 even when limit is 0"
note: "the only source that ignores unlimited"
- rule: "dateRange, keywords, eventbriteApiKey, eventbriteSearch and eventbriteErrorHandling are accepted but never read"
on_violation: "agents believe they applied a filter that was silently dropped"
- rule: "sources run sequentially"
on_violation: "run-time estimates that assume parallelism; sync-endpoint timeouts"
- rule: "absent values are the string 'N/A', never null"
on_violation: "null checks pass while values are unusable"
- rule: "date is not normalised across sources"
on_violation: "sorting or filtering the merged set by raw date silently misorders it"
- rule: "price and venue_address are hardcoded 'N/A' on some sources"
on_violation: "a source-level omission mistaken for a scrape failure"
- rule: "no cross-platform deduplication"
on_violation: "duplicate events double-counted, and double-billed"
- rule: "no proxy input exists; district blocks datacenter IPs"
on_violation: "an empty district result read as a configuration error"
- rule: "country_code must match the location's country (Meetup)"
on_violation: "Meetup returns nothing for a valid city"
- rule: "delivery requires mcpConnector AND mcpTool"
on_violation: "delivery step is skipped with a warning; the dataset is still written in full"
- rule: "mcpArguments must reference {message} for the rendered template to appear anywhere"
on_violation: "message body is empty; the tool is still called"
- rule: "mcpConnector only resolves when the Actor runs on the Apify platform"
on_violation: "local runs log 'APIFY_MCP_PROXY_URL is not set' and skip delivery; the dataset is unaffected"
authentication:
actor_input: none
platform: "Apify API token required for API / SDK / MCP invocation"
target_sites: "no account, login or cookie required for any of the five sources"

📥 Input Contract

.actor/input_schema.json is authoritative — if any table on this page disagrees with the schema files, the schema files win.

Parameters

FieldTypeRequiredDefaultAllowed Values / FormatExample
sourcearrayYes["eventseye"]1–5 of allevents, eventseye, district, meetup, eventbrite["allevents","meetup"]
locationstring⬜ No"Dubai"One city name, shared by all sources"mumbai"
limitinteger⬜ No50150 per source, or 0 for no limit25
country_codestring⬜ No"in"ISO 3166-1 alpha-2 — Meetup only"ae"
eventTypeenum⬜ No"inPerson"inPerson, onlineMeetup only"online"

⚠️ Inputs that exist but do nothing

These are present in the schema and accepted by the API, but no code reads them. They are documented here so an agent doesn't believe a filter was applied.

FieldWhat you might expectWhat actually happens
dateRangeDate-range filteringIgnored. Filter the dataset's date field afterwards, or use Smart Event Scraper
keywordsKeyword filteringIgnored. Filter the dataset's title field afterwards
eventbriteApiKeyAuthenticated Eventbrite accessIgnored. The Eventbrite source reads the public browse JSON and does not authenticate
eventbriteSearchEnable/disable the Eventbrite sourceIgnored. Selecting eventbrite in source is what enables it
eventbriteErrorHandlingToggle error handlingIgnored. Eventbrite errors are always caught and logged

Examples

Broadest sweep — everything for one city

{
"source": ["allevents", "eventseye", "meetup", "eventbrite"],
"location": "mumbai",
"limit": 50,
"country_code": "in",
"deliveryMode": "none"
}

Trade shows only — HTTP-only, cheapest and fastest

{
"source": ["eventseye"],
"location": "berlin",
"limit": 50,
"deliveryMode": "none"
}

Meetup in a non-Indian city — country_code must match

{
"source": ["meetup"],
"location": "Dubai",
"country_code": "ae",
"eventType": "inPerson",
"limit": 50,
"deliveryMode": "none"
}

Online communities only

{
"source": ["meetup"],
"location": "london",
"country_code": "gb",
"eventType": "online",
"limit": 50,
"deliveryMode": "none"
}

Cheap validation run before committing

{
"source": ["allevents", "eventbrite"],
"location": "ahmedabad",
"limit": 2,
"deliveryMode": "none"
}

Consumer + B2B side by side

{
"source": ["allevents", "eventseye"],
"location": "dubai",
"limit": 50,
"deliveryMode": "none"
}

MCP Delivery Configuration (Optional)

Delivery pushes event data into your own tools. It never buys, reserves or contacts anything.

ParameterTypeDefaultDescription
mcpConnectorstring""Authorized MCP connector on your Apify account (Notion, Slack, Airtable, Sheets, …). Leave empty for dataset-only runs.
deliveryModeenumsummarysummary (one call with every event) · chunked (split across calls) · perEvent (one call per event) · none.
mcpToolstring""Tool name on the connector: create_page, send_message, append_row, create_record. Run once with a connector selected — the log lists the available tools.
mcpArgumentsobject{}Arguments passed to the tool. String leaves support {placeholders}.
mcpMessageTemplatestring""Template rendered and exposed to mcpArguments as {message}.

Summary & chunked placeholders: {location}, {sources} (comma-separated list of the sources that actually returned data), {eventCount}, {events}, {message} — plus {part} and {partCount} in chunked mode.

Per-event placeholders: every output field — {source}, {title}, {url}, {date}, {city}, {venue}, {venue_address}, {price} — plus {message}.

A Slack digest of the merged run:

{
"source": ["allevents", "meetup", "eventbrite"],
"location": "mumbai",
"limit": 50,
"mcpConnector": "<your-authorized-slack-connector>",
"deliveryMode": "summary",
"mcpTool": "send_message",
"mcpArguments": { "channel": "#events", "text": "{message}" },
"mcpMessageTemplate": "📅 {eventCount} events in {location} from {sources}:\n\n{events}"
}

A large merged set split across Notion sub-pages:

{
"source": ["allevents", "eventseye", "meetup", "eventbrite"],
"location": "berlin",
"limit": 50,
"mcpConnector": "<your-authorized-notion-connector>",
"deliveryMode": "chunked",
"mcpTool": "notion-create-pages",
"mcpArguments": {
"parent": { "page_id": "<your-page-id>" },
"pages": [
{
"properties": { "title": "Events in {location} — part {part}/{partCount}" },
"content": "{events}"
}
]
}
}

One Airtable row per event, keeping the source tag:

{
"source": ["eventseye"],
"location": "dubai",
"limit": 50,
"mcpConnector": "<your-authorized-airtable-connector>",
"deliveryMode": "perEvent",
"mcpTool": "create_record",
"mcpArguments": {
"fields": {
"Platform": "{source}",
"Event": "{title}",
"Date": "{date}",
"City": "{city}",
"Venue": "{venue}",
"Address": "{venue_address}",
"Price": "{price}",
"Link": "{url}"
}
}
}

📤 Output Contract & Data Structure

Storage: Apify Dataset — one JSON object per event, pushed as each source scrapes. Pagination: limit & offset on the dataset items endpoint. Duplicates: not deduplicated across sources. The same event on two platforms is two records. Dedupe on url, or on title + date for cross-platform matching.

The unified record — 8 fields, identical for every source

FieldTypeEmpty valueMeaningPopulated by
sourcestringnever emptyWhich platform produced this record: allevents, eventseye, district, meetup, eventbriteall
titlestring"N/A"Event or exhibition nameall
urlstring"N/A"Link to the event on its platform — the dedupe keyall
datestring"N/A"Start date/time — format differs per source, not normalisedall
citystring"N/A"City (echoed from your location on most sources)all
venuestring"N/A"Venue or location nameall
venue_addressstring"N/A"Street address⚠️ eventseye, meetup, eventbrite only
pricestring"N/A"Price as a display string, or Free⚠️ district, meetup, eventbrite only

⚠️ "N/A" is a string, not null, and it has two different meanings. On price and venue_address it may mean this source never provides that field (see the column above) rather than this event didn't publish one. Check source before concluding anything about a gap.

There is no description, image, category, organiser, lineup, availability or ID field. Eight fields is the whole contract.

Example — eventseye (trade show, has an address, never a price)

{
"source": "eventseye",
"title": "GULFOOD",
"url": "https://www.eventseye.com/fairs/f-gulfood-1234.html",
"date": "Feb 2027",
"city": "Dubai",
"venue": "Dubai World Trade Centre",
"venue_address": "Sheikh Zayed Road, Dubai, United Arab Emirates",
"price": "N/A"
}

Example — meetup (ISO date, price often Free)

{
"source": "meetup",
"title": "Mumbai Python User Group — Monthly Meetup",
"url": "https://www.meetup.com/mumbai-python/events/301234567/",
"date": "2026-09-18T18:30:00+00:00",
"city": "mumbai",
"venue": "WeWork Enam Sambhav",
"venue_address": "C-20, G Block, Bandra Kurla Complex, Mumbai, MH",
"price": "Free"
}

Example — allevents (display date, no price, no address by design)

{
"source": "allevents",
"title": "Sunburn Arena ft. Martin Garrix",
"url": "https://allevents.in/mumbai/sunburn-arena/1234567890",
"date": "Sat, 12 Sep, 7:00 pm",
"city": "Mumbai",
"venue": "NSCI Dome, Worli",
"venue_address": "N/A",
"price": "N/A"
}

Working with a merged set

from collections import Counter
# Always branch on `source` - "N/A" can mean "this source never provides it".
print(Counter(e["source"] for e in items)) # coverage per platform
priced = [e for e in items if e["price"] != "N/A"] # district / meetup / eventbrite only
addressed = [e for e in items if e["venue_address"] != "N/A"]
# `date` is NOT normalised - only parse within a source you know the format of.
meetup_dated = [e for e in items if e["source"] == "meetup" and e["date"] != "N/A"]
# No cross-platform dedup is done for you.
seen, unique = set(), []
for e in items:
key = (e["title"].strip().lower(), e["date"])
if key not in seen:
seen.add(key)
unique.append(e)
print(f"{len(items)} records → {len(unique)} after cross-platform dedupe")

What a successful run looks like

{
"status": "SUCCEEDED",
"defaultDatasetId": "<datasetId>",
"stats": { "itemCount": 137 }
}

itemCount below limit × len(source) is normal — some sources return less, and district frequently returns nothing at all without a proxy. itemCount: 0 is a valid empty result. Read the per-source log lines to tell the causes apart:

Log lineMeaning
Running scraper: '<source>'That source started — one line per selected source
Unknown source: '<value>' — skipping.A typo or unsupported value; nothing ran for it
[allevents] Input 'location' is missing!location was empty
[allevents] Failed to load pageThe listing page didn't load
[<source>] ✔ Scraped N eventsThat source's own count
Free plan detected — capping results to 2 per source.Free-plan cap applied
Charge failed for '<event>'Billing event failed; the record was still pushed

▶️ Invocation & Integration

Lifecycle: Discover → Understand → Configure → Execute → Retrieve → Validate. Authenticate every call with Authorization: Bearer <APIFY_TOKEN>.

Apify Console

Open the Actor → Input tab → select one or more Sources → type a Location → set Max Events (per source)(for Meetup) set Country code to match the city → (optional) pick an MCP connector, tool and template → Start → export from the Dataset tab (JSON, CSV, Excel, XML).

Model Context Protocol (MCP)

claude mcp add --transport http apify \
"https://mcp.apify.com?tools=techforce.global/universal-event-scraper"

Python (apify-client)

import os
from collections import Counter
from apify_client import ApifyClient
client = ApifyClient(os.getenv("APIFY_TOKEN"))
ACTOR = "techforce.global/universal-event-scraper"
run = client.actor(ACTOR).call(run_input={
"source": ["allevents", "eventseye", "meetup", "eventbrite"],
"location": "mumbai",
"limit": 50, # PER SOURCE → up to 200 records here
"country_code": "in", # Meetup only; must match the city's country
"deliveryMode": "none",
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
print(f"{len(items)} records")
print(Counter(e["source"] for e in items)) # which platforms actually delivered
# "N/A" is a STRING sentinel, and on price/venue_address it may simply mean
# "this source never provides that field".
for event in items[:10]:
price = event["price"] if event["price"] != "N/A" else "—"
print(f'[{event["source"]:<10}] {event["title"][:45]}')
print(f'{"":<13} {event["date"]} · {event["venue"]} · {price}')

Multi-city sweep — one run per city, since location is a single string:

CITIES = ["mumbai", "delhi", "bengaluru"]
all_events = []
for city in CITIES:
run = client.actor(ACTOR).call(run_input={
"source": ["allevents", "eventbrite"],
"location": city,
"limit": 50,
"deliveryMode": "none",
})
all_events += client.dataset(run["defaultDatasetId"]).list_items().items
print(f"{len(all_events)} events across {len(CITIES)} cities")

JavaScript / TypeScript (apify-client)

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const ACTOR = 'techforce.global/universal-event-scraper';
const run = await client.actor(ACTOR).call({
source: ['eventseye', 'eventbrite'],
location: 'berlin',
limit: 50,
deliveryMode: 'none',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
// Group by platform - the `source` tag is what makes a merged set usable.
const bySource = items.reduce<Record<string, number>>((acc, e) => {
acc[e.source] = (acc[e.source] ?? 0) + 1;
return acc;
}, {});
console.log(bySource);
// price is only ever real on district / meetup / eventbrite
const priced = items.filter((e) => e.price !== 'N/A');
console.log(`${priced.length} of ${items.length} records carry a price`);

Sources run sequentially, so a multi-source run takes minutes. Prefer async over the 300s synchronous endpoint.

# 1. Start execution with a hard spend limit
curl -X POST -H 'Content-Type: application/json' \
-H 'Authorization: Bearer <YOUR_APIFY_TOKEN>' \
-d '{"source":["allevents","eventseye","meetup","eventbrite"],"location":"mumbai","limit":50,"deliveryMode":"none"}' \
'https://api.apify.com/v2/acts/techforce.global~universal-event-scraper/runs?maxTotalChargeUsd=2.00'
# 2. Poll
curl -H 'Authorization: Bearer <YOUR_APIFY_TOKEN>' \
'https://api.apify.com/v2/actor-runs/<runId>'
# 3. Retrieve when SUCCEEDED
curl -H 'Authorization: Bearer <YOUR_APIFY_TOKEN>' \
'https://api.apify.com/v2/datasets/<DATASET_ID>/items?clean=true&format=json'

cURL — synchronous (single source, small limit only)

curl -X POST \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <YOUR_APIFY_TOKEN>' \
-d '{"source":["eventseye"],"location":"dubai","limit":20,"deliveryMode":"none"}' \
'https://api.apify.com/v2/acts/techforce.global~universal-event-scraper/run-sync-get-dataset-items'

⚠️ Autonomous Agent Error Handling & Resolution Matrix

Error CodeDetection ConditionUnderlying CauseDeterministic Agent Action
AUTH_INVALIDHTTP 401 from ApifyMissing or malformed APIFY_TOKENAbort & Prompt User: request a valid Apify API token.
RATE_LIMITEDHTTP 429 from ApifyApify API rate / concurrency limitsRetry: exponential backoff (2s, 4s, 8s).
SYNC_TIMEOUTHTTP 408 on the sync endpointSources run sequentially; multi-source runs exceed 300sReconfigure: async POST /runs + polling.
MISSING_SOURCEInput validation rejectionsource is requiredModify Input: supply an array with at least one known value.
UNKNOWN_SOURCESUCCEEDED, 0 items, log Unknown source: '<x>' — skipping.Typo or unsupported platform nameModify Input: use allevents, eventseye, district, meetup, eventbrite.
MISSING_LOCATIONLog [allevents] Input 'location' is missing!location emptyModify Input: supply a city.
VOLUME_UNDERESTIMATEDFar more records than expectedlimit is per sourceFix Expectation: total ≈ limit × source count.
UNLIMITED_RUNAWAYVery large run, high spendlimit: 0 removes the cap entirelyReconfigure: set a real limit and maxTotalChargeUsd.
ALLEVENTS_CAPPED_100allevents stops at 100 with limit: 0That source caps at 100 regardlessFix Expectation: documented behaviour.
FREE_PLAN_CAP2 records per source, upgrade banner in the logFree Apify plan capPrompt User: upgrade for full-volume runs.
DATE_FILTER_IGNOREDdateRange set, results outside itNot implemented — the input is read by nothingRe-route: Smart Event Scraper, or filter the dataset.
KEYWORD_FILTER_IGNOREDkeywords set, unrelated resultsNot implementedRe-route or filter the dataset.
EVENTBRITE_TOGGLE_IGNOREDeventbriteSearch: false yet Eventbrite ranThe toggle is inert; source controls itModify Input: remove eventbrite from source.
DISTRICT_EMPTYdistrict selected, zero district recordsNo proxy support; District blocks datacenter IPsRe-route: District.in Event Scraper with a residential-IN proxy.
MEETUP_EMPTYmeetup selected, zero meetup recordscountry_code doesn't match the location's countryModify Input: set country_code correctly (e.g. ae for Dubai).
SOURCE_EMPTYOne source returns nothing, others workThat platform has no coverage for the city, or its layout changedAccept, or drop that source. Check its [<source>] log lines.
NA_NOT_NULLNull checks pass but values unusableMissing values are the string "N/A"Fix Code: compare against "N/A".
FIELD_NEVER_POPULATEDprice or venue_address always "N/A"That source never provides it — not a failureFix Expectation: check the source-capability table.
DATE_FORMAT_MIXEDDate parsing fails on some recordsdate is not normalised across sourcesFix Code: branch on source before parsing.
DUPLICATE_ACROSS_SOURCESThe same event twiceNo cross-platform dedup is performedFix Code: dedupe on title + date.
MULTI_CITY_UNSUPPORTEDAgent passes a city arraylocation is a single stringLoop: one run per city.
NO_EVENT_DETAILNo description, image, organiser or lineupEight fields onlyFix Expectation: open url.
CHARGE_FAILEDLog Charge failed for '<event>'The billing event call failedNot data loss — the record was still pushed. Report to support if persistent.
DELIVERY_SKIPPEDLog no tool name was providedmcpConnector set but mcpTool emptyModify Input: set mcpTool; the dataset is already saved.
DELIVERY_TOOL_UNKNOWNLog Tool 'x' is not available on this connectorWrong tool name for that connectorModify Input: pick a name from the Available tools: list in the same log line.
DELIVERY_EMPTYConnector called, body emptymcpArguments omitted the {message} placeholderModify Input: map {message} inside mcpArguments.
DELIVERY_FLOODHundreds of connector callsdeliveryMode: "perEvent"Reconfigure: use summary or chunked.
MCP_PROXY_MISSINGLog APIFY_MCP_PROXY_URL is not setRunning locally instead of on the platformReconfigure: apify push and run on the platform.
CHARGE_LIMITRun aborted before all sources finishedmaxTotalChargeUsd spend threshold reachedPrompt User: confirm a higher spend cap.

⚠️ Verify before publishing: the Apify HTTP status rows (401, 408, 429) reflect standard platform behavior. Every source-side row, quoted log line and field condition is taken from this Actor's source. Re-confirm the platform rows if you depend on them for automated retry logic.


🗣️ Natural Language → Actor Mapping

User saysIntentConstructed Actor input
"Get me all the events in Mumbai from every platform"Multi-source sweep{"source":["allevents","eventseye","meetup","eventbrite"],"location":"mumbai","limit":50}
"What trade shows are happening in Dubai?"B2B only{"source":["eventseye"],"location":"dubai","limit":50}
"Find tech meetups in Bengaluru"Community{"source":["meetup"],"location":"bengaluru","country_code":"in"} then filter title
"Online meetups I can join from anywhere"Online only{"source":["meetup"],"location":"london","country_code":"gb","eventType":"online"}
"Workshops and classes in Berlin"Organizer-led{"source":["eventbrite"],"location":"berlin","limit":50}
"Compare how many events each platform lists for Delhi"Coverage analysisrun all sources, then group by source
"Consumer events and business expos side by side"Mixed dataset{"source":["allevents","eventseye"],"location":"<city>"}
"Which of these events are free?"Price filterrun, then filter price == "Free" (only 3 sources populate price)
"Build an event feed for three cities"Multi-cityLoop one run per city — location is a single string
"Push the merged feed into Notion"Delivery{"mcpConnector":"notion","deliveryMode":"chunked","mcpTool":"notion-create-pages"}
"Post a daily summary to Slack"Digest deliveryschedule + {"deliveryMode":"summary","mcpTool":"send_message"}
"Only events next weekend"Date filter⚠️ dateRange is ignored — ➡️ Smart Event Scraper, or filter date afterwards
"Only events matching 'AI'"Keyword filter⚠️ keywords is ignored — filter title afterwards
"Why did District return nothing?"Diagnosis⚠️ No proxy support here — ➡️ District.in Event Scraper
"Remove the duplicates across platforms"Dedup⚠️ Not done for you — dedupe on title + date
"Get me the event description and image"Detail❌ Eight fields only — open url
"How many tickets are left?"Inventory❌ Not returned
"Book two tickets"Transaction❌ Read-only

Should NOT route here: date-range, keyword, category or price filtering at the source · several cities in one run · cross-platform deduplication · District.in data specifically (no proxy support) · event descriptions, images, organisers or lineups · ticket availability, seat maps or inventory · buying or reserving tickets · depth on a single platform where the dedicated Actor offers more fields.


🧭 Agent Execution & Routing Logic

[Input User Query]
1. Does the user need FILTERING at the source (date, keyword, category, price)?
│ YES → Route to Smart Event Scraper. This Actor's dateRange/keywords inputs
│ are ACCEPTED AND IGNORED — promising them here is wrong
│ NO
2. Do they care about only ONE platform?
│ YES → prefer the dedicated Actor (more fields, more options):
│ allevents.in → All Events Scraper
│ eventbrite → Eventbrite Scraper
│ district.in → District.in Event Scraper (has the proxy it needs)
│ eventseye → Events Eye Scraper
│ NO (they want several platforms in one shape) → continue
3. Pick the sources. Note per-source capability:
├── price → district | meetup | eventbrite ONLY
├── venue_address → eventseye | meetup | eventbrite ONLY
├── trade shows → eventseye (and it is HTTP-only, so cheapest)
└── district → will likely return NOTHING here (no proxy support)
4. One city per run. Several cities → loop.
5. Set limit PER SOURCE (1-50; 0 = unlimited, allevents still caps at 100)
│ ⚠️ total ≈ limit × source count, and that is the billable count
6. Using meetup? country_code MUST match the location's country
(Dubai → "ae", London → "gb", Mumbai → "in")
7. Deliver to a connector? YES → mcpConnector + mcpTool + {message}
│ summary (1 call) / chunked / perEvent (1 per event!)
│ NO → set deliveryMode "none" (it defaults to summary)
8. Sources run SEQUENTIALLY → run time is the SUM. Use the ASYNC endpoint
[Execute]
├──► SUCCEEDED, items > 0 ──► handle the merged contract:
│ ALWAYS branch on `source` first
│ "N/A" is a STRING, and on price/venue_address may mean
│ "this source never provides it" — not a scrape failure
│ `date` is NOT normalised → parse per source, never sort the merged set raw
│ NO cross-platform dedup → dedupe on title + date yourself
└──► SUCCEEDED, items == 0 ──► READ THE PER-SOURCE LOG LINES:
"Unknown source: '<x>' — skipping." → fix the source value
"[allevents] Input 'location' missing" → supply a city
district selected but empty → expected: no proxy support
meetup empty → country_code mismatch

💰 Cost Control & Pricing Transparency

Pay-per-event: one charge per record pushed to the dataset, with no monthly subscription. The exact rate is on the Actor's Pricing tab in the Apify Store.

Free Apify plans are capped at 2 records per source, so a five-source run returns up to 10 items — enough to validate a configuration before committing.

Autonomous spend caps: pass maxTotalChargeUsd as a query parameter on the run endpoint for a hard per-execution ceiling.

⚠️ Verify before publishing: the code charges an event named premium-scrape for every source. It also defines a basic-scrape event, but no source maps to it, so basic-scrape can never fire. There is no .actor/pay_per_event.json in the repo, so both events are configured only on the Store listing — confirm the live event configuration (and whether basic-scrape should exist at all) before publishing.

The multiplier to watch: limit is per source

Sources selectedlimitMaximum records (= billable events)
1 (eventseye)5050
250100
450200
550250
Any0 (unlimited)Unboundedallevents still caps at 100, the rest do not
Any2 (free plan)2 × source count

Platform usage is billed on top, and it varies sharply by source:

SourceEngineRelative platform cost
eventseyehttpx, no browser💚 Lowest — plain HTTP
eventbritePublic browse JSON💚 Low
alleventsPlaywright🟠 Browser cost
meetupPlaywright + GraphQL intercept🟠 Browser cost
districtPlaywright + 5-page pool🔴 Highest — and usually returns nothing here

Cost levers:

  • Drop district unless you have a specific reason. It's the most expensive source and, without proxy support, typically yields nothing.
  • Start with ["eventseye"] or ["eventbrite"] if cost matters — both avoid a browser entirely.
  • Trim the source list. Every extra source multiplies both the record count and the run time.
  • Never use limit: 0 without maxTotalChargeUsd. It removes the cap completely.
  • Validate at limit: 2 before a full sweep.
  • Dedupe before charging your own downstream systems — the same event on two platforms is billed twice here.
  • Prefer summary/chunked delivery over perEvent — 1 connector call instead of hundreds.

🔍 Companion machine-readable files

FilePurpose
.actor/actor.jsonIdentity, title, description, version, build tag, and the input / output / dataset schema references
.actor/input_schema.jsonAuthoritative typed input contract — the 5-value source enum, location, limit, the Meetup-only country_code/eventType, the 5 delivery fields, and the 5 inputs explicitly marked as not implemented
.actor/dataset_schema.jsonFull JSON Schema for the record (a oneOf branch per source, so each platform's variant is described individually) plus the Console Output view
.actor/output_schema.jsonDeclares where results are stored
my_actor/main.pyAll five scrapers, the five normalisers, the per-source free-plan cap, charging, and MCP delivery
my_actor/connector.pyMCP connector session handling through the Apify MCP Proxy

Note: this Actor has no pay_per_event.json — the premium-scrape (and unused basic-scrape) events are configured on the Store listing.

If any table on this page disagrees with the schema files, the schema files win.


🛠️ Troubleshooting

#Symptom you seeMost likely causeFix
10 items, log Unknown source: '<x>' — skipping.Typo in a source valueUse allevents, eventseye, district, meetup, eventbrite.
2Log [allevents] Input 'location' is missing!location emptySupply a city name.
3Far more records than expectedlimit is per sourceTotal ≈ limit × source count. Trim sources.
4Exactly 2 per sourceFree Apify plan capUpgrade; the log prints the upgrade banner.
5allevents stopped at 100 with limit: 0That source caps at 100 regardlessDocumented behaviour.
6dateRange had no effectNot implementedFilter the dataset's date, or use Smart Event Scraper.
7keywords had no effectNot implementedFilter the dataset's title.
8Eventbrite ran despite eventbriteSearch: falseThat toggle is inertRemove eventbrite from source.
9district returned nothingNo proxy support; District blocks datacenter IPsUse District.in Event Scraper with a residential-IN proxy.
10meetup returned nothingcountry_code doesn't match the city's countrySet it correctly — ae for Dubai, gb for London.
11One source empty, others fineNo coverage for that city, or a layout changeCheck that source's [<source>] log lines.
12price always "N/A"Only district, meetup, eventbrite populate itExpected for allevents/eventseye.
13venue_address always "N/A"Only eventseye, meetup, eventbrite populate itExpected for allevents/district.
14Null checks never fireMissing values are the string "N/A"Compare against "N/A".
15Date parsing fails on some rowsdate is not normalised across sourcesBranch on source before parsing.
16Sorting the merged set by date misorders itMixed formats — display strings vs ISO 8601Normalise per source first.
17The same event appears twiceNo cross-platform dedupDedupe on title + date.
18Run takes several minutesSources run sequentially, several with browsersExpected; use the async endpoint.
19HTTP 408 on run-sync-get-dataset-itemsThe synchronous endpoint has a hard 300-second ceilingUse async POST /runs → poll → fetch.
20Log Charge failed for '<event>'The billing call failedThe record was still saved — no data loss.
21Only one city came backlocation is a single stringLoop one run per city.
22Hundreds of connector callsdeliveryMode: "perEvent"Switch to summary or chunked.
23Notion / Airtable timed outOne call carrying every event is too largeUse deliveryMode: "chunked".
24Slack / Notion received nothingDelivery needs both mcpConnector and mcpToolSet both. The dataset is still written in full.
25Connector fired but the body is emptymcpArguments did not reference {message}Map {message} and populate mcpMessageTemplate.
26Log APIFY_MCP_PROXY_URL is not setYou ran locally; connectors only resolve on the platformDeploy with apify push and run on the platform.
27HTTP 401 / 403 from ApifyMissing, expired or malformed APIFY_TOKENRegenerate in Apify Console → Settings → API & Integrations.
28HTTP 429 from ApifyApify account concurrency / rate limitsRetry with exponential backoff (2s → 4s → 8s).

Known limitations

  • No proxy support. There is no proxy input at all. This mainly hurts the district source, which needs a residential Indian IP to work.
  • dateRange and keywords are not implemented, along with eventbriteApiKey, eventbriteSearch and eventbriteErrorHandling. All five are accepted and ignored.
  • date is not normalised across sources — a display string on some, ISO 8601 on others.
  • No cross-platform deduplication, so the same event on two platforms is two records.
  • Eight fields only — no description, image, category, organiser, lineup, availability or ID.
  • One city per run, and sources run sequentially, so wall-clock time is the sum of the selected sources.

Diagnostic checklist before opening an issue

  1. Single-source baseline. {"source":["eventseye"],"location":"dubai","limit":5,"deliveryMode":"none"} — HTTP-only, no browser, fastest to prove the pipeline works.
  2. Items returned? If yes, the pipeline is fine — the problem is specific to another source or city.
  3. Read the per-source log lines. Each source logs Running scraper: '<x>' and its own [<source>] messages; that tells you which one produced nothing.
  4. Rule out the known-empty cases first. district without a proxy, and meetup with a mismatched country_code, are the two most common "it returned nothing" reports.
  5. Confirm the counting model. Unexpected volume is almost always limit being per-source rather than per-run.

If the issue survives all five steps, open an Issues ticket on the Actor page (or email support) with the run ID, the exact input JSON, and which source fell short.

❓ FAQ

Scope & sources

What does "universal" actually mean here?

Five platforms in one run, normalised to one record shape. It isn't a generic any-website event scraper — the five sources are fixed and each has purpose-built extraction.

Do I need accounts or API keys for the sources?

No. All five read publicly available listings. (The eventbriteApiKey field in the schema is a leftover and is not used.)

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/universal-event-scraper"

Which source should I pick if I only want one?

Then use the dedicated Actor instead — All Events, Eventbrite, District.in or Events Eye. Each returns more fields and more options than the unified 8-field record.

Why does the district source return nothing?

District fingerprints the caller's IP and hides its location picker from datacenter ranges. This Actor has no proxy input, so it can't get past that. Use the District.in Event Scraper, which supports the residential-IN proxy that source requires.

Why did Meetup return nothing for a real city?

country_code has to match the city's country — it defaults to in. Dubai needs ae, London needs gb.

Filtering

Can I filter by date or keyword?

Not here. Both inputs exist in the schema but no code reads them — they're documented as not implemented. Use Smart Event Scraper, which does filter by category, keyword and date range across six platforms, or filter this Actor's dataset afterwards.

Can I scrape several cities in one run?

No — location is a single string. Loop one run per city.

Output

Is the output really identical across sources?

Yes — all five normalisers emit exactly the same eight keys in the same order. What differs is which of them a given source can actually fill.

Why is price always "N/A" for some sources?

Because those sources don't provide it: allevents and eventseye hardcode "N/A". Only district, meetup and eventbrite populate it. Same story for venue_address, which only eventseye, meetup and eventbrite fill.

Why "N/A" instead of null?

That's the Actor's convention for every absent value. Test == "N/A" rather than relying on null checks.

Can I sort the merged set by date?

Not on the raw value — date is not normalised. Meetup can return ISO 8601 with a timezone while AllEvents returns something like Sat, 12 Sep, 7:00 pm. Parse per source first.

Will the same event appear twice?

Yes, if two platforms list it. There's no cross-platform deduplication; dedupe on title + date.

Pricing

How is this billed?

Pay-per-event — one charge per record pushed. The current rate is on the Actor's Pricing tab. Apify platform usage is billed separately and depends heavily on which sources you pick (eventseye is HTTP-only and cheapest; district is the most expensive).

How do I keep a run cheap?

Fewer sources, prefer eventseye/eventbrite, drop district, and never use limit: 0 without a spend cap.

How do I guarantee an agent never overspends?

Pass maxTotalChargeUsd as a query parameter on the run endpoint.


This Actor's place in the event family

ActorSourcesFilters?Why pick it over this one
This Actor5 platforms❌ NoneOne unified 8-field schema across five platforms in one run
Smart Event Scraper6 platformsCategory, keyword, date range⭐ Same multi-platform idea plus the filtering this Actor lacks, with per-source limits
All Events Scraperallevents.inDepth on one platform — more fields than the unified record
Eventbrite Scrapereventbrite.com⚠️ SomeDepth on Eventbrite, incl. category and location handling
District.in Event Scraperdistrict.inHas the residential-proxy support District requires
Events Eye Scrapereventseye.com⚠️ SomeDepth on trade shows and exhibitions
Eventim Scrapereventim.de✅ Search, city, category, dateGerman ticketed events with live price and stock
Ticketmaster FR/ES ScraperTicketmaster API⚠️ Category onlyFrench and Spanish ticketed events via the official API

Smart Event Scraper is the closer sibling — compare them before choosing. It covers six platforms (including District) and takes a category, a free-text search_query and a date_from/date_to range, with a per-source limit and one standardised output schema. If you want filtering, go there.

Choose this Actor when you specifically want these five sources normalised into one flat 8-field record and don't need filtering at the source.

Enrichment & downstream pipeline

ActorUse it for
Google Maps Business Leads & Sales IntelligenceVenue contact details — email, phone, website — which this Actor never returns
Website Contact ScraperContacts from an organiser's or venue's own website
Hospitality Lead ScraperBars, hotels and restaurants near a venue, for event-driven local outreach

Suggested pipeline patterns

📊 Platform coverage audit Run all sources for one city → group by source → see which platform actually covers that market before committing to a single-source Actor.

🌍 Mixed consumer + B2B feed ["allevents","eventseye"] → one dataset holding both consumer events and trade shows, already in one shape.

💸 Cheap-first two-pass Pass 1 ["eventseye","eventbrite"] (no browsers) → if coverage is thin, pass 2 adds ["allevents","meetup"].

🎯 Event-driven local sales Large upcoming events in a city → Google Maps Business Leads or Hospitality Lead Scraper for nearby venues → pitch catering, transport or accommodation.

🏢 Trade-show prospecting ["eventseye"] per target city → Website Contact Scraper on exhibitor sites → a contactable exhibitor list.

Browse all Actors by Techforce Global at apify.com/techforce.global.


🔐 Compliance & Data Privacy

This Actor is an independent tool. It is not affiliated with, endorsed by, or sponsored by AllEvents, EventsEye, District, Zomato, Meetup, Eventbrite, or any venue, organiser or performer named in its output. All trademarks are the property of their respective owners.

It reads publicly available event listings from five platforms. It does not log in, does not accept credentials, and never buys, reserves or contacts anything.

The output is mostly commercial event data — titles, venues, dates, prices, public URLs. Three things still deserve care:

  • Meetup and Eventbrite listings can carry personal data. Community meetups are often organised by named individuals, and a group or event title can identify a person. Where that happens you are processing personal data under GDPR/UK GDPR and CCPA — have a lawful basis, set a retention period, and don't repurpose it as a marketing list simply because it was public.
  • Each source has its own terms of service, and you are bound by all five you enable. They are not interchangeable: a use that's acceptable for a public trade-show directory may not be for a ticketing platform. Review the terms of each source you select.
  • Prices and availability are volatile and time-stamped by the run. Republishing them as current commits you to a refresh cadence; always attribute the source and link through to url for the live listing. Note also that price is absent by design on two of the five sources, so a merged feed will have systematic gaps.

Because sources run sequentially at modest volume, the footprint on each site is light — don't defeat that by running many parallel executions against the same source and city. You remain responsible for complying with every enabled platform's terms of service and all applicable data-protection and consumer-protection law in the markets you operate in.


🆘 Support & Custom Pipeline Engineering

Need date and keyword filtering wired in, proxy support for the District source, cross-platform deduplication, additional platforms, or a scheduled multi-city event pipeline feeding your own systems?


Made with ❤️ by Techforce Global Specialists in High-Performance Web Scrapers and AI Automation.


🏷️ Structured data for search & AI discovery

{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"name": "Universal Event Scraper — 5 Event Platforms, One Unified Schema",
"applicationCategory": "BusinessApplication",
"operatingSystem": "Cloud (Apify platform)",
"description": "Scrapes events for one city from up to five platforms — AllEvents.in, EventsEye.com, District.in, Meetup.com and Eventbrite — in a single run, normalising every source into the same eight-field record: source, title, url, date, city, venue, venue_address and price. Each source uses a purpose-built engine (plain HTTP for the EventsEye trade-show directory, Playwright for the rendered listings, GraphQL interception for Meetup, public browse JSON for Eventbrite), and results can be delivered into Notion, Slack, Airtable, Google Sheets or any authorized MCP connector. Date-range and keyword filtering are not supported.",
"url": "https://apify.com/techforce.global/universal-event-scraper",
"offers": {
"@type": "Offer",
"priceCurrency": "USD",
"description": "Pay-per-event, charged once per record returned. The current rate is listed on the Actor's Pricing tab."
}
}