If you're building a webinar registration page, a course launch landing page, or a podcast announcement email, you need an add-to-calendar button. The kind that lets a visitor click once and have your event drop into their Google Calendar, Apple Calendar, or Outlook with a reminder pre-set.
You've got two real options.
The hard way: build it yourself with raw ICS files and direct calendar URLs. It's free, gives you total control, and works forever โ but you'll spend a few hours getting timezones and recurrence right.
The easy way: use a tool that does it for you. Drop in an embed code, get a button that handles every calendar provider plus the email-safe rendering quirks.
This tutorial covers both. By the end you'll have a working calendar button you can drop on any website, and you'll understand enough about ICS files to debug the inevitable Outlook edge case.
Key takeaways
- โAdd-to-calendar buttons are essentially a wrapper around five direct calendar URLs (Google, Apple, Outlook, Office 365, Yahoo) plus a downloadable .ics file.
- โThe hand-rolled approach takes about 30 minutes. The shortcut takes 30 seconds.
- โEmail clients require a specific button format โ HTML buttons break in Outlook. Use an image-row of provider icons instead.
- โTimezones and recurring events are where 90% of bugs hide. Get those right and the rest is easy.
What an "Add to Calendar" button actually is
It looks like a single button on your page. Behind the scenes it's a small set of links โ one per calendar provider โ that each tell that calendar to import an event with the title, time, location, and description you've set.
The five providers worth supporting in 2026:
- Google Calendar โ accepts a
https://calendar.google.com/calendar/render?...URL with parameters in the query string - Apple Calendar / iOS โ needs a downloadable
.icsfile (RFC 5545 format) - Outlook (web) โ accepts a
https://outlook.live.com/calendar/0/deeplink/compose?...URL - Office 365 โ accepts
https://outlook.office.com/calendar/0/deeplink/compose?... - Yahoo Calendar โ accepts
https://calendar.yahoo.com/?...
You can build all five by hand. We'll walk through how, then look at when it's worth.
Step 1: Create your event details
Before you write any code, write down the event:
Title: Q4 Product Launch Webinar
Start time: 2026-06-15 18:00 UTC
End time: 2026-06-15 19:00 UTC
Location: https://zoom.us/j/123456789
Description: Live walkthrough of the new analytics dashboard.
Q&A at the end.
Two things matter here. First, always store start/end in UTC and let the calendar provider convert. If you embed local time, anyone in a different timezone will see the wrong hour. Second, include a clear description with any joining instructions โ the description is the one place that survives across all five providers reliably.
Step 2: Build the ICS file (the foundation)
The .ics file is the universal calendar format. Apple Calendar requires it, Outlook desktop requires it, and any non-Google calendar will fall back to it. Build this once and you've covered three of the five providers.
A minimal valid ICS file looks like this:
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Your Company//Your App//EN
BEGIN:VEVENT
UID:q4-launch-webinar-2026@yoursite.com
DTSTAMP:20260427T120000Z
DTSTART:20260615T180000Z
DTEND:20260615T190000Z
SUMMARY:Q4 Product Launch Webinar
DESCRIPTION:Live walkthrough of the new analytics dashboard.\nQ&A at the end.
LOCATION:https://zoom.us/j/123456789
END:VEVENT
END:VCALENDAR
A few rules that trip people up:
- Newlines must be
\r\n, not\n. The RFC 5545 spec is strict about this. If you generate ICS in JavaScript, use'\r\n'explicitly. - Dates use
YYYYMMDDTHHMMSSZformat with the trailingZfor UTC. No dashes, no colons. UIDmust be globally unique and stable. Use<something>@yourdomain.com. If you regenerate the UID on every download, calendars treat it as a different event each time and you get duplicates.- Description newlines are
\ninside the value (not\r\n). Yes, that's inconsistent with the rest of the file. Welcome to RFC 5545.
Save that as event.ics and serve it with content type text/calendar. Clicking the link in any email client will open the user's default calendar app with the event pre-populated.
Validate your ICS file
Before you ship, paste your ICS into icalendar.org/validator.html. Common bugs (missing DTSTAMP, wrong line endings, malformed UID) get caught here.
Step 3: Build the Google Calendar URL
Google Calendar accepts events via URL parameters. The format:
https://calendar.google.com/calendar/render
?action=TEMPLATE
&text=Q4%20Product%20Launch%20Webinar
&dates=20260615T180000Z/20260615T190000Z
&details=Live%20walkthrough%20of%20the%20new%20analytics%20dashboard.
&location=https%3A%2F%2Fzoom.us%2Fj%2F123456789
Built up as a single line:
https://calendar.google.com/calendar/render?action=TEMPLATE&text=Q4%20Product%20Launch%20Webinar&dates=20260615T180000Z/20260615T190000Z&details=Live%20walkthrough%20of%20the%20new%20analytics%20dashboard.&location=https%3A%2F%2Fzoom.us%2Fj%2F123456789
URL-encode every parameter value (replace spaces with %20, : with %3A, etc.). Most languages have a built-in for this โ encodeURIComponent() in JavaScript, urllib.parse.quote() in Python.
Step 4: Build the Outlook + Office 365 URLs
Outlook.com (consumer) and Office 365 (work) use the same parameter shape but different hosts:
https://outlook.live.com/calendar/0/deeplink/compose?path=/calendar/action/compose&rru=addevent&subject=Q4%20Product%20Launch%20Webinar&startdt=2026-06-15T18:00:00Z&enddt=2026-06-15T19:00:00Z&body=Live%20walkthrough...&location=https%3A%2F%2Fzoom.us%2Fj%2F123456789
For Office 365, swap outlook.live.com for outlook.office.com:
https://outlook.office.com/calendar/0/deeplink/compose?path=/calendar/action/compose&rru=addevent&subject=...&startdt=...&enddt=...
Note the date format here is ISO-8601 with dashes and colons (2026-06-15T18:00:00Z), unlike Google's compact format. Calendar URL specs are not consistent. This is one of the larger reasons people use a tool.
Step 5: Build the Yahoo Calendar URL
Yahoo's format is its own thing:
https://calendar.yahoo.com/?v=60&view=d&type=20&title=Q4%20Product%20Launch%20Webinar&st=20260615T180000Z&et=20260615T190000Z&desc=...&in_loc=https%3A%2F%2Fzoom.us...
Yahoo's share has been declining, but it's still ~3% of US users in 2026. Worth supporting if your audience is broad consumer.
Step 6: Wrap them in a button
Now you've got five links. The simplest button is just a <button> that toggles a dropdown:
<div class="calendar-button">
<button onclick="document.getElementById('cal-menu').classList.toggle('open')">
Add to Calendar
</button>
<ul id="cal-menu" class="hidden">
<li><a href="GOOGLE_URL">Google Calendar</a></li>
<li><a href="https://yourdomain.com/event.ics">Apple Calendar</a></li>
<li><a href="OUTLOOK_LIVE_URL">Outlook</a></li>
<li><a href="OUTLOOK_OFFICE_URL">Office 365</a></li>
<li><a href="YAHOO_URL">Yahoo</a></li>
</ul>
</div>
Style it however you want. The CSS isn't the interesting part of this โ the URLs are.
That's a lot of code for one button
SpreadEvent generates all five URLs + the ICS file from a single embed code. Free for 3 events with 100 clicks/month, no credit card.
Step 7: Make it work in email (this is where it gets ugly)
Here's the part most tutorials skip: the button you just built does NOT work in email clients.
Outlook (the desktop one, not Outlook.com) renders HTML through Microsoft Word's rendering engine. JavaScript is stripped. Most CSS is stripped. The dropdown won't open.
Gmail's web client is more permissive but still strips JavaScript and a lot of CSS. Apple Mail is the most lenient but still has surprises.
The pattern that works across every email client in 2026 is a row of clickable images โ one per provider. Each image is a styled "Add to Google Calendar" / "Add to Apple Calendar" link that goes straight to the calendar URL.
<table>
<tr>
<td><a href="GOOGLE_URL"><img src="add-to-google.png" alt="Add to Google Calendar" /></a></td>
<td><a href="APPLE_ICS_URL"><img src="add-to-apple.png" alt="Add to Apple Calendar" /></a></td>
<td><a href="OUTLOOK_URL"><img src="add-to-outlook.png" alt="Add to Outlook" /></a></td>
<td><a href="OFFICE365_URL"><img src="add-to-office365.png" alt="Add to Office 365" /></a></td>
<td><a href="YAHOO_URL"><img src="add-to-yahoo.png" alt="Add to Yahoo" /></a></td>
</tr>
</table>
Tables, not divs. Inline styles, not classes. PNG images, not SVGs. Every email client renders this the same. It's ugly markup but it's reliable.
Why HTML buttons fail in Outlook
The Outlook desktop client uses Microsoft Word's rendering engine for HTML emails โ not a real browser. Word doesn't support display: flex, modern CSS layout, JavaScript, or most pseudo-classes. A <button> with a dropdown collapses into static text. The image-row approach side-steps the entire mess by relying only on <table>, <tr>, <td>, <a>, and <img> โ markup that's been stable since 1999.
Step 8: Test before you ship
Before you put this in production, test it in:
- Real Google Calendar (logged into a Google account, not just the URL preview)
- Apple Calendar on iOS โ download the
.ics, tap it, confirm the event imports correctly - Outlook desktop (Office 2019+) โ paste the email HTML into a test send and click each button
- Gmail web client โ known to lazy-load images, so test with images-on
- Across timezones โ if your audience is global, test from at least one non-UTC timezone
The most common bugs:
- Times shifted by one hour because of DST (test with a date that crosses a DST boundary)
- Description newlines rendering as
\nliterally instead of line breaks (escape with\\nin the URL or use%0A) - ICS file downloading as
event.ics.txtbecause the server isn't sending the rightContent-Typeheader
Step 9: Track clicks (optional but useful)
If this is for marketing, you want to know which provider your audience uses. Wrap each link with a tracking redirect, or add UTM parameters:
GOOGLE_URL + &utm_source=email&utm_campaign=q4-launch&utm_content=google
Then look at your analytics tool to see the breakdown. In our experience, B2B audiences are 60โ70% Outlook/Office 365, B2C is 65โ80% Google. iPad-heavy audiences (creators, agencies) tilt Apple Calendar.
When to skip all this and use a tool
The hand-rolled approach above is genuine work โ maybe 2โ3 hours including testing โ but you only do it once per event template. If you run a single annual event, this is fine.
If you run events regularly, the math changes:
| Manual approach | Cost over 12 months |
|---|---|
| 1 event/year | 3h ร $0/h = free |
| 1 event/month | 36h ร $50/h opportunity cost = $1,800 |
| 1 event/week | 156h ร $50/h = $7,800 |
That's why tools exist. SpreadEvent's Free plan handles 3 events, the cheapest paid tier ($16/mo CalGet) handles 1,500 clicks/event, and Pro plans ($27โ129/mo) lift the caps.
We've written a full comparison of the seven main calendar-button tools so you can pick the one that fits.
The shortcut version with SpreadEvent
If you've decided you want a tool instead of hand-rolling, here's how it works in our system. Same scenario as above (Q4 webinar at 18:00 UTC, Zoom link, etc.):
- Sign in (or sign up โ free, no credit card).
- Click + New Event, paste the title, date, time, location.
- Hit Save. Open the Embed tab.
- Pick a variant: Button, Dropdown, Link, Email, or QR. For a webinar landing page, Button is the right default.
- Customise colours, font, icon โ or accept the defaults.
- Click Copy embed code.
- Paste into your landing page (or WordPress Custom HTML block, or Webflow Embed component).
Total time: about 30 seconds. The embed handles all five calendar URLs, the ICS file, the email-safe variant, click tracking, RSVP capacity, and the device-aware Apple Calendar fallback.
That's the whole pitch.
FAQ
Yes โ every modern email client and browser blocks mixed content. The ICS file must be served over HTTPS. If you're using GitHub Pages, Cloudflare Pages, Netlify, or Vercel, HTTPS is automatic. If you're hosting your own domain on a custom server, get a Let's Encrypt cert.
Bottom line
You can build an add-to-calendar button by hand in an afternoon, and now you know how. The ICS spec, the five provider URLs, and the image-row email pattern are all the moving parts.
If your event volume justifies a tool, SpreadEvent handles all of this โ the manual work above plus the email-safe variant, click tracking, RSVP forms, and the bugs you'll only discover after shipping.
Start free, no credit card โ three events, 100 calendar clicks per month, every feature except the integration layer.
Newsletter
New posts. No spam.
Calendar marketing tips, comparisons, and behind-the-scenes from SpreadEvent. ~1 email per month.


