ICS Calendar Feed Merger & Deduplicator
Pricing
from $1.00 / 1,000 unique merged calendar events
ICS Calendar Feed Merger & Deduplicator
Combine up to 50 public iCal/ICS feeds into one recurrence-aware, filtered, deduplicated JSON or CSV event dataset.
Pricing
from $1.00 / 1,000 unique merged calendar events
Rating
0.0
(0)
Developer
Ben E
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
10 days ago
Last modified
Categories
Share
Combine several public iCal / ICS calendar feeds into one clean, recurrence-aware event dataset. The Actor expands recurring events inside a bounded date window, applies cancellation and keyword filters, removes cross-calendar duplicates, and preserves every contributing source calendar.
Use it for community-event pipelines, school or municipal calendar aggregation, venue and tourism feeds, public holiday calendars, content operations, or automation workflows that need normalized JSON/CSV instead of several subscribed calendars.
What this Actor adds beyond an ICS parser
A parser turns one calendar file into event objects. This Actor handles the next operational layer:
- fetch up to 50 public calendar feeds
- expand RRULE occurrences within a date window
- apply EXDATE exclusions and RECURRENCE-ID overrides
- exclude cancelled events by default
- filter across title, description, location, and categories
- deduplicate the same occurrence across overlapping calendars
- merge source provenance and useful metadata
- sort the final dataset by the next event first
- export through Apify as JSON, CSV, Excel, XML, RSS, or API data
It follows RFC 5545 iCalendar semantics through the maintained node-ical parser.
Quick start
The only required input is calendarUrls:
{"calendarUrls": ["https://www.gov.uk/bank-holidays/england-and-wales.ics"],"expandRecurring": true,"excludeCancelled": true,"deduplicateBy": "smart","maxTotalEvents": 5000}
Leave dateFrom and dateTo blank to process the next 90 days. An explicit window can be up to 366 days:
{"calendarUrls": ["https://example.org/public-events.ics"],"dateFrom": "2026-07-01T00:00:00Z","dateTo": "2026-12-31T23:59:59Z","includeKeywords": ["workshop", "family"],"excludeKeywords": ["private"],"deduplicateBy": "smart"}
Output
Each dataset row is one unique event occurrence:
{"title": "Community workshop","start_at": "2026-08-12T22:00:00.000Z","end_at": "2026-08-12T23:30:00.000Z","start_date": null,"end_date": null,"timezone": "America/New_York","all_day": false,"duration_minutes": 90,"location": "Main Library","description": "Registration requested.","event_url": "https://example.org/events/community-workshop","organizer_name": "Programs Team","status": "CONFIRMED","categories": ["Workshop"],"uid": "workshop-2026@example.org","is_recurring_instance": true,"source_calendar_name": "Community Events","source_calendar_url": "https://example.org/public-events.ics","duplicate_count": 2,"duplicate_source_calendars": ["https://example.org/public-events.ics","https://example.net/area-events.ics"],"dedupe_key": "uid:workshop 2026 example org|2026-08-12T22:00:00.000Z","merged_at": "2026-07-11T22:30:00.000Z"}
The OUTPUT key-value-store record summarizes successful and failed calendars, parsed and filtered events, duplicates removed, unique rows emitted, the date window, and truncation state.
Deduplication choices
- Smart — UID plus occurrence time when a UID exists; otherwise normalized title, start time, and location.
- UID + occurrence time — explicitly prefer the event UID for overlapping feeds, with the title/time/location fallback when a UID is missing.
- Title + time + location — useful when different publishers issue different UIDs for the same public event.
The Actor keeps the longest description and fills missing location or event URL from duplicates. duplicate_count and duplicate_source_calendars make every merge inspectable.
Recurring events
With expandRecurring enabled, the Actor emits individual occurrences only inside the selected date window. It applies EXDATE removals and RECURRENCE-ID overrides and respects time-zone information supplied by the feed. A 366-day maximum prevents an unbounded recurrence rule from producing unlimited output.
Disable recurrence expansion only when you want original VEVENT records whose base start falls inside the window; future instances of an older base event will not be synthesized in that mode.
Pricing
- Apify's automatic Actor-start event: $0.00005 per run
- Unique merged event occurrence: $0.001 each ($1 per 1,000)
Failed calendars, filtered events, cancelled events, duplicates removed before output, and rows beyond the configured cap are not charged as unique event occurrences.
Safety and privacy
- Only user-supplied public HTTP or HTTPS calendar URLs are fetched.
- Event web links, attachments, alarms, and linked pages are never fetched.
- Private, local, reserved, credential-bearing, non-standard-port, oversized, redirect-looping, and invalid inputs are rejected.
- DNS and every redirect are revalidated against public address space; the selected public address is pinned for the request.
- Responses are capped at 2 MB, redirects at three, and each description at 500 characters.
- Attendee email addresses and raw ICS files are not emitted.
Public calendar feeds can still contain names, locations, descriptions, organizer information, or accidentally exposed details. Use only feeds you are authorized to process, avoid private or sensitive calendars, and review output before republishing it. This Actor is a deterministic data-processing tool, not a privacy, legal, compliance, scheduling, or safety guarantee.
Limits
| Limit | Value |
|---|---|
| Calendar URLs per run | 50 |
| Calendar response size | 2 MB |
| Redirects per calendar | 3 |
| Date window | 366 days |
| Events per calendar | 5,000 |
| Unique output rows | 20,000 |
| Include keywords | 20 |
| Exclude keywords | 20 |
API use
Run bene123/ics-calendar-feed-merger-deduplicator from the Apify Console, API, CLI, scheduler, webhook, Make, Zapier, or another Actor. The default dataset can be downloaded in the format your workflow already uses.
Support
Open an issue on the Actor page with a public reproducible calendar URL, the date window, and the expected versus actual result. Do not post private calendar URLs, access tokens, customer data, or attendee details.