This workflow corresponds to n8n.io template #11821 — 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 →
{
"nodes": [
{
"id": "f2a4e703-2598-414b-8e2c-a43317171315",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-304,
-128
],
"parameters": {
"width": 400,
"height": 880,
"content": "## Manage event participants and process QR code check-ins\n\n### Who is this for?\nEvent organizers, conference managers, and community teams who need automated participant management with registration and check-in tracking.\n\n### What this workflow does\n**Registration Flow:**\n- Receives registration via webhook\n- Generates unique ticket ID and QR code\n- Stores in Google Sheets and sends confirmation email\n\n**Check-in Flow:**\n- Decodes scanned QR code\n- Validates ticket and blocks duplicates\n- Sends Slack alerts for VIP arrivals\n- Returns attendance statistics\n\n### Setup\n1. Create Google Sheet with participant columns\n2. Connect Google Sheets and Gmail credentials\n3. Configure Slack for VIP notifications\n\n### Requirements\n- Google Sheets\n- Gmail account\n- Slack workspace"
},
"typeVersion": 1
},
{
"id": "1228946c-c619-4a3d-afa3-5245cd52ea41",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
176,
-128
],
"parameters": {
"color": 7,
"width": 280,
"height": 80,
"content": "**Step 1: Registration**\nReceive participant data, create ticket ID, and save to Google Sheets."
},
"typeVersion": 1
},
{
"id": "f58e2b56-ebf4-4d98-957e-f2c387de94d9",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
672,
-128
],
"parameters": {
"color": 7,
"width": 300,
"height": 80,
"content": "**Step 2: QR Code & Email**\nGenerate QR code with ticket data and send confirmation email with attachment."
},
"typeVersion": 1
},
{
"id": "a2a90ffa-427f-4aae-b5bf-a367859b08fe",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
160,
368
],
"parameters": {
"color": 7,
"width": 280,
"height": 96,
"content": "**Step 3: Check-in Validation**\nDecode QR, validate ticket, and check for duplicate entries."
},
"typeVersion": 1
},
{
"id": "c4eb5603-e201-4939-a695-e23f4783db98",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
1488,
192
],
"parameters": {
"color": 7,
"width": 260,
"height": 80,
"content": "**Step 4: VIP Handling**\nDetect VIP tickets and send Slack notification to event staff."
},
"typeVersion": 1
},
{
"id": "7708123a-6137-4f8a-8454-808d91bf4dd8",
"name": "Registration Webhook",
"type": "n8n-nodes-base.webhook",
"position": [
176,
-16
],
"parameters": {
"path": "event-register",
"options": {},
"httpMethod": "POST",
"responseMode": "responseNode"
},
"typeVersion": 2
},
{
"id": "6305126d-eab7-49a6-98cf-2384615bdf76",
"name": "Create Ticket Data",
"type": "n8n-nodes-base.set",
"position": [
400,
-16
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "1",
"name": "ticketId",
"type": "string",
"value": "={{ 'TKT-' + $json.body.eventId + '-' + $now.format('HHmmssSSS') }}"
},
{
"id": "2",
"name": "eventId",
"type": "string",
"value": "={{ $json.body.eventId }}"
},
{
"id": "3",
"name": "participantName",
"type": "string",
"value": "={{ $json.body.name }}"
},
{
"id": "4",
"name": "email",
"type": "string",
"value": "={{ $json.body.email }}"
},
{
"id": "5",
"name": "ticketType",
"type": "string",
"value": "={{ $json.body.ticketType || 'standard' }}"
},
{
"id": "6",
"name": "registeredAt",
"type": "string",
"value": "={{ $now.toISO() }}"
},
{
"id": "7",
"name": "checkedIn",
"type": "string",
"value": "no"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "e9a53078-081a-4cf2-8bad-47b0b6fc94c0",
"name": "Save to Participants Sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
624,
-16
],
"parameters": {
"columns": {
"value": {
"Name": "={{ $json.participantName }}",
"Email": "={{ $json.email }}",
"Event ID": "={{ $json.eventId }}",
"Ticket ID": "={{ $json.ticketId }}",
"Checked In": "={{ $json.checkedIn }}",
"Ticket Type": "={{ $json.ticketType }}",
"Check-in Time": "",
"Registered At": "={{ $json.registeredAt }}"
},
"mappingMode": "defineBelow"
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "Participants"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": ""
}
},
"typeVersion": 4.5
},
{
"id": "5cce1cc0-faf8-4527-9eee-37f9e75ab31a",
"name": "Prepare QR Payload",
"type": "n8n-nodes-base.code",
"position": [
832,
-16
],
"parameters": {
"jsCode": "const ticket = $input.first().json;\n\nconst qrPayload = JSON.stringify({\n t: ticket.ticketId,\n e: ticket.eventId,\n n: ticket.participantName.substring(0, 20),\n ts: Date.now()\n});\n\nconst encodedPayload = Buffer.from(qrPayload).toString('base64');\n\nreturn [{\n json: {\n ...ticket,\n qrData: encodedPayload,\n qrContent: `https://event.company.com/checkin?code=${encodedPayload}`\n }\n}];"
},
"typeVersion": 2
},
{
"id": "044255d1-666d-46e1-ba77-0347a16078b7",
"name": "Generate QR Code",
"type": "n8n-nodes-base.httpRequest",
"position": [
1056,
-16
],
"parameters": {
"url": "=https://api.qrserver.com/v1/create-qr-code/?size=300x300&data={{ encodeURIComponent($json.qrContent) }}",
"options": {
"response": {
"response": {
"responseFormat": "file"
}
}
}
},
"typeVersion": 4.2
},
{
"id": "4096158e-0722-4bdb-98b3-cf25b7d61c56",
"name": "Send Ticket Email",
"type": "n8n-nodes-base.gmail",
"position": [
1280,
-16
],
"parameters": {
"sendTo": "={{ $json.email }}",
"message": "=Hello {{ $json.participantName }},\n\nThank you for registering!\n\nTicket ID: {{ $json.ticketId }}\nTicket Type: {{ $json.ticketType }}\n\nPlease present the attached QR code at the venue entrance.",
"options": {
"attachmentsUi": {
"attachmentsBinary": [
{}
]
}
},
"subject": "=Your Ticket for {{ $json.eventId }}"
},
"typeVersion": 2.1
},
{
"id": "39756491-416a-454b-be79-b5a66dd0313f",
"name": "Registration Success",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
1504,
-16
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={{ JSON.stringify({ success: true, ticketId: $json.ticketId, message: 'Ticket sent to ' + $json.email }) }}"
},
"typeVersion": 1.1
},
{
"id": "31ba1d12-9c7f-43ca-bc3b-00cf5118d869",
"name": "Check-in Webhook",
"type": "n8n-nodes-base.webhook",
"position": [
176,
512
],
"parameters": {
"path": "event-checkin",
"options": {},
"httpMethod": "POST",
"responseMode": "responseNode"
},
"typeVersion": 2
},
{
"id": "c48a2ec3-6cca-4193-bc26-4577e4f88e86",
"name": "Decode QR Code",
"type": "n8n-nodes-base.code",
"position": [
384,
512
],
"parameters": {
"jsCode": "const input = $input.first().json;\nconst qrCode = input.body?.code || input.body?.qrCode || '';\n\nif (!qrCode) {\n return [{ json: { valid: false, error: 'No QR code provided' } }];\n}\n\ntry {\n const decoded = Buffer.from(qrCode, 'base64').toString('utf8');\n const payload = JSON.parse(decoded);\n \n return [{\n json: {\n valid: true,\n ticketId: payload.t,\n eventId: payload.e,\n participantName: payload.n,\n scanTime: new Date().toISOString()\n }\n }];\n} catch (e) {\n return [{ json: { valid: false, error: 'Invalid QR code format' } }];\n}"
},
"typeVersion": 2
},
{
"id": "2c87839a-641f-4c98-87a8-844b9ad03926",
"name": "Is Valid QR?",
"type": "n8n-nodes-base.if",
"position": [
608,
512
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "valid",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.valid }}"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "61304708-30fd-4254-9009-59d738104e0c",
"name": "Lookup Ticket in DB",
"type": "n8n-nodes-base.googleSheets",
"position": [
832,
400
],
"parameters": {
"operation": "getMany",
"documentId": {
"__rl": true,
"mode": "list",
"value": ""
}
},
"typeVersion": 4.5
},
{
"id": "ee2e1e8e-8f95-481f-adb0-098778cc016c",
"name": "Validate Check-in",
"type": "n8n-nodes-base.code",
"position": [
1056,
400
],
"parameters": {
"jsCode": "const qrData = $('Decode QR Code').first().json;\nconst ticketRecords = $input.all();\n\nif (ticketRecords.length === 0) {\n return [{ json: { allowed: false, reason: 'Ticket not found', ticketId: qrData.ticketId } }];\n}\n\nconst ticket = ticketRecords[0].json;\n\nif (ticket['Checked In'] === 'yes') {\n return [{ json: { \n allowed: false, \n reason: 'Already checked in at ' + ticket['Check-in Time'],\n ticketId: qrData.ticketId,\n participantName: ticket.Name\n } }];\n}\n\nreturn [{ json: {\n allowed: true,\n ticketId: qrData.ticketId,\n eventId: ticket['Event ID'],\n participantName: ticket.Name,\n ticketType: ticket['Ticket Type'],\n isVIP: ticket['Ticket Type']?.toLowerCase() === 'vip',\n checkInTime: qrData.scanTime\n} }];"
},
"typeVersion": 2
},
{
"id": "74239af4-ebb7-4771-8f13-aee588c67605",
"name": "Check-in Allowed?",
"type": "n8n-nodes-base.if",
"position": [
1264,
400
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "allowed",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.allowed }}"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "100b8983-8cba-4a66-9f0a-7ef4b621be0a",
"name": "Mark as Checked In",
"type": "n8n-nodes-base.googleSheets",
"position": [
1488,
304
],
"parameters": {
"columns": {
"value": {
"Ticket ID": "={{ $json.ticketId }}",
"Checked In": "yes",
"Check-in Time": "={{ $json.checkInTime }}"
},
"mappingMode": "defineBelow"
},
"options": {},
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "Participants"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": ""
}
},
"typeVersion": 4.5
},
{
"id": "1938e6f2-a284-443f-9799-dab383c43f32",
"name": "Is VIP?",
"type": "n8n-nodes-base.if",
"position": [
1712,
304
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "vip",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.isVIP }}"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "4b2a9d05-8501-44ae-9556-1ec88156c2c2",
"name": "Slack VIP Alert",
"type": "n8n-nodes-base.slack",
"position": [
1936,
208
],
"parameters": {
"text": "=:star: *VIP Arrival*\n{{ $json.participantName }} has arrived!\nTicket: {{ $json.ticketId }}",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "name",
"value": "#event-vip"
},
"otherOptions": {}
},
"typeVersion": 2.2
},
{
"id": "536b9854-756b-489f-a781-9ea15eb60c67",
"name": "Merge VIP Path",
"type": "n8n-nodes-base.merge",
"position": [
2144,
304
],
"parameters": {
"mode": "chooseBranch"
},
"typeVersion": 3
},
{
"id": "e27d9c5b-f24c-4c32-b48b-406e79c40438",
"name": "Build Success Response",
"type": "n8n-nodes-base.code",
"position": [
2368,
304
],
"parameters": {
"jsCode": "const checkinData = $('Validate Check-in').first().json;\n\nconst mockAttendance = 245;\nconst capacity = 300;\nconst attendancePercent = (mockAttendance / capacity * 100).toFixed(1);\n\nreturn [{\n json: {\n status: 'success',\n message: `Welcome, ${checkinData.participantName}!`,\n ticketId: checkinData.ticketId,\n ticketType: checkinData.ticketType,\n checkInTime: checkinData.checkInTime,\n attendanceCount: mockAttendance,\n capacityPercent: parseFloat(attendancePercent)\n }\n}];"
},
"typeVersion": 2
},
{
"id": "db1f12e8-a819-49dd-8c57-6fa1da26c0c8",
"name": "Check-in Success",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
2592,
304
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={{ JSON.stringify($json) }}"
},
"typeVersion": 1.1
},
{
"id": "477702f1-5df6-48e3-b623-dc904858a2a2",
"name": "Check-in Denied",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
1488,
512
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={{ JSON.stringify({ status: 'denied', reason: $json.reason, ticketId: $json.ticketId }) }}"
},
"typeVersion": 1.1
},
{
"id": "7cb84ed5-7834-4815-ae61-e0d09608b9cc",
"name": "Invalid QR Response",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
832,
608
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={{ JSON.stringify({ status: 'error', error: $json.error }) }}"
},
"typeVersion": 1.1
}
],
"connections": {
"Is VIP?": {
"main": [
[
{
"node": "Slack VIP Alert",
"type": "main",
"index": 0
}
],
[
{
"node": "Merge VIP Path",
"type": "main",
"index": 1
}
]
]
},
"Is Valid QR?": {
"main": [
[
{
"node": "Lookup Ticket in DB",
"type": "main",
"index": 0
}
],
[
{
"node": "Invalid QR Response",
"type": "main",
"index": 0
}
]
]
},
"Decode QR Code": {
"main": [
[
{
"node": "Is Valid QR?",
"type": "main",
"index": 0
}
]
]
},
"Merge VIP Path": {
"main": [
[
{
"node": "Build Success Response",
"type": "main",
"index": 0
}
]
]
},
"Slack VIP Alert": {
"main": [
[
{
"node": "Merge VIP Path",
"type": "main",
"index": 0
}
]
]
},
"Check-in Webhook": {
"main": [
[
{
"node": "Decode QR Code",
"type": "main",
"index": 0
}
]
]
},
"Generate QR Code": {
"main": [
[
{
"node": "Send Ticket Email",
"type": "main",
"index": 0
}
]
]
},
"Check-in Allowed?": {
"main": [
[
{
"node": "Mark as Checked In",
"type": "main",
"index": 0
}
],
[
{
"node": "Check-in Denied",
"type": "main",
"index": 0
}
]
]
},
"Send Ticket Email": {
"main": [
[
{
"node": "Registration Success",
"type": "main",
"index": 0
}
]
]
},
"Validate Check-in": {
"main": [
[
{
"node": "Check-in Allowed?",
"type": "main",
"index": 0
}
]
]
},
"Create Ticket Data": {
"main": [
[
{
"node": "Save to Participants Sheet",
"type": "main",
"index": 0
}
]
]
},
"Mark as Checked In": {
"main": [
[
{
"node": "Is VIP?",
"type": "main",
"index": 0
}
]
]
},
"Prepare QR Payload": {
"main": [
[
{
"node": "Generate QR Code",
"type": "main",
"index": 0
}
]
]
},
"Lookup Ticket in DB": {
"main": [
[
{
"node": "Validate Check-in",
"type": "main",
"index": 0
}
]
]
},
"Registration Webhook": {
"main": [
[
{
"node": "Create Ticket Data",
"type": "main",
"index": 0
}
]
]
},
"Build Success Response": {
"main": [
[
{
"node": "Check-in Success",
"type": "main",
"index": 0
}
]
]
},
"Save to Participants Sheet": {
"main": [
[
{
"node": "Prepare QR Payload",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Who is this for? This template is ideal for event organizers, conference managers, and community teams who need an automated participant management system. Perfect for workshops, conferences, meetups, or any event requiring registration and check-in tracking. What this workflow…
Source: https://n8n.io/workflows/11821/ — 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.
Streamline and standardize your entire client onboarding process with a single end-to-end automation. 🚀📋 This workflow captures detailed client intake data via webhook, automatically creates a fully s
Human Approval AI Response. Uses httpRequest, slack, gmail, googleSheets. Webhook trigger; 20 nodes.
Automate WhatsApp communication for recruitment agencies with an interactive, structured customer experience. This workflow handles pricing inquiries, request submissions, tracking, complaints, and hu
Suspicious_login_detection. Uses postgres, httpRequest, noOp, html. Webhook trigger; 43 nodes.
This n8n workflow is designed for security monitoring and incident response when suspicious login events are detected. It can be initiated either manually from within the n8n UI for testing or automat