Click a link starting https:// that points at a calendar file and your browser downloads it. Click the same link starting webcal:// and your calendar app opens and offers to subscribe. Same server, same bytes, entirely different outcome.
Below: what the scheme does, why subscribing beats importing, how each major client handles refresh, how to publish a feed, and the security consideration most people miss.
webcal:// is a URL scheme that tells the operating system "this URL points at a calendar feed, hand it to a calendar application to subscribe to, do not download it".
It is not a protocol. There is no webcal port, no webcal handshake, no webcal server software. When a client resolves webcal://example.com/team.ics, it substitutes https:// (or http:// for older or explicitly insecure feeds) and makes a completely ordinary HTTP GET request. What comes back is standard iCalendar data, exactly as described in the complete guide to ICS files.
It is also not a standard. There is no RFC for webcal. Apple introduced it, everyone else adopted it because it solved a real problem, and it has been de facto universal ever since without being formally specified. In practice it works reliably.
Browsers treat an HTTPS URL ending in .ics as a file to download, which is the wrong outcome when the publisher wants you subscribed rather than holding a snapshot. There is no HTTP header that reliably means "subscribe to me": Content-Type: text/calendar gets you close on some platforms and does nothing on others. Registering a custom scheme sidesteps the browser entirely, handing the URL to whichever application claims webcal.
This is the actual decision, and the scheme is just the mechanism for expressing it.
| Import (file) | Subscribe (URL) | |
|---|---|---|
| What you get | A copy, owned by you | A live mirror, owned by the publisher |
| Updates | Never | On each refresh |
| Deletions upstream | Stay in your calendar forever | Disappear from your calendar |
| Editable by you | Yes | No, read-only |
| Removing it | Delete each event, or the calendar | Unsubscribe, one action |
| Works offline | Yes | Yes, cached copy |
The row that matters most is the second. An imported file is frozen at the moment of import. Publish a fixture list as a downloadable .ics, then postpone a match, and every person who downloaded it holds a wrong date with no way for you to reach them. Publish the same data as a feed and the correction propagates on the next poll.
The corollary is that subscribed events are read-only. Recipients cannot drag them, edit the title, or delete a single instance. For a published schedule that is usually correct. For something a recipient might want to personalise, it is a real limitation.
Feeds are polled, not pushed. There is no notification mechanism, so "how often does it update" is entirely down to the client, and the answer varies a lot.
Google polls external feeds on its own schedule, typically around 24 hours, with no user-facing setting to change it. Observed intervals range from about 8 hours to several days, and clicking refresh in the UI does not force a re-fetch.
This is the single biggest constraint on subscription calendars. If your audience is mostly on Google, do not promise same-day updates. Google's "From URL" field also only accepts http and https, so publish both forms of your link, as covered in the Google Calendar guide.
Apple is the most configurable. On iOS, Settings > Apps > Calendar > Accounts > the subscribed calendar > Refresh lets you pick every 5 minutes, 15 minutes, hourly, daily or weekly. On macOS it is the calendar's Get Info panel. The catch is that iOS treats the setting as a target rather than a guarantee, deferring background fetches on battery or in Low Power Mode. Opening the Calendar app forces a check. Full detail in the Apple Calendar guide.
Classic Outlook for Windows honours publisher hints. Two properties can advertise a poll frequency inside the feed itself:
X-PUBLISHED-TTL:PT1H REFRESH-INTERVAL;VALUE=DURATION:PT1H
X-PUBLISHED-TTL is Microsoft's non-standard original. REFRESH-INTERVAL is the standardised equivalent from RFC 7986. Emit both, using an ISO 8601 duration such as PT1H for hourly or P1D for daily. Outlook enforces a floor of roughly an hour regardless of what you ask for. Outlook on the web and new Outlook are less predictable, often landing in the several-hours range. See the Outlook guide for the subscription setup path in each version.
Design for a worst case of about 24 hours. Publish the hints anyway, because the clients that honour them will refresh faster and it costs you two lines. And if a change is genuinely urgent, email people. Do not rely on a poll.
The server side is straightforward. You need an HTTPS endpoint that returns iCalendar data.
Serve it with the right headers:
Content-Type: text/calendar; charset=utf-8 Content-Disposition: inline; filename="schedule.ics" Cache-Control: max-age=3600
Avoid Content-Disposition: attachment, which nudges browsers toward downloading rather than handing off.
The body is a normal VCALENDAR with your events inside it, plus a few properties that matter specifically for feeds:
BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Your Org//Fixtures//EN METHOD:PUBLISH X-WR-CALNAME:First Team Fixtures X-WR-CALDESC:All league and cup fixtures for the 2026 season X-PUBLISHED-TTL:PT1H REFRESH-INTERVAL;VALUE=DURATION:PT1H ...VEVENT components... END:VCALENDAR
X-WR-CALNAME sets the calendar's display name in the subscriber's app. Without it, clients fall back to the URL, and your subscribers end up with a calendar called "feed.ics". It is non-standard but universally supported and worth including every time. METHOD:PUBLISH marks the content as informational rather than a scheduling request, which is what you want for a feed.
Two rules for the events themselves. First, keep UIDs stable. Clients match events by UID, so regenerating them on each request makes every poll a churn of deletions and re-additions, showing up as duplicate notifications and lost reminders. Derive the UID from your database identifier and never change it.
Second, include VTIMEZONE blocks for every TZID you reference, or use UTC timestamps ending in Z. Feeds are consumed in unknown locales, and a floating time will be wrong for most of them.
Once the feed is live, publish the webcal:// form as the primary subscribe link and the https:// form as a fallback. To check what a client will actually see, fetch the URL and drop the response into the ICS viewer, which surfaces structural errors, or use the ICS to CSV converter for a spreadsheet view.
This is the part people miss, and it has caused real incidents.
Calendar clients do not reliably support authentication on subscribed feeds. Some handle HTTP Basic auth, most do not, and none handle OAuth or a login form. In practice, feed URLs are secured by being unguessable: a long random token embedded in the path or query string.
Which means anyone holding the URL can read the entire calendar, forever. Consider what that implies:
Sensible practices: use a high-entropy token of at least 128 bits, issue a distinct URL per subscriber so you can revoke individually, support easy rotation, serve only over HTTPS, and rate-limit the endpoint since a leaked URL is a free scraping target. If a feed carries sensitive scheduling data, treat the URL exactly as you would treat a password, because functionally that is what it is.
Subscriptions are the right answer for ongoing, changing sets of events. They are the wrong answer in several common cases.
A single event. Asking someone to subscribe to a whole calendar for one webinar is a lot of friction, and the read-only constraint means they cannot even set their own reminder. Use an add to calendar link instead: one URL that detects the platform and drops that event into whichever calendar the recipient uses. That is the model on the add to calendar links page, and you can build one with the add to calendar link generator.
Events people need to personalise. If your recipients need to add notes, move things, or delete individual entries, they need their own copies. Offer a downloadable file.
Anything time-critical. A cancellation two hours before the event will not reach Google subscribers in time. Email them.
Where you need to know who is coming. A feed tells you nothing beyond an anonymous poll from an IP address. If attendance matters, you need a link with RSVP handling behind it.
The general rule: subscribe for schedules, link for individual events. Getting that split right removes most of the friction people experience with calendar sharing. More on the ongoing-schedule side is on the subscription calendars page, and if the terminology is still tangled, the ICS vs iCal vs webcal explainer untangles it.
If you want to test how a feed or a link behaves before publishing it, the free ICS generator will produce a valid file you can host and subscribe to yourself. It is a quick way to see the refresh behaviour of your own clients before you ask anyone else to trust it.
Last updated on July 22, 2026