Google Calendar Module
Run a workflow for every event created, changed or canceled in a Google calendar, or before an event starts, and find, create, update and delete events, answer invitations, list calendars and find free time from any flow.
The Google Calendar Module adds one Start event on its own Channel, the Google Calendar Start (GoogleCalendar), and two Tasks that work on any Channel. Typical uses: send a WhatsApp reminder 30 minutes before every meeting; create a CRM record for every interview booked in the team calendar; offer the next free slots in a chat flow and book the one the visitor picks.
Requirements
- A Google account connects the Module. The flows see every calendar that account sees; writing events needs write access to the calendar.
- The platform needs a Google Cloud OAuth client with the Calendar API enabled (an administrator sets
GoogleCalendarModule:OAuth:ClientId/ClientSecret). The calendar permissions are sensitive scopes: a production client needs Google's verification.
Configuration
The Google Calendar Module is configured per Environment, so Development and Production can use different accounts or calendars.
| Field | Type | Required | Description |
|---|---|---|---|
| Google account | button | Yes | Connect Google Calendar signs in with Google. Workspace owners and admins only. The sign-in is stored encrypted on the engine and never shown. The field also shows which calendars are watched. Disconnect revokes the sign-in and stops the trigger. |
| Default calendar | string | No | The calendar the Start watches and the Tasks use when they leave their Calendar empty: primary (the account's own calendar), a calendar id (…@group.calendar.google.com) or the address a calendar is shared from. Default: primary. |
| Default time zone | string | No | Advanced. IANA time zone (e.g. Europe/Rome) for local times and for times written without an offset. Tasks can override it. Default: the event's own zone, else the account's. |
| Check for changes every (minutes) | number | No | Advanced. How often the engine asks Google for changes in the watched calendars, 1 to 60. Default: 2. |
Google has no reliable push for third-party servers, so the trigger checks the calendars on this interval: a change starts the flow within that time.
Google Calendar Start
Starts the Process when one of the ticked things happens in the watched calendars. When you deploy, the engine checks that the connected account can read every watched calendar and begins watching them; nothing that already existed is reported. A deploy without a Google connection is refused. Deploying a version without the Start stops the watching.
| Field | Type | Default | Description |
|---|---|---|---|
| Event created | boolean | on | A new event appears (also events the flows themselves create; see Skip events the connected account created). |
| Event changed | boolean | off | An existing event is edited: time, title, attendees, an attendee's answer… |
| Event canceled | boolean | off | An event is deleted or canceled. Only the id, calendar and status of a deleted event are known. |
| Event starting | boolean | off | An event is about to start. Runs once per event, Minutes before start before it. |
| Minutes before start | number | 15 | For Event starting: 1 minute to 7 days. The run may be up to one check interval late. |
| Calendars | string | (default calendar) | Comma-separated calendar ids to watch. |
| Only events whose title contains | string | (all) | Advanced. Comma-separated words, case-insensitive. |
| Skip events the connected account created | boolean | off | Advanced. Use it when the flow creates events in the watched calendar, so it does not run for its own events. |
| Include all-day events | boolean | on | Advanced. Off: birthdays, holidays and other all-day events do not start the flow. |
| Event variable | output | {event} | Receives the event (below). |
When several things are ticked, branch on {event.action} with an Exclusive Gateway. The GoogleCalendar Channel has nobody to answer: an Input Task fails there. To reach the people involved, use an email, SMS or WhatsApp Task with {event.attendeeEmails} or {event.organizer.email}.
A recurring series counts as one event (its first occurrence's time and its recurrence rules) for created, changed and canceled; Event starting runs for each occurrence.
Testing. In the editor's chat, start the Process at the Google Calendar Start with test data, e.g. { "action": "starting", "title": "Interview", "start": "2026-11-03T09:00:00Z", "attendees": "ada@example.com", "minutesUntilStart": 15 }. Without test data a sample event is used. {event.isTest} is true.
The {event} variable
| Path | Example | Description |
|---|---|---|
{event.action} | created | created, updated, canceled or starting. |
{event.minutesUntilStart} | 15 | For starting: minutes until the event begins. |
{event.id}, {event.calendarId} | abc123, primary | The event and its calendar (pass them to the events Task). |
{event.title}, {event.description}, {event.location} | Demo call | The event's text. |
{event.status} | confirmed | confirmed, tentative or cancelled. |
{event.start}, {event.end} | 2026-11-03T10:00:00+01:00 | As Google gives them: with the event's offset, or a plain date for an all-day event. |
{event.startUtc}, {event.endUtc} | 2026-11-03T09:00:00Z | UTC. |
{event.startLocal}, {event.endLocal} | 2026-11-03T10:00:00+01:00 | In the Environment's default time zone (else the event's). |
{event.allDay}, {event.durationMinutes}, {event.timeZone} | false, 30, Europe/Rome | |
{event.organizer.email}, {event.organizer.name}, {event.organizer.self} | The organizer (also {event.from}); self is true for the connected account. {event.creator} has the same fields. | |
{event.attendees.0.email}, .name, .responseStatus, .optional, .self | Each attendee; responseStatus is accepted, declined, tentative or needsAction. | |
{event.attendeeEmails} | a@x.test, b@x.test | Every attendee's email, comma-separated. |
{event.myResponse} | accepted | The connected account's own answer, empty when not invited. |
{event.meetLink}, {event.htmlLink} | https://meet.google.com/… | The Google Meet link and the event's page. |
{event.recurring}, {event.recurringEventId}, {event.recurrence.0} | true, …, RRULE:FREQ=WEEKLY | Repetition. |
{event.visibility}, {event.transparency}, {event.colorId} | default, opaque, 5 | |
{event.created}, {event.updated}, {event.iCalUid} | ||
{event.channel}, {event.isTest} | GoogleCalendar, false |
Google Calendar events
Works with events in one calendar. Times are ISO-8601 with an offset, a local time read in the Task's time zone (2026-11-03T10:00), or a plain date (2026-11-03) for an all-day event.
| Field | Type | Operations | Description |
|---|---|---|---|
| Operation | select | Find events, Get event, Create event, Update event, Delete event, Quick add, Respond to invitation. | |
| Calendar | string | all | primary, a calendar id or a shared calendar's address. Empty: the Environment's default calendar. |
| Event id | string | Get, Update, Delete, Respond | e.g. {event.id} or {created.id}. |
| From, Until | date | Find | The period. Empty: now, and 30 days after From. |
| Containing | string | Find | Only events whose text or attendees contain it. |
| Max results | number | Find | 1–250, soonest first. Default 20. |
| Expand recurring events | boolean | Find | Advanced. On: each occurrence; off: the series once. |
| Title | string | Create, Update | |
| Text | string | Quick add | Plain text Google turns into an event: Lunch with Ada tomorrow at 1pm at Café Roma. |
| Start, End | date | Create, Update | End empty: Start plus Duration (default 30 minutes). For an all-day event End is its last day. On Update, a moved Start keeps the event's length. |
| Duration (minutes) | number | Create, Update | Advanced. Used when End is empty. |
| Description, Location | string | Create, Update | |
| Attendees | string | Create, Update | Comma-separated emails. On Update, replaces the list when filled. |
| Add a Google Meet link | boolean | Create | |
| Email the attendees | select | Create, Update, Delete | Everyone, guests outside the organization, or nobody. |
| Reminders (minutes before) | string | Create, Update | Advanced. Comma-separated minutes for popup reminders, at most 5. |
| Repeat | string | Create, Update | Advanced. iCalendar rules, one per line (RRULE:FREQ=WEEKLY;COUNT=10). |
| Visibility, Show as, Color | select / string | Create, Update | Advanced. |
| Answer, Note | select, string | Respond | Accept, Decline or Maybe, with a comment the organizer sees. The connected account must be invited. |
| Time zone | string | all | Advanced. Overrides the Environment's default. |
Outputs: Save events as ({events.count}, {events.items.0.title}…), Save event as ({calendarEvent}: the same fields as {event} above, without action), Save result as ({deleted.deleted}, {deleted.id}).
Google Calendar availability
| Field | Type | Operations | Description |
|---|---|---|---|
| Operation | select | List calendars, Busy times, Find free slots. | |
| Calendars | string | Busy, Slots | Comma-separated calendar ids whose busy times count, at most 50: the account's calendars, or colleagues' addresses whose free/busy is visible. Empty: the default calendar. |
| From, Until | date | Busy, Slots | The period, at most 60 days. Empty: now, and 7 days after From. |
| Slot length (minutes) | number | Slots | 5–480. Default 30. |
| Working hours | string | Slots | 09:00-18:00, local to the Task's time zone. Empty: any hour. |
| Working days | string | Slots | Advanced. Mon, Tue, Wed, Thu, Fri. Empty: every day. |
| Step (minutes) | number | Slots | Advanced. Slots start every this many minutes. Default: the slot length. |
| Max slots | number | Slots | Advanced. 1–100, soonest first. Default 10. |
| Time zone | string | all | Advanced. |
Outputs: Save calendars as ({calendars.items.0.id}, .name, .primary, .accessRole, .timeZone), Save busy times as ({busy.items.0.start}, .end, .startLocal, .calendarId; {busy.unreadable} lists calendars Google could not read), Save slots as ({slots.count}, {slots.items.0.start}, .startLocal, .end, and {slots.text}: Tue 3 Nov 09:00, Tue 3 Nov 09:30, … for a message).
A typical booking flow: Find free slots → Output {slots.text} → Input the choice → Create event with Start={slots.items.N.start} and the visitor's email as attendee, Add a Google Meet link on.
Errors
| Situation | What the Task reports |
|---|---|
| Not connected, or the sign-in was revoked | ModuleMissingConfiguration: connect (or reconnect) in the Environment's Google Calendar settings. |
| A field is wrong (a date that does not read, an email that is not one, End before Start) | TaskInvalidData, before any call to Google. |
| Google refused (no access to the calendar, unknown event, rate limit) | ModuleException with Google's own message. |
The trigger logs at the engine: an environment whose connection needs reconnecting is skipped on every check until reconnected.