This integration is for self-hosted Cognee deployments — you create and own the Google Cloud OAuth client. It is the server-side, multi-user counterpart to calling
google_calendar_source() from Python yourself: the same connector runs underneath, but Cognee holds the OAuth credential instead of a local token file.v1.6.5. See the changelog.
What It Does
- One Google account, one Cognee user. Whoever completes the consent owns the credential, and the account’s events are indexed into that user’s memory. Personal and Workspace accounts take the same path and are told apart by the hosted-domain claim (
account_type: workspaceorpersonal). - Read-only. The requested scopes are
openid email https://www.googleapis.com/auth/calendar.readonly— Cognee never creates, changes or deletes events. - Its own grant. Like Google Drive and Gmail, Google Calendar is a separate provider with its own settings and its own consent, so disconnecting one never revokes the others.
- Opt-in by calendar. A new connection selects nothing, and there is no “all calendars” selection. No events are read until you choose calendars explicitly and start a sync.
- Incremental and deletion-aware. Each calendar keeps its own sync token; later syncs fetch only what changed, and deleted events — as well as every event of a calendar you deselect — are forgotten.
Prerequisites
-
A Cognee backend on
v1.6.5or later. -
The
google-calendarextra installed on that backend:It pulls ingoogle-api-python-client,google-authandgoogle-auth-oauthlib, which the sync builds its Calendar client with. - A Google Cloud project with the Google Calendar API enabled.
Setup
1. Create the Google Cloud OAuth client
In the Google Cloud Console, enable the Google Calendar API, then:2. Configure Cognee
Add the client’s values to your backend’s.env (the same block is in .env.template):
The SDK connector reads the same
GOOGLE_CALENDAR_* prefix for local use (GOOGLE_CALENDAR_IDS, GOOGLE_CALENDAR_REFRESH_TOKEN and the other fields listed on the connector page). Hosted syncs never use those fields: a connected account syncs only the calendars its user selected, never a server-wide GOOGLE_CALENDAR_IDS list.
Stored tokens are encrypted with the integrations framework’s credential key, the same INTEGRATION_CREDENTIALS_KEY (or INTEGRATION_CREDENTIALS_KEYS keyring) described on the Google Drive page.
The settings are checked when they are used, not at startup, so a backend without them still boots. POST /authorize answers 503 (google_calendar integration is not configured on this server.) until they are set. Restart the backend after changing .env.
3. Connect
/authorize, within 10 minutes, and read the result from the redirect to <GOOGLE_CALENDAR_FRONTEND_BASE_URL>/integrations?google_calendar=<outcome>. The outcomes (connected, cancelled, error_invalid_state, error_already_connected, error_exchange_failed) and the split-domain cookie caveat are described under Google Drive → Connect.
Calendar selection is driven through the API calls below.
Choosing Calendars
List the account’s calendars:id, its name (your own name for the calendar if you set one, otherwise its title), its description, and attributes with primary (whether it is the account’s primary calendar) and access_role (Google’s access role for the account, e.g. owner or reader). Persist a selection with PUT:
null is refused with 422 (google_calendar needs an explicit list of resource ids; null is not supported): the connector reads a missing selection as the primary calendar or the server’s GOOGLE_CALENDAR_IDS, so “all calendars” has no safe meaning per user. A blank or whitespace-only id is refused with 422 as well (Resource ids must not be blank or whitespace only). Duplicate ids are stored once.
Narrowing the selection deletes data. The next sync forgets every event of a calendar you dropped from resourceIds, from the graph, vector and relational stores alike. Setting the selection to [] and syncing clears everything the account has indexed; so does disconnecting with delete_data=true. A sync in which every calendar fails forgets nothing, but once any selected calendar finishes, the dropped calendars are forgotten even if another calendar failed.
Syncing and Status
Connecting does not start a sync. Start one after choosing calendars:google_calendar_source() handed to remember() with write_disposition="merge", primary_key="id" and no row cap, so a re-sync updates events instead of duplicating them. It runs with self_improvement=False, so no whole-graph improve() pass fires on each refresh. Each event becomes one document with the calendar name, organizer and attendees written in, so the same person is linked across meetings.
- Only the first sync reads each calendar in full. The connector keeps one sync token per selected calendar; later syncs ask Google only for what changed. A calendar whose token has expired is listed again in full and reconciled against what was stored. Adding a calendar to the selection backfills just that calendar.
- Deletions are forgotten. A deleted event is removed from memory on the next sync. A calendar that was synced before and has since left the account’s calendar list (deleted or no longer shared) has its events forgotten too.
- One failing calendar doesn’t block the others. When one calendar fails, the others still finish and save their sync tokens; the failed one keeps its previous state and is retried on the next sync. An authentication error or a rate limit ends the whole run, since the remaining calendars would fail the same way.
- One sync per account at a time. While a sync is running, another
/synccall returns{"accepted": false}and does nothing. The guard lives in the API process, so a deployment with several workers needs its own queue or lock. - Nothing refreshes on its own. There are no Calendar webhooks and no built-in scheduler. Call
/syncagain, or from your own scheduler, to pick up new events.
google_calendar_<email-slug>_<hash>. The slug is built the same way as for Google Drive datasets; the hash is the first 10 hex characters of the SHA-256 of the Google account id.
GET /api/v1/integrations/google_calendar/connection returns the same fields as the Drive connection state: connected, accountLabel, datasetId, storedItems, syncStatus (ok, degraded, syncing), lastSyncedAt and syncCounts. Calendar’s syncCounts carry scanned, skipped (workingLocation events, which are not ingested), failed, deleted and calendars (how many calendars finished), plus failed_auth, failed_rate_limit, failed_calendar_sync and failed_ingestion when something failed.
Reconnecting an account keeps its stored calendar selection. Only a first-time connection starts with [].
The repository’s examples/guides/google_integration_sync.py drives these calls for you once an account is connected:
Token Lifecycle and Disconnect
Tokens are handled exactly as for Google Drive: the access token is refreshed 5 minutes before it expires, and aninvalid_grant on refresh (access revoked at myaccount.google.com/permissions) revokes the connection locally so it stops reading as connected.
google_calendar disconnected, but its data could not be deleted). The connection is already gone at that point.
Limitations
- No “all calendars” selection. List the calendars you want explicitly; a calendar added to the account later is not picked up until you add it to the selection.
- No automatic refresh.
/syncis the only thing that updates memory. - One Cognee user per Google account. Connecting an account that another user already holds is refused with
error_already_connected. - Attachments and conference details beyond the meeting link are not ingested.
calendar.readonlyis a sensitive scope, so public distribution needs Google’s OAuth verification.
Related
Gmail
The sibling Google OAuth integration for mailboxes, selected by label.
Google Drive
The sibling Google OAuth integration for files, with the same connect flow, status fields and token handling.
Calendar from Python
Call
google_calendar_source() directly with your own OAuth token, without the integrations API.