Source side 4 min read · Published · Verified

ICS download is a web page, not a calendar

Why a calendar export or feed address returns an HTML page instead of an .ics file, how to tell which page you got, and how to reach the real export.

Short answer

If a downloaded .ics file starts with <!DOCTYPE html> or <html>, the server sent a web page instead of calendar data, usually a login screen, a redirect to the home page, a firewall or bot-check page, or the events page itself. The file name means nothing; the first line decides. Read the page’s title to see which case you have, then fix the address or the access rule, not the calendar.

This guide is for the moment a calendar “file” turns out not to be one: the checker says Not a calendar file, a calendar app refuses to import it, or a subscription shows nothing. It is not the same problem as a calendar with no events, and the fix is somewhere else.

Why the file name doesn’t help

A file name is a label, not a format. When a browser saves a download it uses whatever name the server suggests, and MDN describes that suggested filename as “mostly indicative information”. A server that answers a feed request with its login page can still have that page saved as events.ics.

An iCalendar file is plain text whose first line is BEGIN:VCALENDAR. RFC 5545 registers it with the media type text/calendar. Anything else, whatever it is called, is not calendar data.

Look at the first lines

Open the file in a text editor, not a calendar app. Or run it through the ICS event checker, which reads it in your browser. For the test fixture below, a WordPress login form saved as .ics, the checker reports:

Not a calendar file
This looks like a saved web page, not an ICS export.

What we found
  Starts with HTML markup
  No BEGIN:VCALENDAR line
Real checker output for tests/fixtures/ics/html-disguised.ics. No count is shown, because nothing could be counted.
<!DOCTYPE html>
<html lang="en">
<head><title>Log in</title></head>
<body><form action="/wp-login.php"><input name="log"></form></body>
</html>
The fixture itself: a login page, not a calendar.

Work out which page you got

The <title> and the first visible text usually say which page the server sent. Each points to a different cause:

What the HTML is Likely cause Where to fix it
A login form (wp-login.php, “Log in”, “Members only”) The feed sits behind a login or membership rule Make the export public, or allow the feed address through the membership rule
The site’s home page The request was redirected Find the redirect: a redirect plugin, a changed events address, or a bot-redirect setting
“Access denied”, “Checking your browser”, a 403 or challenge page A firewall, security plugin or CDN blocked the request Allow the feed address in that tool, after confirming with whoever manages it
“Page not found” or a server error The address is wrong, or the events page has moved or broken Get the current export address from the events page
The events page itself, with event titles in it You saved the page you were viewing, not the export Use the export or subscribe link instead (below)

The Events Calendar’s documentation lists several of these for its own feeds: login requirements that calendar apps can’t get past, firewalls blocking feed requests, CDN measures that block some user agents and bots, and its Redirect Bots setting, which it says can answer a calendar importer’s request with a 301 redirect to the home page.

Check the response with curl

A terminal shows exactly what the server returns, including redirects:

curl -sS -L -o feed.ics \
  -w '%{http_code} %{content_type}\n%{url_effective}\nredirects: %{num_redirects}\n' \
  "https://example.org/events/list/?ical=1"
head -n 1 feed.ics
Prints the final status, content type, address after redirects and number of redirects. Replace the address with your export link.

What to look for:

  • A content type of text/calendar and a first line of BEGIN:VCALENDAR: the address works from here. If the browser download still fails, the problem is browser-specific, such as being logged in or a cached redirect.
  • text/html with a final address on another page: a redirect. Run curl -sSIL with the same address to see each hop and decide which one is wrong.
  • 403 or 503 with text/html: a block or challenge page.
  • 200 with text/html at the same address: the address serves a page, not an export. It is the wrong link.

Find the real export

Once you know which page you were getting, get the export address directly:

  • The Events Calendar: use the calendar’s export or subscribe option, or add ?ical=1 to the events view address. Its documentation also gives a test address that returns an .ics file of the next 30 events: /?post_type=tribe_events&ical=1&eventDisplay=list on the site’s domain.
  • Hosted calendars (Google Calendar, Outlook and similar): look in the calendar’s sharing or integration settings for an address in iCal format, usually ending in .ics. Private or “secret” addresses work without a login, so treat them like a password and don’t paste them into tickets.
  • Other plugins and systems: look for Export, Subscribe or iCal on the events page or in the plugin’s settings, and choose the .ics or iCal option rather than “Add to Google Calendar”.

Download it again and repeat the first-line check. When the checker gives any of its readable results, you have the calendar data and can move on to whether it has upcoming events.

Why it matters beyond the download

An HTML response is not an empty calendar, and it’s worth saying so in a client report. A calendar app or importer subscribed to that address gets no usable events from it, so anything fed by it, such as a subscription, a sync or another site’s import, can go quiet while the original calendar is perfectly full. If a feed that used to work starts returning HTML, look first at what changed around it: a new security rule, a membership plugin, a redirect or a moved events page.

Limitations of this guide

  • The checker identifies HTML by its opening markup. It can’t tell you which plugin or rule produced the page; the table above is a guide to the usual causes, not a diagnosis.
  • Setting names for The Events Calendar come from its documentation at the verification date above.
  • curl doesn’t run JavaScript. If a security service only lets real browsers through, curl and a calendar app may both be blocked while your browser works; that is useful evidence in itself.

Sources

  1. Troubleshooting Subscribe and Export on The Events Calendar · The Events Calendar documentation (Nexcess) , accessed 7 Nov 2026
  2. RFC 5545: Internet Calendaring and Scheduling Core Object Specification (iCalendar) · IETF , accessed 7 Nov 2026
  3. Content-Disposition header · MDN Web Docs , accessed 7 Nov 2026

Maintaining calendars for several clients? We’re recruiting five agencies to pilot automated checks Pilot