ICS Merge & Dedupe

Combine one or more iCalendar (.ics) files into a single calendar and drop duplicate events — matched by UID, or by start time and title for the same event exported by different apps. Paste the file contents; everything runs in your browser and nothing is uploaded.

Try:
Merged calendar

About this tool

ICS Merge & Dedupe combines one or more iCalendar files — the .ics format that Google Calendar, Apple Calendar and Outlook export — into a single calendar and removes duplicate events along the way. Paste the contents of one file, or concatenate several files one after another, and you get back one clean BEGIN:VCALENDAR…END:VCALENDAR document with each event kept only once.

Duplicates are matched the way real calendars overlap: by UID when both copies carry one (the same event re-exported from the same source), or by start time and title for the same public event that two different apps each stamped with their own UID. Every surviving event is copied through verbatim — its properties, folded lines, alarms and RFC 5545 escapes are untouched — so the result imports cleanly back into any calendar app. Line endings are normalized to CRLF, identical VTIMEZONE blocks are emitted once by their TZID, and VTODO / VJOURNAL / VFREEBUSY components pass through unchanged.

Everything runs locally in your browser — your calendar never leaves your device.

Worked example

Input — two files that both contain the same event (same UID):

BEGIN:VCALENDAR
VERSION:2.0
BEGIN:VEVENT
UID:[email protected]
DTSTART:20240309T081530Z
SUMMARY:Team Standup
END:VEVENT
END:VCALENDAR
BEGIN:VCALENDAR
VERSION:2.0
BEGIN:VEVENT
UID:[email protected]
DTSTART:20240309T081530Z
SUMMARY:Team Standup
END:VEVENT
END:VCALENDAR

Output (defaults — smart matching, keep first, sorted) — one calendar, one event:

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//gizza-ai//ics-merge-dedupe//EN
CALSCALE:GREGORIAN
BEGIN:VEVENT
UID:[email protected]
DTSTART:20240309T081530Z
SUMMARY:Team Standup
END:VEVENT
END:VCALENDAR

Options

Limits & edge cases

FAQ

How does it decide two events are the same?

It depends on the Match duplicates by option. With smart (the default), two events match if they share a UID; an event with no UID falls back to matching on its normalized start time and title. uid_start additionally requires the start times to match, which keeps recurrence overrides that reuse one UID. start_title ignores UIDs completely and matches on start + title, which is what collapses the same public event that Google and Apple each exported under a different UID.

Which copy of a duplicate is kept?

With Keep which copy set to first (the default), the earliest occurrence in the combined input wins and later copies are dropped. Set it to last_modified to keep the copy with the newest LAST-MODIFIED timestamp (falling back to DTSTAMP when that property is absent), which is what you want when a second file is a more recently edited version of the first.

Are my events changed or reformatted?

No. Every surviving event is copied through verbatim — its properties, ordering, folded continuation lines, VALARM sub-blocks and RFC 5545 text escapes are left exactly as written. The only additions are a fresh VCALENDAR wrapper and, if you provide one, an X-WR-CALNAME calendar-name line. Line endings are normalized to CRLF so the output imports cleanly.

Is my calendar uploaded anywhere?

No. The merge runs entirely in your browser using WebAssembly — the .ics text you paste is processed on your own device and is never sent to a server.

Developer & Automation Access

Run it from the terminal

Same engine as this page, headless — via the gizza CLI:

gizza tool ics-merge-dedupe "BEGIN:VCALENDAR
VERSION:2.0
BEGIN:VEVENT
UID:[email protected]
DTSTART:20240309T081530Z
SUMMARY:Team Standup
END:VEVENT
END:VCALENDAR
BEGIN:VCALENDAR
VERSION:2.0
BEGIN:VEVENT
UID:[email protected]
DTSTART:20240309T081530Z
SUMMARY:Team Standup
END:VEVENT
END:VCALENDAR"

New to the CLI? Get gizza →

Open it by URL

Pre-fill and auto-run this tool with query parameters — the names match the API/CLI:

https://gizza.ai/tools/ics-merge-dedupe/?ics=BEGIN%3AVCALENDAR%0AVERSION%3A2.0%0ABEGIN%3AVEVENT%0AUID%3Aevt-1%40example.com%0ADTSTART%3A20240309T081530Z%0ASUMMARY%3ATeam%20Standup%0AEND%3AVEVENT%0AEND%3AVCALENDAR%0ABEGIN%3AVCALENDAR%0AVERSION%3A2.0%0ABEGIN%3AVEVENT%0AUID%3Aevt-1%40example.com%0ADTSTART%3A20240309T081530Z%0ASUMMARY%3ATeam%20Standup%0AEND%3AVEVENT%0AEND%3AVCALENDAR&dedupe_by=smart&keep=first&sort=true&calendar_name=Team%20Calendar

Machine-readable descriptor: tool.json — title + parameters JSON Schema for agents.