This workflow corresponds to n8n.io template #16904 — we link there as the canonical source.
This workflow follows the Gmail → Google Sheets 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 →
{
"id": "D3xrD6bKnTDX7ufR",
"name": "n8n Starter Lab",
"tags": [],
"nodes": [
{
"id": "ab1aa2d8-228a-4d55-9238-26896d76645c",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-192,
848
],
"parameters": {
"width": 816,
"height": 320,
"content": "## Live Event Lab QR Scan Attendance Booking\n\n### How it works\n\nThis workflow handles QR code-based event registration. Attendees scan a QR code, complete a registration form, and the form submits data to this webhook.\n\nThe workflow:\n- Validates required fields (name, email, eventId)\n- Checks Google Sheets for an existing registration\n- Returns a duplicate response if already registered\n- Otherwise saves the attendee, sends a Gmail confirmation, and returns success\n"
},
"typeVersion": 1
},
{
"id": "9c83f1cf-b344-4dc0-87a9-15f54221d33f",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-192,
1248
],
"parameters": {
"color": 7,
"width": 1024,
"height": 432,
"content": "## Receive and validate request\n\nStarts from the webhook, validates the incoming payload, and branches invalid submissions to an immediate JSON error response."
},
"typeVersion": 1
},
{
"id": "fced7f88-c7e6-4fe3-8ef9-16d014f9dd46",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
864,
1120
],
"parameters": {
"color": 7,
"width": 960,
"height": 480,
"content": "## Check existing registration\n\nReads the current Google Sheets rows, checks whether the submitted user is already present, and returns an already-registered response for duplicates."
},
"typeVersion": 1
},
{
"id": "d158af51-7a4d-4d49-b8ce-a7c8c9440291",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1856,
1216
],
"parameters": {
"color": 7,
"width": 480,
"height": 368,
"content": "## Save and notify user\n\nHandles the non-duplicate path by appending the new registration to Google Sheets and sending a confirmation email through Gmail."
},
"typeVersion": 1
},
{
"id": "5454cdac-a641-4ecf-b560-aae734fbcdf2",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
2352,
1200
],
"parameters": {
"color": 7,
"width": 368,
"height": 384,
"content": "## Return success response\n\nFinishes the successful registration path by sending a JSON response back to the webhook caller."
},
"typeVersion": 1
},
{
"id": "054d9668-5bf1-4af8-81b1-4bc59870d197",
"name": "Check Input Validity",
"type": "n8n-nodes-base.code",
"position": [
160,
1376
],
"parameters": {
"jsCode": "const body = $input.first().json.body || {};\nconst name = body.name?.trim();\nconst email = body.email?.trim();\nconst role = body.role?.trim() || 'Participant';\nconst eventId = body.eventId || 'n8n-starter-lab-2026';\nconst day = body.day?.trim() || 'Day 1';\nconst sheetName = day.replace(' ', '');\n\nif (!name || !email) {\n return [{ json: { valid: false, message: 'Name and email are required.' } }];\n}\n\nconst emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\nif (!emailRegex.test(email)) {\n return [{ json: { valid: false, message: 'Please enter a valid email address.' } }];\n}\n\nconst now = new Date();\nconst dateStr = now.toLocaleDateString('en-GB', { timeZone: 'Europe/Berlin', day: '2-digit', month: 'long', year: 'numeric' });\nconst timeStr = now.toLocaleTimeString('en-GB', { timeZone: 'Europe/Berlin', hour: '2-digit', minute: '2-digit', hour12: false });\nconst nameUpper = name.toUpperCase();\n\nreturn [{\n json: {\n valid: true,\n name,\n nameUpper,\n email,\n role,\n eventId,\n day,\n sheetName,\n timestamp: now.toISOString(),\n date: dateStr,\n time: timeStr\n }\n}];\n"
},
"typeVersion": 2
},
{
"id": "34c8a187-2ab3-4a1a-884d-cb649f3fa2e6",
"name": "Check Validity Status",
"type": "n8n-nodes-base.if",
"position": [
384,
1376
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "cond-001",
"operator": {
"type": "boolean",
"operation": "true"
},
"leftValue": "={{ $json.valid }}",
"rightValue": true
}
]
}
},
"typeVersion": 2
},
{
"id": "f40569f3-d49a-4675-ac92-9911dc1c7f6c",
"name": "Retrieve Sheet Data",
"type": "n8n-nodes-base.googleSheets",
"position": [
912,
1360
],
"parameters": {
"options": {},
"sheetName": {
"__rl": true,
"mode": "name",
"value": "={{ $json.day.replace(' ', '') }}"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1fzBymGE1OozTAxpor_KeAo8COsFZ1lEHDo3C69rOnCk",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1fzBymGE1OozTAxpor_KeAo8COsFZ1lEHDo3C69rOnCk/edit?usp=drivesdk",
"cachedResultName": "Training Participants"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4,
"alwaysOutputData": true
},
{
"id": "c497c859-221d-446d-866a-f3cfb8d2a215",
"name": "Identify Duplicates",
"type": "n8n-nodes-base.code",
"position": [
1136,
1360
],
"parameters": {
"jsCode": "const incomingEmail = $('Check Input Validity').first().json.email.toLowerCase().trim();\nconst rows = $input.all();\n\n// If no rows returned, sheet is empty \u2014 no duplicate\nif (!rows || rows.length === 0) {\n return [{ json: { isDuplicate: false } }];\n}\n\n// Check if any row has matching email\nconst found = rows.some(row => {\n const rowEmail = (row.json.email || '').toLowerCase().trim();\n return rowEmail === incomingEmail;\n});\n\nreturn [{ json: { isDuplicate: found } }];"
},
"typeVersion": 2
},
{
"id": "01e2acb5-c687-4658-991a-14131b0119b2",
"name": "If Duplicate Exists",
"type": "n8n-nodes-base.if",
"position": [
1344,
1360
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "dup-cond-001",
"operator": {
"type": "boolean",
"operation": "true"
},
"leftValue": "={{ $json.isDuplicate }}",
"rightValue": true
}
]
}
},
"typeVersion": 2
},
{
"id": "f0596d41-da56-44aa-8df2-03da415736b0",
"name": "Add New Entry to Sheets",
"type": "n8n-nodes-base.googleSheets",
"position": [
1920,
1376
],
"parameters": {
"columns": {
"value": {
"date": "={{ $('Check Input Validity').first().json.date }}",
"name": "={{ $('Check Input Validity').first().json.name }}",
"role": "={{ $('Check Input Validity').first().json.role }}",
"time": "={{ $('Check Input Validity').first().json.time }}",
"email": "={{ $('Check Input Validity').first().json.email }}",
"eventId": "={{ $('Check Input Validity').first().json.eventId }}"
},
"schema": [
{
"id": "name",
"type": "string",
"display": true,
"required": false,
"displayName": "name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "email",
"type": "string",
"display": true,
"required": false,
"displayName": "email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "role",
"type": "string",
"display": true,
"required": false,
"displayName": "role",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "eventId",
"type": "string",
"display": true,
"required": false,
"displayName": "eventId",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "date",
"type": "string",
"display": true,
"required": false,
"displayName": "date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "time",
"type": "string",
"display": true,
"required": false,
"displayName": "time",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "={{ $('Check Input Validity').first().json.sheetName }}"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1fzBymGE1OozTAxpor_KeAo8COsFZ1lEHDo3C69rOnCk",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1fzBymGE1OozTAxpor_KeAo8COsFZ1lEHDo3C69rOnCk/edit?usp=drivesdk",
"cachedResultName": "Training Participants"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4
},
{
"id": "440fb12f-064d-4fdd-82a3-3289da15fb20",
"name": "Dispatch Confirmation Email",
"type": "n8n-nodes-base.gmail",
"position": [
2144,
1376
],
"parameters": {
"sendTo": "={{ $('Check Input Validity').first().json.email }}",
"message": "=<!DOCTYPE html><html><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"></head><body style=\"margin:0;padding:0;background:#f0f7f6;font-family:'Helvetica Neue',Arial,sans-serif;\"><table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" style=\"background:#f0f7f6;padding:40px 0;\"><tr><td align=\"center\"><table width=\"560\" cellpadding=\"0\" cellspacing=\"0\" style=\"max-width:560px;width:100%;\"><tr><td style=\"background:#2B7B6D;border-radius:12px 12px 0 0;padding:24px 36px;\"><span style=\"color:#fff;font-size:18px;font-weight:700;letter-spacing:-0.3px;\">n8n Training</span></td></tr><tr><td style=\"background:#ffffff;padding:36px 36px 32px;border-radius:0 0 12px 12px;box-shadow:0 4px 20px rgba(0,0,0,0.08);\"><p style=\"margin:0 0 4px;font-size:15px;color:#6b7280;\">Hi <strong style=\"color:#111827;\">{{ $('Check Input Validity').first().json.nameUpper }}</strong>,</p><h1 style=\"margin:0 0 20px;font-size:22px;font-weight:700;color:#111827;letter-spacing:-0.4px;\">Your attendance is confirmed! \ud83c\udf89</h1><p style=\"margin:0 0 28px;font-size:15px;color:#4b5563;line-height:1.65;\">Thank you for registering for <strong>n8n Training</strong>. We are excited to have you join us for a hands-on session on building automations with n8n.</p><table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" style=\"background:#f0faf8;border:1.5px solid #a7d4cf;border-radius:10px;margin-bottom:28px;\"><tr><td style=\"padding:20px 24px;\"><p style=\"margin:0 0 14px;font-size:11px;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;color:#2B7B6D;\">Registration Details</p><table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\"><tr><td style=\"padding:5px 0;font-size:13px;color:#6b7280;width:70px;\">Event</td><td style=\"padding:5px 0;font-size:13px;font-weight:600;color:#111827;\">{{ $('Check Input Validity').first().json.eventId }}</td></tr><tr><td style=\"padding:5px 0;font-size:13px;color:#6b7280;\">Day</td><td style=\"padding:5px 0;font-size:13px;font-weight:600;color:#111827;\">{{ $('Check Input Validity').first().json.day }}</td></tr><tr><td style=\"padding:5px 0;font-size:13px;color:#6b7280;\">Role</td><td style=\"padding:5px 0;font-size:13px;font-weight:600;color:#111827;\">{{ $('Check Input Validity').first().json.role }}</td></tr><tr><td style=\"padding:5px 0;font-size:13px;color:#6b7280;\">Name</td><td style=\"padding:5px 0;font-size:13px;font-weight:600;color:#111827;\">{{ $('Check Input Validity').first().json.nameUpper }}</td></tr><tr><td style=\"padding:5px 0;font-size:13px;color:#6b7280;\">Date</td><td style=\"padding:5px 0;font-size:13px;font-weight:600;color:#111827;\">{{ $('Check Input Validity').first().json.date }}</td></tr><tr><td style=\"padding:5px 0;font-size:13px;color:#6b7280;\">Time</td><td style=\"padding:5px 0;font-size:13px;font-weight:600;color:#111827;\">{{ $('Check Input Validity').first().json.time }} (CET)</td></tr></table></td></tr></table><p style=\"margin:0 0 14px;font-size:15px;color:#4b5563;line-height:1.65;\">Get ready to explore real-world automation workflows, connect nodes, and build your first working pipeline \u2014 no prior experience needed.</p><p style=\"margin:0 0 32px;font-size:15px;color:#4b5563;line-height:1.65;\">More details about the session schedule and resources will be shared closer to the event date. Stay tuned!</p><hr style=\"border:none;border-top:1px solid #e5f4f2;margin:0 0 24px;\"><p style=\"margin:0 0 4px;font-size:12px;color:#9ca3af;\">If you have any questions, feel free to reply to this email.</p><p style=\"margin:0;font-size:13px;color:#4b5563;\">Best regards,<br><strong style=\"color:#2B7B6D;\"> Training Team</strong></p></td></tr></table></td></tr></table></body></html>\n",
"options": {
"senderName": "Training Attendance"
},
"subject": "=Attendance Confirmed - {{ $('Check Input Validity').first().json.eventId }}"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2
},
{
"id": "9bbe4dda-4ae9-4ea1-9ec0-70eb49f380d5",
"name": "Return Success Response",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
2464,
1376
],
"parameters": {
"options": {
"responseHeaders": {
"entries": [
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "Access-Control-Allow-Origin",
"value": "*"
}
]
}
},
"respondWith": "json",
"responseBody": "={{ JSON.stringify({ success: true, message: 'Attendance registered! Confirmation email sent.', name: $('Check Input Validity').first().json.name, role: $('Check Input Validity').first().json.role, eventId: $('Check Input Validity').first().json.eventId, timestamp: $('Check Input Validity').first().json.timestamp }) }}"
},
"typeVersion": 1
},
{
"id": "22e51da3-cd59-48f0-a817-9bc6d6cc9c61",
"name": "Return Error Response",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
608,
1504
],
"parameters": {
"options": {
"responseHeaders": {
"entries": [
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "Access-Control-Allow-Origin",
"value": "*"
}
]
}
},
"respondWith": "json",
"responseBody": "={{ JSON.stringify({ success: false, message: $json.message || 'Validation failed.' }) }}"
},
"typeVersion": 1
},
{
"id": "e8b37bd3-2fc4-4e93-8eaf-2dff5699c062",
"name": "Return Duplicate Response",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
1584,
1232
],
"parameters": {
"options": {
"responseHeaders": {
"entries": [
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "Access-Control-Allow-Origin",
"value": "*"
}
]
}
},
"respondWith": "json",
"responseBody": "={{ JSON.stringify({ success: false, duplicate: true, message: 'Attendance already marked for this email.' }) }}"
},
"typeVersion": 1
},
{
"id": "9bac5983-5232-48bd-a3a1-c5b212996542",
"name": "Receive Webhook Data",
"type": "n8n-nodes-base.webhook",
"position": [
-96,
1376
],
"parameters": {
"path": "register",
"options": {
"allowedOrigins": "*"
},
"httpMethod": "POST",
"responseMode": "responseNode",
"authentication": "basicAuth"
},
"credentials": {
"httpBasicAuth": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"executionOrder": "v1"
},
"versionId": "520206d0-0199-4fa4-9cc5-8d9958c19fe4",
"connections": {
"Identify Duplicates": {
"main": [
[
{
"node": "If Duplicate Exists",
"type": "main",
"index": 0
}
]
]
},
"If Duplicate Exists": {
"main": [
[
{
"node": "Return Duplicate Response",
"type": "main",
"index": 0
}
],
[
{
"node": "Add New Entry to Sheets",
"type": "main",
"index": 0
}
]
]
},
"Retrieve Sheet Data": {
"main": [
[
{
"node": "Identify Duplicates",
"type": "main",
"index": 0
}
]
]
},
"Check Input Validity": {
"main": [
[
{
"node": "Check Validity Status",
"type": "main",
"index": 0
}
]
]
},
"Receive Webhook Data": {
"main": [
[
{
"node": "Check Input Validity",
"type": "main",
"index": 0
}
]
]
},
"Check Validity Status": {
"main": [
[
{
"node": "Retrieve Sheet Data",
"type": "main",
"index": 0
}
],
[
{
"node": "Return Error Response",
"type": "main",
"index": 0
}
]
]
},
"Add New Entry to Sheets": {
"main": [
[
{
"node": "Dispatch Confirmation Email",
"type": "main",
"index": 0
}
]
]
},
"Dispatch Confirmation Email": {
"main": [
[
{
"node": "Return Success Response",
"type": "main",
"index": 0
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
gmailOAuth2googleSheetsOAuth2ApihttpBasicAuth
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow powers a QR code-based event attendance system. A presenter displays a QR code (generated via the companion web app) which participants scan with their phones. Scanning opens a registration form pre-filled with the Event ID; on submission, the form POSTs to this…
Source: https://n8n.io/workflows/16904/ — 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 WhatsApp communication for recruitment agencies with an interactive, structured customer experience. This workflow handles pricing inquiries, request submissions, tracking, complaints, and hu
This workflow automates HR onboarding by capturing new hires via a webhook, saving them to Google Sheets, emailing a Slack invite via Gmail, and notifying managers in Slack, then listening for Slack t
Advanced AI Powered Document Parsing & Text Extraction with Llama Parse. Uses gmail, gmailTrigger, httpRequest, googleSheets. Webhook trigger; 54 nodes.
Code. Uses googleSheets, gmail, supabase, stickyNote. Webhook trigger; 51 nodes.
This template turns Podium's conversation inbox into a full sales CRM with a custom funnel, AI message classification, automated drip follow-ups, daily admin reports, and a live Kanban dashboard. Six