Sync a CalDAV calendar#

CalDAVAdapter syncs one calendar through a python-caldav client: every object in it, tasks and journal entries as well as events. Quickstart shows a whole sync. This page covers what’s particular to CalDAV.

Connect with your server’s profile#

from caldav.davclient import DAVClient

from calendaring_sync.adapters.caldav import CalDAVAdapter

client = DAVClient(url=URL, username=USERNAME, password=PASSWORD, features=SERVER)
calendar = client.calendar(url=CALENDAR_URL)
adapter = CalDAVAdapter(replica, calendar)

Name your server in features when python-caldav has a profile for it, such as "radicale" or "stalwart". The profile saves a request for each event you create, and tells the adapter whether the server needs full listings. client.calendar(url=...) opens a calendar without a request; client.get_calendars() lists the account’s calendars instead.

Schedule full listings#

from datetime import UTC, datetime, timedelta

adapter.sync()
listed = replica.scope(adapter.scope_id).last_full_listing_at
stale = listed is None or datetime.now(UTC) - listed > timedelta(days=1)
if adapter.needs_full_listings and stale:
    adapter.sync(full_listing=True)

Some servers answer a sync token they no longer accept with fewer changes, instead of refusing it. needs_full_listings is True for those, and a regular full listing repairs what an incremental sync missed, at little cost, as Adapters explains. Server compatibility lists which tested servers need it.

Move from python-caldav’s own sync#

python-caldav’s sync() keeps the sync token only on the Python object, so a new process starts over unless you save the token yourself, and it stores nothing it returns. The adapter keeps the token, a copy of every object, and the change feed in the store, and sends your edits too. Replace the sync() call with adapter.sync(), and read what changed from the feed instead of the two lists sync() returned, as Read the change feed shows.

Last updated on 2026-10-27.