Connect Google Calendar with Notion
Implementation Guide
Overview: Connecting Google Calendar and Notion
Knowledge workers and operations teams who use Notion as their primary workspace often need calendar context surfaced directly within their project databases, meeting note repositories, and weekly planning dashboards. Google Calendar is the dominant scheduling infrastructure in most organizations, but its events live in temporal isolation—rich context about attendees, agendas, and linked project work exists in Notion, while the canonical record of when and with whom those conversations happen lives in Google Calendar. The Google Calendar-to-Notion integration closes this gap by automatically creating and maintaining Notion database pages that correspond to calendar events, enabling teams to build meeting intelligence systems, automated retrospective logs, and OKR-aligned scheduling dashboards without manual data entry.
This guide covers the technical implementation using Make (formerly Integromat) as the primary iPaaS layer, with detailed treatment of Google Calendar's push notification (webhook) system, the Notion API's database page creation and property update endpoints, and the specific data transformations required to map Calendar event objects to Notion's typed property schema.
Core Prerequisites
For Google Calendar, you need a Google account with access to the target calendar and the ability to manage Google Cloud projects. Enable the Google Calendar API in the Google Cloud Console under APIs & Services > Library. Create OAuth 2.0 credentials (Client ID and Client Secret) for a Web Application, setting the authorized redirect URI to your Make OAuth callback URL: https://www.make.com/oauth/cb/google. The required OAuth 2.0 scopes are https://www.googleapis.com/auth/calendar.readonly for read-only event access, or https://www.googleapis.com/auth/calendar if you intend to write back to Calendar (e.g., to add a Notion page URL to the event description). For service account–based implementations (recommended for organization-wide calendar monitoring), create a Service Account in the Google Cloud Console, download the JSON key file, and grant the service account domain-wide delegation with the calendar scope in Google Workspace Admin > Security > API Controls.
For the Notion API, create an internal integration at developers.notion.com. Note the Integration Token (prefixed with secret_). The integration must be granted access to the specific Notion database you intend to write to. Navigate to the target Notion database, click the ... menu, go to Connections, and add your integration. The Notion API requires the integration to have the "Insert content" and "Read content" capabilities. The database_id of the target database is found in the database's URL: https://www.notion.so/[workspace]/[database_id]?v=[view_id]. The database ID is the 32-character hex string before the ?.
Your Notion database must have the following property types configured to receive Calendar event data: a Title property (type: title) for the event name, a Date property (type: date) that supports start and end datetime for the event time range, a Multi-select or Relation property for attendees, a URL property for the Google Meet or conferencing link, and a Select property for event status (Confirmed, Tentative, Cancelled).
Top Enterprise Use Cases
The canonical use case is a Notion-based meeting log. Every meeting on a designated calendar (e.g., a team calendar or a personal calendar filtered by specific event types) automatically generates a Notion page in a "Meetings" database. The page is pre-populated with the meeting title, participants, time, video link, and a linked template for meeting notes and action items. This eliminates the manual process of creating meeting note documents and ensures every scheduled conversation has a corresponding knowledge artifact.
A second use case is OKR and project alignment dashboards. When events are tagged with a specific naming convention or calendar color in Google Calendar (e.g., events prefixed with [Q2-OKR-3]), the integration creates Notion pages that are automatically related to the corresponding OKR or project record in a Notion database, giving teams a time-based view of effort allocation against strategic priorities.
A third use case is automated retrospective capture. At the end of each sprint, a recurring Google Calendar event triggers the creation of a structured Notion retrospective page with pre-filled sections for "What went well," "What didn't go well," and "Action items," linked to the current sprint database record. This ensures retrospective documentation is never skipped due to meeting prep overhead.
Step-by-Step Implementation Guide
Configuring Google Calendar Polling or Push Notifications in Make
Make provides a native Google Calendar module that supports both scheduled polling and push notifications. For near-real-time sync (under 2 minutes latency), use the Google Calendar > Watch Events trigger module, which uses Google's Calendar Push Notification API (also known as the Channel Watch API) under the hood. When activated, Make registers a webhook channel with Google Calendar by calling the POST https://www.googleapis.com/calendar/v3/calendars/CALENDAR_ID/events/watch endpoint with a payload like:
{
"id": "make-channel-unique-id-12345",
"type": "web_hook",
"address": "https://hook.eu1.make.com/YOUR_MAKE_WEBHOOK_ID",
"token": "optional-state-token",
"expiration": 1735689600000
}
Google Calendar push notification channels expire after a maximum of 7 days (604,800 seconds). Make automatically handles channel renewal by re-registering before expiration. If you are implementing this outside of Make using the Google Calendar API directly, you must build a channel renewal mechanism into your application.
The Google Calendar event object delivered via push notification does not include full event details—it is a lightweight notification indicating that the calendar has changed. Your application must then make a follow-up call to the Events API to fetch the updated event. The full event object structure is:
{
"kind": "calendar#event",
"id": "abc123xyz789",
"summary": "Q2 Planning Session",
"description": "Agenda: Review OKRs, finalize sprint backlog",
"location": "Conference Room B",
"status": "confirmed",
"start": {
"dateTime": "2024-04-15T14:00:00-07:00",
"timeZone": "America/Los_Angeles"
},
"end": {
"dateTime": "2024-04-15T15:30:00-07:00",
"timeZone": "America/Los_Angeles"
},
"attendees": [
{
"email": "[email protected]",
"displayName": "Alice Chen",
"responseStatus": "accepted"
},
{
"email": "[email protected]",
"displayName": "Bob Patel",
"responseStatus": "tentative"
}
],
"conferenceData": {
"entryPoints": [
{
"entryPointType": "video",
"uri": "https://meet.google.com/xyz-abcd-efg",
"label": "meet.google.com/xyz-abcd-efg"
}
]
},
"creator": {
"email": "[email protected]"
},
"organizer": {
"email": "[email protected]"
},
"created": "2024-04-01T09:00:00.000Z",
"updated": "2024-04-10T11:30:00.000Z"
}
Creating a Notion Database Page
To create a Notion database page, use the Notion API's page creation endpoint: POST https://api.notion.com/v1/pages. The request must include the Authorization: Bearer secret_YOUR_INTEGRATION_TOKEN header, Notion-Version: 2022-06-28 header, and Content-Type: application/json. The body must specify the parent (your database ID) and properties matching your database schema.
A complete Notion page creation payload mapped from the Google Calendar event object above is:
{
"parent": {
"database_id": "YOUR_32_CHAR_DATABASE_ID"
},
"properties": {
"Name": {
"title": [
{
"type": "text",
"text": {
"content": "Q2 Planning Session"
}
}
]
},
"Date": {
"date": {
"start": "2024-04-15T14:00:00-07:00",
"end": "2024-04-15T15:30:00-07:00",
"time_zone": "America/Los_Angeles"
}
},
"Status": {
"select": {
"name": "Confirmed"
}
},
"Meet Link": {
"url": "https://meet.google.com/xyz-abcd-efg"
},
"Google Event ID": {
"rich_text": [
{
"type": "text",
"text": {
"content": "abc123xyz789"
}
}
]
}
},
"children": [
{
"object": "block",
"type": "heading_2",
"heading_2": {
"rich_text": [
{
"type": "text",
"text": {
"content": "Agenda"
}
}
]
}
},
{
"object": "block",
"type": "paragraph",
"paragraph": {
"rich_text": [
{
"type": "text",
"text": {
"content": "Review OKRs, finalize sprint backlog"
}
}
]
}
},
{
"object": "block",
"type": "heading_2",
"heading_2": {
"rich_text": [
{
"type": "text",
"text": {
"content": "Action Items"
}
}
]
}
}
]
}
The Google Event ID property stored as rich text is essential for the update and deduplication logic. When a calendar event is updated, your integration must first query the Notion database for an existing page with a matching Google Event ID value before deciding whether to create a new page or update an existing one. Use the Notion Database Query endpoint: POST https://api.notion.com/v1/databases/DATABASE_ID/query with a filter:
{
"filter": {
"property": "Google Event ID",
"rich_text": {
"equals": "abc123xyz789"
}
}
}
If the query returns results, use the PATCH https://api.notion.com/v1/pages/PAGE_ID endpoint to update the existing page's properties. If no results are returned, proceed with the POST /v1/pages creation flow.
Handling Event Cancellation
When Google Calendar fires a push notification for a cancelled event (where the event's status field equals cancelled), your integration should update the corresponding Notion page's Status property to "Cancelled" rather than deleting the page. Deleting Notion pages via the API requires archiving (setting archived: true on the PATCH request), which removes the page from views but retains it in Notion's trash. For most operational use cases, updating the Status to "Cancelled" is preferable to archiving, as it preserves the page in filtered database views for audit purposes.
Common Pitfalls & Troubleshooting
A 400 Bad Request from the Notion API during page creation most commonly results from a property name mismatch. Notion property names in the API are case-sensitive and must exactly match the column names in your database, including spaces and special characters. If your Notion database has a property named "Meet Link" but your payload uses "Meet link" (lowercase l), the API will return a 400 error. Use the Notion database schema retrieval endpoint (GET https://api.notion.com/v1/databases/DATABASE_ID) to fetch the exact property names and types before building your payload.
A 401 Unauthorized from the Notion API indicates an invalid or expired integration token. Notion integration tokens do not expire by default, so a 401 typically means the integration has been disconnected from the database (a workspace admin removed the connection) or the token was revoked and regenerated. Verify the integration connection in the Notion database settings.
Google Calendar push notifications may stop delivering if your Make webhook URL returns non-200 responses for an extended period. Google will silently stop sending notifications after repeated delivery failures without disabling the channel. Monitor the channel expiration and re-registration process. If you suspect a channel has gone stale, use the Google Calendar Channels API to stop the channel: POST https://www.googleapis.com/calendar/v3/channels/stop and then re-register.
The Notion API enforces a rate limit of 3 requests per second per integration token. If your calendar has a high volume of events (e.g., bulk imports or calendar migrations), you will encounter 429 Too Many Requests responses from Notion. The Notion API returns a Retry-After header. In Make, use the Error Handler module to catch 429 errors and add a Sleep module for the specified duration before retrying.