This workflow corresponds to n8n.io template #12081 — we link there as the canonical source.
This workflow follows the Error Trigger → Gmail recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"meta": {
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "0cc24318-7afd-4185-82d0-8ad18aee3d27",
"name": "New Event Trigger",
"type": "n8n-nodes-base.googleCalendarTrigger",
"position": [
-2608,
-608
],
"parameters": {
"options": {},
"pollTimes": {
"item": [
{
"mode": "everyMinute"
}
]
},
"triggerOn": "eventCreated",
"calendarId": {
"__rl": true,
"mode": "list",
"value": "primary"
}
},
"typeVersion": 1
},
{
"id": "2e7415e5-98bf-48c9-b221-b88bcd420653",
"name": "Updated Event Trigger",
"type": "n8n-nodes-base.googleCalendarTrigger",
"position": [
-2608,
-400
],
"parameters": {
"options": {},
"pollTimes": {
"item": [
{
"mode": "everyMinute"
}
]
},
"triggerOn": "eventUpdated",
"calendarId": {
"__rl": true,
"mode": "list",
"value": "primary"
}
},
"typeVersion": 1
},
{
"id": "a55feb7c-f8ce-4e25-aa7c-6e83acc73081",
"name": "Daily Summary Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-2608,
96
],
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 8 * * *"
}
]
}
},
"typeVersion": 1.1
},
{
"id": "f4b8ba3b-55eb-4145-80b0-c83871d61d5b",
"name": "Process Event",
"type": "n8n-nodes-base.code",
"position": [
-2304,
-496
],
"parameters": {
"jsCode": "const event = $json;\n\n// Basic data\nconst eventId = event.id || '';\nconst summary = event.summary || 'Untitled';\nconst description = event.description || '';\nconst status = event.status || 'confirmed';\nconst creator = event.creator?.email || '';\nconst organizer = event.organizer?.email || '';\n\n// Attendees\nconst attendees = event.attendees || [];\nconst attendeeCount = attendees.length;\nconst attendeeEmails = attendees.map(a => a.email).join(', ');\nconst acceptedCount = attendees.filter(a => a.responseStatus === 'accepted').length;\nconst declinedCount = attendees.filter(a => a.responseStatus === 'declined').length;\nconst pendingCount = attendees.filter(a => a.responseStatus === 'needsAction' || a.responseStatus === 'tentative').length;\n\n// Dates\nconst startDateTime = event.start?.dateTime || event.start?.date;\nconst endDateTime = event.end?.dateTime || event.end?.date;\nconst isAllDay = !event.start?.dateTime;\n\n// Format dates\nlet formattedDate = '';\nlet startTime = '';\nlet endTime = '';\nlet dayOfWeek = '';\n\nif (startDateTime) {\n const startDate = new Date(startDateTime);\n formattedDate = startDate.toLocaleDateString('en-US', {\n year: 'numeric',\n month: '2-digit',\n day: '2-digit'\n });\n dayOfWeek = startDate.toLocaleDateString('en-US', { weekday: 'long' });\n startTime = isAllDay ? 'All day' : startDate.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' });\n if (endDateTime && !isAllDay) {\n endTime = new Date(endDateTime).toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' });\n }\n}\n\n// Calculate duration in minutes\nlet durationMinutes = 60;\nlet durationText = '1 hour';\nif (startDateTime && endDateTime && !isAllDay) {\n const start = new Date(startDateTime);\n const end = new Date(endDateTime);\n durationMinutes = Math.round((end - start) / (1000 * 60));\n if (durationMinutes < 60) {\n durationText = `${durationMinutes} min`;\n } else if (durationMinutes === 60) {\n durationText = '1 hour';\n } else {\n const hours = Math.floor(durationMinutes / 60);\n const mins = durationMinutes % 60;\n durationText = mins > 0 ? `${hours}h ${mins}m` : `${hours} hours`;\n }\n}\n\n// Detect video call platform\nlet platform = 'In-person';\nlet meetingLink = '';\nlet location = event.location || '';\n\nif (event.hangoutLink) {\n platform = 'Google Meet';\n meetingLink = event.hangoutLink;\n} else if (event.conferenceData?.entryPoints) {\n const videoEntry = event.conferenceData.entryPoints.find(e => e.entryPointType === 'video');\n if (videoEntry) {\n meetingLink = videoEntry.uri;\n if (meetingLink.includes('zoom.us')) platform = 'Zoom';\n else if (meetingLink.includes('teams.microsoft')) platform = 'Teams';\n else platform = 'Google Meet';\n }\n} else if (location) {\n if (location.includes('zoom.us')) {\n platform = 'Zoom';\n meetingLink = location;\n } else if (location.includes('teams.microsoft')) {\n platform = 'Teams';\n meetingLink = location;\n } else if (location.includes('meet.google')) {\n platform = 'Google Meet';\n meetingLink = location;\n }\n}\n\n// Categorize event type\nlet category = 'General';\nconst titleLower = summary.toLowerCase();\nif (titleLower.includes('meeting') || titleLower.includes('call') || titleLower.includes('sync')) {\n category = 'Meeting';\n} else if (titleLower.includes('1:1') || titleLower.includes('one on one') || titleLower.includes('1-on-1')) {\n category = '1:1';\n} else if (titleLower.includes('interview')) {\n category = 'Interview';\n} else if (titleLower.includes('lunch') || titleLower.includes('coffee') || titleLower.includes('social')) {\n category = 'Social';\n} else if (titleLower.includes('demo') || titleLower.includes('presentation')) {\n category = 'Demo';\n} else if (titleLower.includes('focus') || titleLower.includes('deep work') || titleLower.includes('blocked')) {\n category = 'Focus Time';\n}\n\n// Event status\nconst isCancelled = status === 'cancelled';\nlet statusText = 'Confirmed';\nif (isCancelled) statusText = 'Canceled';\nelse if (status === 'tentative') statusText = 'Tentative';\n\n// Detect if recurring\nconst isRecurring = !!event.recurringEventId;\n\nreturn {\n json: {\n // IDs\n eventId: eventId,\n recurringEventId: event.recurringEventId || '',\n \n // Basic info\n title: summary,\n description: description,\n category: category,\n \n // Dates and time\n date: formattedDate,\n dayOfWeek: dayOfWeek,\n startTime: startTime,\n endTime: endTime,\n durationMinutes: durationMinutes,\n durationText: durationText,\n allDay: isAllDay ? 'Yes' : 'No',\n isRecurring: isRecurring ? 'Yes' : 'No',\n \n // Location\n platform: platform,\n meetingLink: meetingLink,\n location: location,\n \n // Attendees\n organizer: organizer,\n creator: creator,\n attendeeCount: attendeeCount,\n attendees: attendeeEmails,\n accepted: acceptedCount,\n declined: declinedCount,\n pending: pendingCount,\n \n // Status\n status: statusText,\n cancelled: isCancelled,\n \n // Metadata\n syncedAt: new Date().toISOString(),\n syncedAtFormatted: new Date().toLocaleString('en-US')\n }\n};"
},
"typeVersion": 2
},
{
"id": "198eb6e3-6947-4d93-94c8-d331866066f2",
"name": "Is Canceled?",
"type": "n8n-nodes-base.if",
"position": [
-2064,
-496
],
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{ $json.cancelled }}",
"value2": true
}
]
}
},
"typeVersion": 1
},
{
"id": "ca7dc61a-f224-4302-988e-a8b0d5bce949",
"name": "Log Event",
"type": "n8n-nodes-base.googleSheets",
"position": [
-1760,
-608
],
"parameters": {
"columns": {
"value": {
"ID": "={{ $json.eventId }}",
"Day": "={{ $json.dayOfWeek }}",
"Date": "={{ $json.date }}",
"Title": "={{ $json.title }}",
"Status": "={{ $json.status }}",
"Category": "={{ $json.category }}",
"Duration": "={{ $json.durationText }}",
"End Time": "={{ $json.endTime }}",
"Platform": "={{ $json.platform }}",
"Attendees": "={{ $json.attendeeCount }}",
"Synced At": "={{ $json.syncedAtFormatted }}",
"Start Time": "={{ $json.startTime }}",
"Meeting Link": "={{ $json.meetingLink }}"
},
"mappingMode": "defineBelow"
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "Events"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "YOUR_DOCUMENT_ID"
}
},
"typeVersion": 4
},
{
"id": "392f3ba6-9c24-437e-9b20-2cf184318c7d",
"name": "Log Cancellation",
"type": "n8n-nodes-base.googleSheets",
"position": [
-1760,
-400
],
"parameters": {
"columns": {
"value": {
"ID": "={{ $json.eventId }}",
"Title": "={{ $json.title }}",
"Canceled At": "={{ $json.syncedAtFormatted }}",
"Original Date": "={{ $json.date }}",
"Original Time": "={{ $json.startTime }}",
"Affected Attendees": "={{ $json.attendeeCount }}"
},
"mappingMode": "defineBelow"
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "Cancellations"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "YOUR_DOCUMENT_ID"
}
},
"typeVersion": 4
},
{
"id": "3a608d14-fb51-4ec6-abdf-4e76fe80fc66",
"name": "Slack - New Event",
"type": "n8n-nodes-base.slack",
"position": [
-1520,
-608
],
"parameters": {
"text": ":calendar: *New calendar event*",
"otherOptions": {
"includeLinkToWorkflow": false
}
},
"typeVersion": 2
},
{
"id": "c3e63763-51b1-4113-9424-16bebbd9da93",
"name": "Slack - Cancellation",
"type": "n8n-nodes-base.slack",
"position": [
-1520,
-400
],
"parameters": {
"text": ":x: *Event canceled*",
"otherOptions": {
"includeLinkToWorkflow": false
}
},
"typeVersion": 2
},
{
"id": "0718fe64-ce83-4344-a2b7-e7d618825590",
"name": "Has Attendees?",
"type": "n8n-nodes-base.if",
"position": [
-1264,
-608
],
"parameters": {
"conditions": {
"number": [
{
"value1": "={{ $('Process Event').item.json.attendeeCount }}",
"operation": "larger"
}
]
}
},
"typeVersion": 1
},
{
"id": "e5009348-bc88-4675-90e4-a37a916f8052",
"name": "Prepare Confirmation Email",
"type": "n8n-nodes-base.code",
"position": [
-960,
-624
],
"parameters": {
"jsCode": "const data = $('Process Event').first().json;\n\n// Config\nconst CONFIG = {\n companyName: 'Your Company',\n primaryColor: '#4f46e5'\n};\n\nconst emailHtml = `\n<!DOCTYPE html>\n<html>\n<head><meta charset=\"UTF-8\"></head>\n<body style=\"margin:0;padding:0;font-family:'Segoe UI',Arial,sans-serif;background:#f4f7fa;\">\n <table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" style=\"background:#f4f7fa;padding:40px 20px;\">\n <tr><td align=\"center\">\n <table width=\"600\" cellpadding=\"0\" cellspacing=\"0\" style=\"background:#fff;border-radius:12px;box-shadow:0 4px 6px rgba(0,0,0,0.1);\">\n <tr><td style=\"background:${CONFIG.primaryColor};padding:30px;text-align:center;border-radius:12px 12px 0 0;\">\n <h1 style=\"margin:0;color:#fff;font-size:24px;\">Event Scheduled</h1>\n </td></tr>\n <tr><td style=\"padding:30px;\">\n <h2 style=\"margin:0 0 20px;color:#2d3748;\">${data.title}</h2>\n \n <div style=\"background:#f0f4ff;border-radius:8px;padding:20px;margin:20px 0;border-left:4px solid ${CONFIG.primaryColor};\">\n <p style=\"margin:0 0 10px;color:#4338ca;font-size:16px;\">${data.dayOfWeek} ${data.date}</p>\n <p style=\"margin:0 0 10px;color:#4338ca;font-size:16px;\">${data.startTime} - ${data.endTime} (${data.durationText})</p>\n <p style=\"margin:0;color:#4338ca;font-size:16px;\">${data.platform}</p>\n </div>\n \n ${data.meetingLink ? `<div style=\"text-align:center;margin:25px 0;\"><a href=\"${data.meetingLink}\" style=\"display:inline-block;background:${CONFIG.primaryColor};color:#fff;text-decoration:none;padding:15px 40px;border-radius:8px;font-size:16px;font-weight:600;\">Join Meeting</a></div>` : ''}\n \n ${data.description ? `<div style=\"border-top:1px solid #e2e8f0;padding-top:20px;margin-top:20px;\"><p style=\"color:#718096;font-size:14px;line-height:1.6;margin:0;\"><strong>Description:</strong><br>${data.description}</p></div>` : ''}\n </td></tr>\n <tr><td style=\"background:#f7fafc;padding:20px;text-align:center;border-top:1px solid #e2e8f0;border-radius:0 0 12px 12px;\">\n <p style=\"margin:0;color:#718096;font-size:12px;\">${new Date().getFullYear()} ${CONFIG.companyName}</p>\n </td></tr>\n </table>\n </td></tr>\n </table>\n</body>\n</html>\n`;\n\nreturn {\n json: {\n to: data.attendees,\n subject: `Event: ${data.title} - ${data.date} ${data.startTime}`,\n htmlContent: emailHtml\n }\n};"
},
"typeVersion": 2
},
{
"id": "7c7bc8dd-205f-470c-89cd-24978427af49",
"name": "Send Email",
"type": "n8n-nodes-base.gmail",
"position": [
-720,
-624
],
"parameters": {
"sendTo": "={{ $json.to }}",
"message": "={{ $json.htmlContent }}",
"options": {
"appendAttribution": false
},
"subject": "={{ $json.subject }}"
},
"typeVersion": 2
},
{
"id": "d1b987ce-4146-4193-a9ab-c441b1b3419d",
"name": "Get Today Events",
"type": "n8n-nodes-base.googleCalendar",
"position": [
-2320,
96
],
"parameters": {
"options": {
"timeMax": "={{ $now.endOf('day').toISO() }}",
"timeMin": "={{ $now.startOf('day').toISO() }}"
},
"calendar": {
"__rl": true,
"mode": "list",
"value": "primary"
},
"operation": "getAll"
},
"typeVersion": 1.2
},
{
"id": "cef60c0c-d3ca-4729-8c19-0089f03f06ad",
"name": "Calculate Statistics",
"type": "n8n-nodes-base.code",
"position": [
-2080,
96
],
"parameters": {
"jsCode": "const events = $input.all();\nconst today = new Date().toLocaleDateString('en-US', {\n weekday: 'long',\n year: 'numeric',\n month: 'long',\n day: 'numeric'\n});\n\n// Filter non-canceled events\nconst activeEvents = events.filter(e => e.json.status !== 'cancelled');\n\n// Calculate total meeting time\nlet totalMinutes = 0;\nlet virtualMeetings = 0;\nlet inPersonMeetings = 0;\n\nconst eventList = activeEvents.map(e => {\n const event = e.json;\n const start = new Date(event.start?.dateTime || event.start?.date);\n const end = new Date(event.end?.dateTime || event.end?.date);\n const duration = Math.round((end - start) / (1000 * 60));\n \n if (!event.start?.date) { // Don't count all-day events\n totalMinutes += duration;\n }\n \n const hasVideoCall = event.hangoutLink || event.conferenceData?.entryPoints?.length > 0;\n if (hasVideoCall) virtualMeetings++;\n else inPersonMeetings++;\n \n const time = event.start?.dateTime \n ? new Date(event.start.dateTime).toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' })\n : 'All day';\n \n return `- ${time} - ${event.summary || 'Untitled'}`;\n}).join('\\n');\n\n// Format total time\nconst hours = Math.floor(totalMinutes / 60);\nconst minutes = totalMinutes % 60;\nconst formattedTime = hours > 0 \n ? `${hours}h ${minutes}m` \n : `${minutes} minutes`;\n\n// Calculate % of day in meetings (8 work hours = 480 min)\nconst busyPercent = Math.round((totalMinutes / 480) * 100);\n\nlet dayStatus = 'Light day';\nif (busyPercent > 75) dayStatus = 'Very busy day';\nelse if (busyPercent > 50) dayStatus = 'Busy day';\nelse if (busyPercent > 25) dayStatus = 'Moderate day';\n\nreturn {\n json: {\n date: today,\n totalEvents: activeEvents.length,\n meetingTime: formattedTime,\n totalMinutes: totalMinutes,\n busyPercent: `${busyPercent}%`,\n dayStatus: dayStatus,\n virtualMeetings: virtualMeetings,\n inPersonMeetings: inPersonMeetings,\n eventList: eventList || 'No events scheduled',\n generatedAt: new Date().toLocaleTimeString('en-US')\n }\n};"
},
"typeVersion": 2
},
{
"id": "6c631cca-a4de-412d-9bd5-c8b2e111a82f",
"name": "Slack - Daily Summary",
"type": "n8n-nodes-base.slack",
"position": [
-1808,
96
],
"parameters": {
"text": ":chart_with_upwards_trend: *Daily Summary*",
"otherOptions": {
"includeLinkToWorkflow": false
}
},
"typeVersion": 2
},
{
"id": "1c5e480f-0076-4007-bd82-96ee29af4b81",
"name": "Log Statistics",
"type": "n8n-nodes-base.googleSheets",
"position": [
-1568,
96
],
"parameters": {
"columns": {
"value": {
"Date": "={{ $json.date }}",
"Busy %": "={{ $json.busyPercent }}",
"Status": "={{ $json.dayStatus }}",
"Minutes": "={{ $json.totalMinutes }}",
"Virtual": "={{ $json.virtualMeetings }}",
"In-Person": "={{ $json.inPersonMeetings }}",
"Meeting Time": "={{ $json.meetingTime }}",
"Total Events": "={{ $json.totalEvents }}"
},
"mappingMode": "defineBelow"
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "Statistics"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "YOUR_DOCUMENT_ID"
}
},
"typeVersion": 4
},
{
"id": "dcaf1c9c-34a3-4f8f-a561-5fab20a2fe0a",
"name": "Error Trigger",
"type": "n8n-nodes-base.errorTrigger",
"position": [
-2624,
448
],
"parameters": {},
"typeVersion": 1
},
{
"id": "78e60ff2-7e8c-429d-b6eb-745e3e26475f",
"name": "Format Error",
"type": "n8n-nodes-base.code",
"position": [
-2336,
448
],
"parameters": {
"jsCode": "const error = $input.item.json;\nreturn {\n json: {\n errorTime: new Date().toISOString(),\n errorMessage: error.message || 'Unknown error',\n errorNode: error.node?.name || 'Unknown',\n workflow: 'Google Calendar Sync'\n }\n};"
},
"typeVersion": 2
},
{
"id": "5a965d16-af8a-4157-969e-ccec56c5238b",
"name": "Slack - Error Alert",
"type": "n8n-nodes-base.slack",
"position": [
-2096,
448
],
"parameters": {
"text": ":rotating_light: *Workflow Error*",
"otherOptions": {
"includeLinkToWorkflow": true
}
},
"typeVersion": 2
},
{
"id": "bf7ba5a8-8aab-469f-8586-631894568ace",
"name": "Done - Event",
"type": "n8n-nodes-base.noOp",
"position": [
-960,
-416
],
"parameters": {},
"typeVersion": 1
},
{
"id": "422125df-5c53-4b3d-83e1-d86f28937e9b",
"name": "Done - Cancellation",
"type": "n8n-nodes-base.noOp",
"position": [
-1264,
-400
],
"parameters": {},
"typeVersion": 1
},
{
"id": "345927ff-e680-4c43-a47c-23217bf9bf93",
"name": "Done - Summary",
"type": "n8n-nodes-base.noOp",
"position": [
-1312,
96
],
"parameters": {},
"typeVersion": 1
},
{
"id": "e604476b-4bfd-442c-be19-f91f79eaab5f",
"name": "Overview",
"type": "n8n-nodes-base.stickyNote",
"position": [
-3200,
-816
],
"parameters": {
"color": 2,
"width": 440,
"height": 664,
"content": "## Sync Google Calendar events to Sheets with Slack notifications\n\nAutomatically track all calendar events, log them to Google Sheets, and send Slack notifications.\n\n### How it works\n\n1. **Monitor** - Watches calendar for new and updated events\n2. **Process** - Extracts title, date, time, attendees, platform\n3. **Categorize** - Auto-tags: Meeting, 1:1, Interview, Demo, Focus\n4. **Log** - Saves all events to Google Sheets\n5. **Alert** - Slack notifications for changes and cancellations\n6. **Report** - Daily 8 AM summary with stats\n\n### Setup steps\n\n1. Connect Google Calendar, Google Sheets, Slack, Gmail\n2. Create Sheet with tab named \"Events\"\n3. Replace YOUR_DOCUMENT_ID in Sheets nodes\n4. Configure Slack channels: #calendar and #errors\n5. Test by creating a calendar event"
},
"typeVersion": 1
},
{
"id": "3f3e0e22-b5f1-43c5-a860-a0f2b696d4a8",
"name": "Step 1 Calendar Triggers",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2624,
-816
],
"parameters": {
"color": 5,
"width": 280,
"height": 650,
"content": "## Step 1: Calendar Triggers\n\n**What happens here:**\n- New event trigger\n- Updated event trigger\n- Monitors your calendar"
},
"typeVersion": 1
},
{
"id": "bb40d8be-7657-4750-82a8-97f2762fe561",
"name": "Step 2 Event Processing",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2320,
-816
],
"parameters": {
"color": 7,
"width": 520,
"height": 650,
"content": "## Step 2: Event Processing\n\n**What happens here:**\n- Extract event details\n- Check if cancelled\n- Route accordingly"
},
"typeVersion": 1
},
{
"id": "f5edd03e-cd96-4779-a57a-9c54bf581722",
"name": "Step 3 Logging",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1776,
-816
],
"parameters": {
"color": 6,
"width": 696,
"height": 650,
"content": "## Step 3: Logging & Alerts\n\n**What happens here:**\n- Log to Sheets\n- Slack notifications\n- Track changes"
},
"typeVersion": 1
},
{
"id": "a931e3ec-4411-4e27-914d-fdcb229585dc",
"name": "Step 4 Email",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1024,
-816
],
"parameters": {
"color": 5,
"width": 520,
"height": 650,
"content": "## Step 4: Confirmation Email\n\n**What happens here:**\n- Prepare email\n- Send to attendees\n- Confirmation flow"
},
"typeVersion": 1
},
{
"id": "87d6cbad-0be6-4ea5-a94f-9c7e8adfcef9",
"name": "Step 5 Daily Summary",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2656,
-96
],
"parameters": {
"color": 7,
"width": 1540,
"height": 352,
"content": "## Step 5: Daily Summary\n\n**What happens here:**\n- 8 AM trigger\n- Calculate statistics\n- Slack report"
},
"typeVersion": 1
},
{
"id": "b9f3c06d-220f-44ea-8200-fcd231b4a142",
"name": "Step 6 Error Handling",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2656,
288
],
"parameters": {
"color": 6,
"width": 1552,
"height": 320,
"content": "## Step 6: Error Handling\n\n**What happens here:**\n- Catch errors\n- Format details\n- Alert #errors"
},
"typeVersion": 1
}
],
"connections": {
"Log Event": {
"main": [
[
{
"node": "Slack - New Event",
"type": "main",
"index": 0
}
]
]
},
"Send Email": {
"main": [
[
{
"node": "Done - Event",
"type": "main",
"index": 0
}
]
]
},
"Format Error": {
"main": [
[
{
"node": "Slack - Error Alert",
"type": "main",
"index": 0
}
]
]
},
"Is Canceled?": {
"main": [
[
{
"node": "Log Cancellation",
"type": "main",
"index": 0
}
],
[
{
"node": "Log Event",
"type": "main",
"index": 0
}
]
]
},
"Error Trigger": {
"main": [
[
{
"node": "Format Error",
"type": "main",
"index": 0
}
]
]
},
"Process Event": {
"main": [
[
{
"node": "Is Canceled?",
"type": "main",
"index": 0
}
]
]
},
"Has Attendees?": {
"main": [
[
{
"node": "Prepare Confirmation Email",
"type": "main",
"index": 0
}
],
[
{
"node": "Done - Event",
"type": "main",
"index": 0
}
]
]
},
"Log Statistics": {
"main": [
[
{
"node": "Done - Summary",
"type": "main",
"index": 0
}
]
]
},
"Get Today Events": {
"main": [
[
{
"node": "Calculate Statistics",
"type": "main",
"index": 0
}
]
]
},
"Log Cancellation": {
"main": [
[
{
"node": "Slack - Cancellation",
"type": "main",
"index": 0
}
]
]
},
"New Event Trigger": {
"main": [
[
{
"node": "Process Event",
"type": "main",
"index": 0
}
]
]
},
"Slack - New Event": {
"main": [
[
{
"node": "Has Attendees?",
"type": "main",
"index": 0
}
]
]
},
"Calculate Statistics": {
"main": [
[
{
"node": "Slack - Daily Summary",
"type": "main",
"index": 0
}
]
]
},
"Slack - Cancellation": {
"main": [
[
{
"node": "Done - Cancellation",
"type": "main",
"index": 0
}
]
]
},
"Daily Summary Trigger": {
"main": [
[
{
"node": "Get Today Events",
"type": "main",
"index": 0
}
]
]
},
"Slack - Daily Summary": {
"main": [
[
{
"node": "Log Statistics",
"type": "main",
"index": 0
}
]
]
},
"Updated Event Trigger": {
"main": [
[
{
"node": "Process Event",
"type": "main",
"index": 0
}
]
]
},
"Prepare Confirmation Email": {
"main": [
[
{
"node": "Send Email",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Sync your Google Calendar events with Google Sheets and get daily Slack summaries with meeting statistics. FEATURES:
Source: https://n8n.io/workflows/12081/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Automate daily KPI tracking and reporting by integrating ClickUp tasks and Google Sheets lead data into a unified dashboard. This workflow computes performance metrics, analyzes sentiment, and deliver
This n8n workflow transforms your HR department from reactive to proactive by automatically monitoring 5 critical employee timelines and generating smart alerts before deadlines hit. Data Input → Empl
Categories: Payments, Project Operations, Client Onboarding
Fluxo de Entrevistas. Uses formTrigger, gmail, googleSheets, googleCalendar. Event-driven trigger; 28 nodes.
Complete Calendly automation that handles confirmations, cancellations and reschedules in a single workflow. WHAT IT DOES: