ICS Calendar Feed Merger & Deduplicator avatar

ICS Calendar Feed Merger & Deduplicator

Pricing

from $1.00 / 1,000 unique merged calendar events

Go to Apify Store
ICS Calendar Feed Merger & Deduplicator

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

Ben E

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

10 days ago

Last modified

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

LimitValue
Calendar URLs per run50
Calendar response size2 MB
Redirects per calendar3
Date window366 days
Events per calendar5,000
Unique output rows20,000
Include keywords20
Exclude keywords20

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.