DEV Community

Pirate Prentice
Pirate Prentice

Posted on

n8n Google Calendar Node: Sync Events, Build Booking Workflows, and Automate Scheduling (Free Workflow JSON)

Google Calendar is the scheduling backbone for millions of teams. The n8n Google Calendar node lets you create, update, delete, and query events — and respond to new bookings in real time with the Calendar Trigger. This guide covers every operation, the gotchas that catch new users, and three production patterns you can deploy today.


Prerequisites

  • n8n (self-hosted or cloud)
  • A Google account with Calendar enabled
  • Google Calendar OAuth2 credentials in n8n

Setting up OAuth2:

  1. Go to console.cloud.google.com → Create or select a project
  2. Enable the Google Calendar API
  3. Create OAuth 2.0 Client ID (Application type: Web application)
  4. Add your n8n callback URL as an authorized redirect URI: https://your-n8n-domain/rest/oauth2-credential/callback
  5. In n8n: Credentials → New → Google Calendar OAuth2 API → paste Client ID and Secret → connect

Operations at a Glance

Operation What It Does
Event: Create Create a new calendar event
Event: Delete Delete an event by ID
Event: Get Fetch a single event by ID
Event: Get Many List events with filters (time range, query, max results)
Event: Patch Update specific fields on an existing event (partial update)
Event: Update Full replace of an event
Calendar: Get Many List all calendars the account has access to
Calendar Trigger Fire a workflow when a new event is created or updated

Key Parameters

Event: Create / Update

  • Calendar — the calendar to write to (primary, or any calendar ID)
  • Start / End — ISO 8601 datetime strings; for all-day events use date-only format (2026-07-19)
  • Timezone — always set explicitly; omitting it can cause silent UTC-offset bugs
  • Summary — event title
  • Description — event body (HTML supported in most clients)
  • Location — plain text or address
  • Attendees — array of email addresses; Google sends invitations automatically
  • Send Updatesall sends email invitations; none creates the event silently
  • Recurrence — RRULE string (e.g., RRULE:FREQ=WEEKLY;COUNT=4)
  • Color ID — 1–11 for Google's color palette
  • Reminders — override default reminders with popup/email at N minutes before

Event: Get Many

  • Time Min / Time Max — filter by date range (ISO 8601 with timezone offset)
  • Query — full-text search across title, description, location
  • Max Results — up to 2500 per page; combine with Single Value (Return All) for pagination
  • Order BystartTime (ascending only when timeMin is set) or updated

Calendar Trigger

  • Trigger On — Event Created or Event Updated
  • Poll Times — how often n8n checks for new events (minimum 1 minute)

Six Gotchas

1. All-day events break with datetime format.
All-day events require date-only format (2026-07-19), not datetime (2026-07-19T00:00:00Z). Passing a datetime string creates a timed event, not an all-day event.

2. Attendees trigger email invitations by default.
Adding attendees with Send Updates: all fires real Google Calendar invitations immediately. Use Send Updates: none to create events silently during testing or internal workflows.

3. Timezone must be explicit or events shift.
If you omit timezone on create, Google Calendar inherits the calendar's default timezone — which may not match your user's. Always pass timeZone explicitly, especially for cross-timezone teams.

4. Calendar Trigger polls, not pushes.
Unlike webhooks, the Calendar Trigger polls the Google Calendar API on a schedule. Minimum poll interval is 1 minute; you won't get sub-minute latency. For faster response, use a Google Forms → Apps Script → HTTP Request → n8n webhook chain.

5. Get Many requires timeMin for startTime ordering.
Order By: startTime only works when timeMin is set. Without it, the API returns an error. Use Order By: updated when you don't have a time filter.

6. Recurring event instances are separate events.
Querying recurring events returns each instance as a separate event. The recurringEventId field links them to the parent. To update all instances of a series, use the recurringEventId as the event ID with Patch.


Three Production Patterns

Pattern 1: Typeform Booking → Google Calendar Event + Confirmation Email

Use case: A Typeform form collects meeting requests. Automatically create a Google Calendar event and send a confirmation email via Gmail.

Workflow:

  1. Typeform Trigger → fires on new submission
  2. Google Calendar: Event Create → create event with attendees = {{ $json.email }}, summary = "Meeting with {{ $json.name }}", start/end from form fields, Send Updates: none (control confirmation email yourself)
  3. Gmail: Send Email → send a branded confirmation with the event time, Google Meet link (if added to the event), and calendar link from the response's htmlLink field
  4. Google Sheets: Append Row → log booking to a sheet for CRM/reporting

Free workflow JSON: [Download below]


Pattern 2: Daily Agenda Digest → Slack

Use case: Every morning at 8 AM, pull today's calendar events and post a digest to a Slack channel.

Workflow:

  1. Schedule Trigger0 8 * * 1-5 (weekdays at 8 AM, your timezone)
  2. Google Calendar: Event Get ManytimeMin: {{ $now.startOf('day').toISO() }}, timeMax: {{ $now.endOf('day').toISO() }}, Return All: true
  3. Code node → format events into a Slack-friendly block:
   const events = $input.all();
   if (events.length === 0) return [{ json: { text: "No events today." } }];
   const lines = events.map(e => {
     const start = new Date(e.json.start.dateTime || e.json.start.date);
     const time = e.json.start.dateTime 
       ? start.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', timeZone: 'America/Chicago' })
       : 'All day';
     return `• ${time}${e.json.summary}`;
   });
   return [{ json: { text: `*Today's agenda:*\n${lines.join('\n')}` } }];
Enter fullscreen mode Exit fullscreen mode
  1. Slack: Send Message → post to #standup or a personal DM channel

Pattern 3: Stripe Payment → Client Onboarding Calendar Event

Use case: When a customer pays via Stripe, automatically schedule an onboarding call on your calendar and send them a calendar invite.

Workflow:

  1. Webhook → receives Stripe checkout.session.completed event (or use Stripe Trigger node)
  2. Set node → extract customer_email, customer_name from Stripe payload
  3. Google Calendar: Event Create:
    • Calendar: your primary calendar
    • Summary: "Onboarding Call — {{ $json.customer_name }}"
    • Start: {{ $now.plus({ days: 2 }).set({ hour: 14, minute: 0 }).toISO() }} (2 days from now at 2 PM)
    • End: {{ $now.plus({ days: 2 }).set({ hour: 15, minute: 0 }).toISO() }}
    • Attendees: {{ $json.customer_email }}
    • Send Updates: all (fires Google's invitation email)
    • Description: "Welcome to [Your Service]! Here are your onboarding resources: [link]"
  4. Gmail: Send Email → follow-up with a personalized welcome email including the calendar link

Free Workflow JSON

{
  "name": "Google Calendar — Typeform Booking + Confirmation",
  "nodes": [
    {
      "parameters": { "formId": "YOUR_TYPEFORM_ID" },
      "name": "Typeform Trigger",
      "type": "n8n-nodes-base.typeformTrigger",
      "position": [250, 300]
    },
    {
      "parameters": {
        "resource": "event",
        "operation": "create",
        "calendarId": "primary",
        "summary": "={{ $json.meeting_topic }}",
        "startTime": "={{ $json.preferred_date }}T{{ $json.preferred_time }}:00",
        "endTime": "={{ $json.preferred_date }}T{{ $json.preferred_time_end }}:00",
        "additionalFields": {
          "attendees": "={{ $json.email }}",
          "sendUpdates": "none",
          "timeZone": "America/Chicago"
        }
      },
      "name": "Create Calendar Event",
      "type": "n8n-nodes-base.googleCalendar",
      "position": [450, 300]
    },
    {
      "parameters": {
        "fromEmail": "you@yourdomain.com",
        "toEmail": "={{ $('Typeform Trigger').item.json.email }}",
        "subject": "Your meeting is confirmed — {{ $('Typeform Trigger').item.json.meeting_topic }}",
        "message": "Hi {{ $('Typeform Trigger').item.json.name }},\n\nYour meeting has been added to your calendar: {{ $json.htmlLink }}\n\nSee you then!"
      },
      "name": "Send Confirmation Email",
      "type": "n8n-nodes-base.gmail",
      "position": [650, 300]
    }
  ],
  "connections": {
    "Typeform Trigger": { "main": [[{ "node": "Create Calendar Event", "type": "main", "index": 0 }]] },
    "Create Calendar Event": { "main": [[{ "node": "Send Confirmation Email", "type": "main", "index": 0 }]] }
  }
}
Enter fullscreen mode Exit fullscreen mode

Import this JSON in n8n: Workflows → Import from file / clipboard. Update the Typeform form ID, your email, timezone, and field mappings.


Google Calendar Node vs. HTTP Request Node

Google Calendar Node HTTP Request (Google Calendar API)
Auth Managed OAuth2 in n8n OAuth2 token you manage
Operations Common CRUD + Trigger Full API surface (ACLs, settings, freebusy)
Pagination Return All handles it You implement nextPageToken loop
Best for Standard scheduling automations Advanced queries, ACL management

For most scheduling workflows, the Google Calendar node is the right choice. Drop to the HTTP Request node only when you need endpoints the node doesn't expose (free/busy queries, calendar ACL management, push notification channels).


Summary

The Google Calendar node is the fastest way to add scheduling automation to any n8n workflow. Three things to remember: always pass timezone explicitly, use Send Updates: none during testing, and use the Calendar Trigger for event-driven flows (accepting the 1-minute poll latency).

Want someone to build this workflow for you? Done-For-You n8n Workflow Build — $99 — describe your use case and get a production-ready workflow delivered within 48 hours.

Looking for reusable n8n workflow templates? n8n Workflow Pack — $29 — plug-and-play JSON files for common automations.

Top comments (0)