Skip to content

How to list iCloud calendar events

Apple has no public calendar REST API. iCloud Calendar runs on CalDAV, an XML-based protocol that requires persistent connections and manual credential management. There’s no developer portal, no SDK, and no way to programmatically generate the app-specific passwords that Apple requires for third-party access. Nylas handles the CalDAV connection for you and exposes iCloud Calendar through the same Events API you use for Google and Microsoft.

This guide covers listing events from iCloud Calendar accounts, including the app-specific password requirement, the one-year time range cap, and iCloud-specific behaviors that affect how you query events.

CalDAV works, but building on it directly is a significant investment:

  • XML everywhere. CalDAV uses WebDAV extensions with XML request and response bodies. Nylas gives you REST endpoints with JSON.
  • Persistent connections required. You need to maintain long-lived CalDAV sessions per user. Nylas manages connection pooling and reconnection behind the scenes.
  • No programmatic password generation. Every user must manually create an app-specific password through their Apple ID settings. Nylas guides users through this during authentication, but the manual step can’t be eliminated.
  • No real-time push. CalDAV has no native push notification system comparable to Google’s or Microsoft’s. Nylas provides webhooks for change notifications across all providers.
  • Limited query capabilities. CalDAV supports basic time-range queries but lacks the rich filtering that Google Calendar or Microsoft Graph offer. Nylas normalizes what it can and clearly documents the gaps.

If you’re comfortable with XML parsing and only need iCloud, CalDAV works fine. For multi-provider apps or faster development, Nylas saves you from building and maintaining a CalDAV client.

You’ll need:

  • A Nylas application with a valid API key
  • A grant for an iCloud account using the iCloud connector (not generic IMAP)
  • An iCloud connector configured in your Nylas application

New to Nylas? Start with the quickstart guide to set up your app and connect a test account before continuing here.

iCloud requires app-specific passwords for third-party access. Unlike Google or Microsoft OAuth, there’s no way to generate these programmatically. Each user must create one manually in their Apple ID settings.

Nylas supports two authentication flows for iCloud:

MethodBest for
Hosted OAuthProduction apps where Nylas guides users through the app password flow
Bring Your Own (BYO) AuthenticationCustom auth pages where you collect credentials directly

With either method, users need to:

  1. Go to appleid.apple.com and sign in
  2. Navigate to Sign-In and Security then App-Specific Passwords
  3. Generate a new app password
  4. Use that password (not their regular iCloud password) when authenticating

App-specific passwords can’t be generated via API. Your app’s onboarding flow should include clear instructions telling users how to create one. Users who enter their regular iCloud password will fail authentication.

The full setup walkthrough is in the iCloud provider guide and the app passwords guide.

Make a List Events request with the grant ID and a calendar_id. By default, Nylas returns up to 50 events sorted by start time.

iCloud does not support calendar_id=primary. You must call the List Calendars endpoint first to get the actual calendar ID for the account.

For iCloud accounts, replace <CALENDAR_ID> in these samples with an actual calendar ID from the List Calendars response. The primary shortcut that works for Google and Microsoft is not available.

You can narrow results with query parameters. Here’s the full set supported by the Events API:

ParameterWhat it doesExample
calendar_idRequired. Filter by calendar?calendar_id=primary
titleMatch on event title (case insensitive)?title=standup
descriptionMatch on description (case insensitive)?description=quarterly
locationMatch on location (case insensitive)?location=Room%20A
startEvents starting at or after a Unix timestamp?start=1706000000
endEvents ending at or before a Unix timestamp?end=1706100000
attendeesFilter by attendee email (comma-delimited)[email protected]
busyFilter by busy status?busy=true
metadata_pairFilter by metadata key-value pair?metadata_pair=project_id:abc123

iCloud does not support several filter parameters. The following will either be ignored or return an error:

  • attendees - not supported on CalDAV
  • busy - not supported on CalDAV
  • metadata_pair - not supported on CalDAV

Additionally, the time range between start and end cannot exceed one year. Requests with a wider range will fail.

Here’s how to filter events by title within a time range:

Remember to replace calendar_id=primary in the shared examples with an actual iCloud calendar ID.

iCloud Calendar runs on CalDAV, which gives it a different behavior profile than Google or Microsoft. Here’s what you should plan for.

Google and Microsoft both support calendar_id=primary as a shorthand for the user’s default calendar. iCloud does not. You must call the List Calendars endpoint first and pick the correct calendar ID from the response.

The default calendar name varies by language and region. English accounts typically have a calendar called “Calendar” or “Home”, but don’t count on it. Always discover calendar IDs dynamically.

The start to end range in a List Events request cannot exceed one year for iCloud accounts. If you need events across a longer window, split the request into multiple calls with consecutive one-year ranges and paginate through each.

CalDAV supports a narrower set of query capabilities than Google Calendar or Microsoft Graph. For iCloud accounts:

  • title, description, location, start, and end work as expected
  • attendees, busy, and metadata_pair are not supported
  • There is no equivalent to Google’s event_type filter
  • show_cancelled, ical_uid, updated_after, updated_before, and master_event_id are not available

If your app targets multiple providers, test your filter combinations against iCloud specifically. A query that works on Google may silently return different results on iCloud.

App-specific passwords and user experience

Section titled “App-specific passwords and user experience”

The biggest friction point for iCloud integration is the app-specific password. A few things to keep in mind:

  • Passwords cannot be generated programmatically. Every user must create one manually.
  • Users can revoke an app password at any time through their Apple ID settings, which invalidates the grant.
  • There’s no way for your app to detect a revoked password before the next sync attempt fails. Use webhooks to catch grant.expired events.
  • Your onboarding flow should include step-by-step instructions with screenshots showing users how to create an app password.

iCloud Calendar’s CalDAV foundation means a simpler feature set compared to Google or Microsoft:

  • No conferencing auto-attach. Google can automatically generate Meet links when you create events. iCloud has no equivalent. You can still include conferencing details manually in the event body.
  • No event types. Google supports focusTime, outOfOffice, and workingLocation event types. iCloud treats all events the same.
  • No color IDs. Calendar and event colors are managed locally in Apple Calendar and are not exposed through CalDAV.
  • Recurring events work through standard iCalendar (RFC 5545) recurrence rules. Nylas expands recurring events into individual instances, just like it does for other providers.

CalDAV sync can be slower than Google’s push notifications or Microsoft’s change subscriptions. A few practical notes:

  • Changes made in Apple Calendar may take a few minutes to appear through the Nylas API.
  • Use webhooks rather than polling. Nylas monitors for changes and sends notifications when events are created, updated, or deleted.
  • If you need near-real-time sync and iCloud is your only provider, be aware that CalDAV introduces inherent latency that does not exist with Google or Microsoft.

The Events API returns paginated responses. When there are more results, the response includes a next_cursor value. Pass it back as page_token to get the next page:

Keep paginating until the response comes back without a next_cursor.

For iCloud accounts, replace calendar_id=primary in the pagination examples with the actual calendar ID from the List Calendars response.