This workflow corresponds to n8n.io template #5758 — we link there as the canonical source.
This workflow follows the Form → Form Trigger 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": "B1Tn4E0X4IfTUiHw",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Meetup Participant Registration & Giveaway App",
"tags": [],
"nodes": [
{
"id": "76bd011c-3ace-4094-8fa0-bac818192d9a",
"name": "Thank you screen",
"type": "n8n-nodes-base.form",
"position": [
620,
600
],
"parameters": {
"options": {
"customCss": ":root {\n\t--font-family: 'Inter', sans-serif;\n\t--font-weight-normal: 400;\n\t--font-weight-bold: 700;\n\t--font-size-body: 14px;\n\t--font-size-label: 16px;\n\t--font-size-header: 24px;\n\t--font-size-input: 16px;\n\t--font-size-error: 12px;\n\n\t/* Purple Themed Colors */\n\t--color-background: #f5f3ff; /* soft lavender */\n\t--color-card-bg: #ffffff;\n\t--color-card-border: #e0d7f8;\n\t--color-card-shadow: rgba(103, 80, 164, 0.12);\n\t--color-header: #3c1e74;\n\t--color-label: #4c1d95;\n\t--color-input-text: #1f1b2e;\n\t--color-input-border: #c4b5fd;\n\t--color-focus-border: #7c3aed;\n\t--color-submit-btn-bg: #7c3aed;\n\t--color-submit-btn-bg-hover: #6d28d9;\n\t--color-submit-btn-text: #ffffff;\n\t--color-error: #dc2626;\n\t--color-required: #dc2626;\n\t--color-test-notice-text: #7e22ce;\n\t--color-test-notice-bg: #f3e8ff;\n\t--color-test-notice-border: #e9d5ff;\n\n\t--border-radius-card: 12px;\n\t--border-radius-input: 8px;\n\t--submit-btn-height: 52px;\n\n\t--padding-card: 32px;\n\t--padding-form-input: 14px;\n\t--box-shadow-card: 0 8px 24px rgba(103, 80, 164, 0.15);\n}\n\n/* Body Background */\nbody {\n\tbackground-color: var(--color-background);\n\tfont-family: var(--font-family);\n\tmargin: 0;\n\tpadding: 0;\n\tcolor: var(--color-input-text);\n}\n\n/* Form Container Card */\n.card {\n\tmax-width: 480px;\n\tmargin: 40px auto;\n\tbackground-color: var(--color-card-bg);\n\tborder-radius: var(--border-radius-card);\n\tbox-shadow: var(--box-shadow-card);\n\tpadding: var(--padding-card);\n\tborder: 1px solid var(--color-card-border);\n}\n\n/* Header */\n.card h1 {\n\tfont-size: var(--font-size-header);\n\tfont-weight: var(--font-weight-bold);\n\tcolor: var(--color-header);\n\tmargin-bottom: 24px;\n\ttext-align: center;\n}\n\n/* Test Notice */\n.test-notice {\n\tbackground-color: var(--color-test-notice-bg);\n\tcolor: var(--color-test-notice-text);\n\tborder: 1px solid var(--color-test-notice-border);\n\tborder-radius: 6px;\n\tpadding: 12px 16px;\n\tfont-size: 14px;\n\tmargin-bottom: 24px;\n}\n\n/* Label */\nlabel {\n\tdisplay: block;\n\tfont-size: var(--font-size-label);\n\tfont-weight: var(--font-weight-bold);\n\tcolor: var(--color-label);\n\tmargin-bottom: 8px;\n}\n\n/* Input Field */\ninput[type=\"text\"], input[type=\"email\"] {\n\twidth: 100%;\n\tpadding: var(--padding-form-input);\n\tborder: 1px solid var(--color-input-border);\n\tborder-radius: var(--border-radius-input);\n\tfont-size: var(--font-size-input);\n\tcolor: var(--color-input-text);\n\tbox-sizing: border-box;\n\ttransition: border-color 0.2s ease;\n}\n\ninput[type=\"text\"]:focus, input[type=\"email\"]:focus {\n\tborder-color: var(--color-focus-border);\n\toutline: none;\n}\n\n/* Error Message */\n.error {\n\tcolor: var(--color-error);\n\tfont-size: var(--font-size-error);\n\tmargin-top: 6px;\n}\n\n/* Submit Button */\nbutton[type=\"submit\"] {\n\twidth: 100%;\n\theight: var(--submit-btn-height);\n\tbackground-color: var(--color-submit-btn-bg);\n\tcolor: var(--color-submit-btn-text);\n\tfont-weight: var(--font-weight-bold);\n\tfont-size: 16px;\n\tborder: none;\n\tborder-radius: 10px;\n\tcursor: pointer;\n\ttransition: background-color 0.2s ease;\n}\n\nbutton[type=\"submit\"]:hover {\n\tbackground-color: var(--color-submit-btn-bg-hover);\n}\n\n/* Required Asterisk */\nlabel .required {\n\tcolor: var(--color-required);\n\tmargin-left: 4px;\n}\n"
},
"operation": "completion",
"completionTitle": "Glad You're Here!",
"completionMessage": "Thank you for being part of our meetup. Don\u2019t miss the giveaway at the end of the session!"
},
"typeVersion": 1
},
{
"id": "dc0a7158-2b27-4a83-8fc0-e826ce425b7f",
"name": "Format participant list",
"type": "n8n-nodes-base.code",
"position": [
420,
1140
],
"parameters": {
"jsCode": "// Loop over input items and add a new field called 'myNewField' to the JSON of each one\nvar list = $input.all();\n\nfunction base64Encode(originalString) {\n // Create a Buffer from the string\n const buffer = Buffer.from(originalString, 'utf8');\n // Convert the Buffer to a Base64 string\n const encodedString = buffer.toString('base64');\n return encodedString;\n}\nfunction redactWhatsapp(number) {\n if (!number || number.length < 7) return number; // too short to redact safely\n const start = number.slice(0, 4);\n const end = number.slice(-4);\n return `${start}****${end}`;\n}\nvar newList = list.filter((r)=>{\n return !!r.json.nama_lengkap;\n}).map((row)=> {\n var data = row.json\n var name = data.nama_lengkap\n var whatsapp = redactWhatsapp(data.whatsapp)\n var label = name + ' (' +whatsapp+')'\n return label;\n})\n\nreturn {names: newList}"
},
"typeVersion": 2,
"alwaysOutputData": true
},
{
"id": "7fba3d0f-8c7b-4f19-8954-9b8ab7a6d95b",
"name": "Mapping form to database",
"type": "n8n-nodes-base.set",
"position": [
180,
600
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "8d91a9a0-84fa-47c6-a8b9-31b21bb25ab0",
"name": "nama_lengkap",
"type": "string",
"value": "={{ $json['Nama Lengkap'] }}"
},
{
"id": "3459b5c2-0c65-4684-a7f7-bcdb2aece4d5",
"name": "discord_username",
"type": "string",
"value": "={{ $json['Discord Username (yang join di discord channel)'] }}"
},
{
"id": "59ac4d04-3dee-4ccb-bd08-351f5529bd6b",
"name": "domisili_kota",
"type": "string",
"value": "={{ $json['Domisili (Kota)'] }}"
},
{
"id": "c0ac2b89-4d7b-4e79-87de-c7f58efcba1f",
"name": "bio",
"type": "string",
"value": "={{ $json['Bio (pekerjaan, specialty, dsb)'] }}"
},
{
"id": "7460a976-89e9-4d9c-8680-74ac823a6aca",
"name": "email",
"type": "string",
"value": "={{ $json.Email }}"
},
{
"id": "9018f12d-2aaf-4e9c-941c-9db53da5e83c",
"name": "whatsapp",
"type": "string",
"value": "={{ $json.Whatsapp }}"
},
{
"id": "483859a7-add4-46e5-a39d-d9199c86e59b",
"name": "threads_username",
"type": "string",
"value": "={{ $json['Threads Username'] }}"
},
{
"id": "9717df91-b9f1-4098-8eb3-6c97dfede3d7",
"name": "instagram_username",
"type": "string",
"value": "={{ $json['Instagram Username'] }}"
},
{
"id": "0d2fb350-61ec-4822-8dc5-c3ab9a20ce1c",
"name": "created_at",
"type": "string",
"value": "={{ $json.submittedAt }}"
},
{
"id": "32b9a3fa-0ef7-4a84-9adb-df25d112d4af",
"name": "event",
"type": "string",
"value": "={{ $json.Event }}"
},
{
"id": "8e2be506-a19b-4c0d-97c4-1fa73fe1546e",
"name": "id",
"type": "string",
"value": "={{ $json.Event }}--{{ $json.Whatsapp }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "6d66e53e-147c-42a8-a742-349901287c96",
"name": "Get all participants",
"type": "n8n-nodes-base.postgres",
"position": [
200,
1140
],
"parameters": {
"table": {
"__rl": true,
"mode": "list",
"value": "n8n_meetup_participants",
"cachedResultName": "n8n_meetup_participants"
},
"where": {
"values": [
{
"value": "Meetup #2",
"column": "event"
}
]
},
"schema": {
"__rl": true,
"mode": "list",
"value": "public"
},
"options": {},
"operation": "select",
"returnAll": true
},
"credentials": {
"postgres": {
"name": "<your credential>"
}
},
"typeVersion": 2.6,
"alwaysOutputData": true
},
{
"id": "8478dcf5-7e9c-471e-b7db-d7b601f4fd58",
"name": "Giveaway App",
"type": "n8n-nodes-base.webhook",
"position": [
-20,
1140
],
"parameters": {
"path": "giveaway-app",
"options": {},
"responseMode": "responseNode"
},
"typeVersion": 2
},
{
"id": "0df6e338-46ee-42fc-b2b8-4986e167f271",
"name": "Respond to Giveaway App",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
620,
1140
],
"parameters": {
"options": {},
"respondWith": "text",
"responseBody": "=<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"/>\n <title>n8n Meetup Name Picker</title>\n <style>\n body {\n font-family: 'Inter', sans-serif;\n background-color: #f5f3ff;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n min-height: 100vh;\n justify-content: center;\n }\n\n .container {\n background-color: #ffffff;\n border-radius: 12px;\n padding: 32px;\n max-width: 500px;\n width: 100%;\n box-shadow: 0 8px 24px rgba(103, 80, 164, 0.15);\n text-align: center;\n }\n\n h1 {\n color: #4c1d95;\n margin-bottom: 24px;\n }\n\n textarea {\n width: 100%;\n height: 150px;\n border: 1px solid #c4b5fd;\n border-radius: 8px;\n padding: 12px 20px 12px 16px;\n font-family: 'Inter', sans-serif;\n box-sizing: border-box;\n font-size: 14px;\n margin-bottom: 16px;\n resize: none;\n }\n\n input[type=\"number\"] {\n width: 60px;\n padding: 8px;\n margin: 8px 0;\n border-radius: 6px;\n border: 1px solid #c4b5fd;\n text-align: center;\n }\n\n button {\n background-color: #7c3aed;\n color: white;\n border: none;\n padding: 12px 24px;\n border-radius: 8px;\n font-size: 16px;\n cursor: pointer;\n margin-top: 12px;\n }\n\n button:hover {\n background-color: #6d28d9;\n }\n\n .results {\n margin-top: 24px;\n font-size: 18px;\n color: #1f1b2e;\n }\n\n .results li {\n margin: 4px 0;\n }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <h1>\ud83c\udf89 Giveaway <br/> N8N ID Meetup #2</h1>\n <div id=\"formSection\">\n <p>Paste the list of attendee names below (one per line):</p>\n <textarea id=\"nameInput\" placeholder=\"e.g. John Doe Jane Smith Andi Prasetyo\"></textarea>\n <p>Select how many names to pick:</p>\n <input type=\"number\" id=\"countInput\" value=\"5\" min=\"1\" />\n <br />\n <button onclick=\"pickNames()\">Pick Random Name(s)</button>\n </div>\n <div id=\"rollingSection\" style=\"display:none; margin-top:32px; text-align:center;\">\n <div id=\"rollingNames\" style=\"font-size:2rem; color:#7c3aed; min-height:2.5em; font-weight:bold;\"></div>\n <div id=\"rollingCount\" style=\"margin-top:8px; color:#6d28d9;\"></div>\n <button id=\"backButton\" style=\"display:none; margin-top:24px; background:#e0e7ff; color:#4c1d95; border:none; padding:10px 24px; border-radius:8px; font-size:15px; cursor:pointer;\" onclick=\"backToInput()\">Back to Input</button>\n </div>\n </div>\n\n <script src=\"https://cdn.jsdelivr.net/npm/canvas-confetti@1.6.0/dist/confetti.browser.min.js\"></script>\n\n <script>\n // Daftar nama peserta (bisa diubah sesuai kebutuhan)\n const predefinedNames = {{ JSON.stringify($json?.names || []) }}\n\n // Isi textarea dengan daftar nama saat halaman dimuat\n window.onload = function() {\n document.getElementById('nameInput').value = predefinedNames.join('\\n');\n };\n\n function pickNames() {\n const input = document.getElementById('nameInput').value.trim();\n const count = parseInt(document.getElementById('countInput').value);\n const resultsList = document.getElementById('resultsList');\n const formSection = document.getElementById('formSection');\n const rollingSection = document.getElementById('rollingSection');\n const rollingNames = document.getElementById('rollingNames');\n const rollingCount = document.getElementById('rollingCount');\n\n if (!input) {\n alert('Please enter at least one name.');\n return;\n }\n\n const names = input.split('\\n').map(name => name.trim()).filter(name => name !== '');\n\n if (count > names.length) {\n alert('Not enough names to pick from.');\n return;\n }\n\n // Sembunyikan form, tampilkan rolling\n formSection.style.display = 'none';\n rollingSection.style.display = 'block';\n\n // Rolling animation\n let rollingInterval;\n let rollingDuration = 2000; // ms\n let rollingSpeed = 60; // ms\n let rollingNamesArr = [];\n let rollingStep = 0;\n\n if (count === 1) {\n // Rolling satu nama\n rollingInterval = setInterval(() => {\n const randomName = names[Math.floor(Math.random() * names.length)];\n rollingNames.textContent = randomName;\n }, rollingSpeed);\n } else {\n // Rolling beberapa nama sekaligus\n rollingInterval = setInterval(() => {\n rollingNamesArr = [];\n let tempNames = [...names];\n for (let i = 0; i < count; i++) {\n if (tempNames.length === 0) break;\n const idx = Math.floor(Math.random() * tempNames.length);\n rollingNamesArr.push(tempNames[idx]);\n tempNames.splice(idx, 1);\n }\n rollingNames.innerHTML = rollingNamesArr.map(n => `<div>${n}</div>`).join('');\n }, rollingSpeed);\n }\n rollingCount.textContent = 'Picking winner...';\n\n setTimeout(() => {\n clearInterval(rollingInterval);\n // Pilih pemenang sebenarnya\n const shuffled = names.sort(() => 0.5 - Math.random());\n const selected = shuffled.slice(0, count);\n rollingNames.innerHTML = selected.map(n => `<div style=\\\"color:#22c55e;\\\">${n}</div>`).join('');\n rollingCount.textContent = 'Winner' + (count > 1 ? 's' : '') + ' \ud83c\udf89';\n\n // Tampilkan confetti\n confetti({\n particleCount: 120,\n spread: 90,\n origin: { y: 0.6 }\n });\n\n document.getElementById('backButton').style.display = 'inline-block';\n }, rollingDuration);\n }\n\n function backToInput() {\n document.getElementById('formSection').style.display = 'block';\n document.getElementById('rollingSection').style.display = 'none';\n document.getElementById('backButton').style.display = 'none';\n document.getElementById('resultsList').innerHTML = '';\n document.getElementById('rollingNames').textContent = '';\n document.getElementById('rollingCount').textContent = '';\n }\n </script>\n</body>\n</html>\n"
},
"typeVersion": 1.4
},
{
"id": "99f96a32-d847-43f7-8740-cff828d7b314",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1500,
420
],
"parameters": {
"width": 660,
"height": 520,
"content": "# \ud83c\udf89 n8n Workflow: Meetup Participant Registration & Giveaway App\n\nThis n8n workflow is designed to handle both the participant registration process and the random selection of giveaway winners via a frontend integration.\n\n## \u2705 Use Case Summary\n\n- Efficiently collects and stores attendee information\n- Securely exposes a simplified participant list to the frontend\n- Prepares giveaway-ready data with privacy protection\n- Perfect for community events or randomized prize draws\n\n"
},
"typeVersion": 1
},
{
"id": "cf039ad9-01ee-4484-ae3d-d0225227da32",
"name": "Participant Form",
"type": "n8n-nodes-base.formTrigger",
"position": [
-40,
600
],
"parameters": {
"options": {
"path": "giveaway-form",
"customCss": ":root {\n\t--font-family: 'Inter', sans-serif;\n\t--font-weight-normal: 400;\n\t--font-weight-bold: 700;\n\t--font-size-body: 14px;\n\t--font-size-label: 16px;\n\t--font-size-header: 24px;\n\t--font-size-input: 16px;\n\t--font-size-error: 12px;\n\n\t/* Purple Themed Colors */\n\t--color-background: #f5f3ff; /* soft lavender */\n\t--color-card-bg: #ffffff;\n\t--color-card-border: #e0d7f8;\n\t--color-card-shadow: rgba(103, 80, 164, 0.12);\n\t--color-header: #3c1e74;\n\t--color-label: #4c1d95;\n\t--color-input-text: #1f1b2e;\n\t--color-input-border: #c4b5fd;\n\t--color-focus-border: #7c3aed;\n\t--color-submit-btn-bg: #7c3aed;\n\t--color-submit-btn-bg-hover: #6d28d9;\n\t--color-submit-btn-text: #ffffff;\n\t--color-error: #dc2626;\n\t--color-required: #dc2626;\n\t--color-test-notice-text: #7e22ce;\n\t--color-test-notice-bg: #f3e8ff;\n\t--color-test-notice-border: #e9d5ff;\n\n\t--border-radius-card: 12px;\n\t--border-radius-input: 8px;\n\t--submit-btn-height: 52px;\n\n\t--padding-card: 32px;\n\t--padding-form-input: 14px;\n\t--box-shadow-card: 0 8px 24px rgba(103, 80, 164, 0.15);\n}\n\n/* Body Background */\nbody {\n\tbackground-color: var(--color-background);\n\tfont-family: var(--font-family);\n\tmargin: 0;\n\tpadding: 0;\n\tcolor: var(--color-input-text);\n}\n\n/* Form Container Card */\n.card {\n\tmax-width: 480px;\n\tmargin: 40px auto;\n\tbackground-color: var(--color-card-bg);\n\tborder-radius: var(--border-radius-card);\n\tbox-shadow: var(--box-shadow-card);\n\tpadding: var(--padding-card);\n\tborder: 1px solid var(--color-card-border);\n}\n\n/* Header */\n.card h1 {\n\tfont-size: var(--font-size-header);\n\tfont-weight: var(--font-weight-bold);\n\tcolor: var(--color-header);\n\tmargin-bottom: 24px;\n\ttext-align: center;\n}\n\n/* Test Notice */\n.test-notice {\n\tbackground-color: var(--color-test-notice-bg);\n\tcolor: var(--color-test-notice-text);\n\tborder: 1px solid var(--color-test-notice-border);\n\tborder-radius: 6px;\n\tpadding: 12px 16px;\n\tfont-size: 14px;\n\tmargin-bottom: 24px;\n}\n\n/* Label */\nlabel {\n\tdisplay: block;\n\tfont-size: var(--font-size-label);\n\tfont-weight: var(--font-weight-bold);\n\tcolor: var(--color-label);\n\tmargin-bottom: 8px;\n}\n\n/* Input Field */\ninput[type=\"text\"], input[type=\"email\"] {\n\twidth: 100%;\n\tpadding: var(--padding-form-input);\n\tborder: 1px solid var(--color-input-border);\n\tborder-radius: var(--border-radius-input);\n\tfont-size: var(--font-size-input);\n\tcolor: var(--color-input-text);\n\tbox-sizing: border-box;\n\ttransition: border-color 0.2s ease;\n}\n\ninput[type=\"text\"]:focus, input[type=\"email\"]:focus {\n\tborder-color: var(--color-focus-border);\n\toutline: none;\n}\n\n/* Error Message */\n.error {\n\tcolor: var(--color-error);\n\tfont-size: var(--font-size-error);\n\tmargin-top: 6px;\n}\n\n/* Submit Button */\nbutton[type=\"submit\"] {\n\twidth: 100%;\n\theight: var(--submit-btn-height);\n\tbackground-color: var(--color-submit-btn-bg);\n\tcolor: var(--color-submit-btn-text);\n\tfont-weight: var(--font-weight-bold);\n\tfont-size: 16px;\n\tborder: none;\n\tborder-radius: 10px;\n\tcursor: pointer;\n\ttransition: background-color 0.2s ease;\n}\n\nbutton[type=\"submit\"]:hover {\n\tbackground-color: var(--color-submit-btn-bg-hover);\n}\n\n/* Required Asterisk */\nlabel .required {\n\tcolor: var(--color-required);\n\tmargin-left: 4px;\n}\n",
"ignoreBots": true,
"buttonLabel": "Submit",
"appendAttribution": false
},
"formTitle": "n8n Indonesia Community Meetup #2",
"formFields": {
"values": [
{
"fieldName": "Event",
"fieldType": "hiddenField",
"fieldValue": "=Meetup #2"
},
{
"fieldLabel": "Nama Lengkap",
"requiredField": true
},
{
"fieldLabel": "Domisili (Kota)",
"requiredField": true
},
{
"fieldType": "textarea",
"fieldLabel": "Bio (pekerjaan, specialty, dsb)",
"requiredField": true
},
{
"fieldLabel": "Whatsapp",
"requiredField": true
},
{
"fieldLabel": "Discord Username (yang join di discord channel)"
},
{
"fieldLabel": "Threads Username"
},
{
"fieldLabel": "Instagram Username"
},
{
"fieldType": "email",
"fieldLabel": "Email"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "d1387478-3489-4d10-b2a0-910eda73469c",
"name": "Save Participant to Database",
"type": "n8n-nodes-base.postgres",
"position": [
400,
600
],
"parameters": {
"table": {
"__rl": true,
"mode": "list",
"value": "n8n_meetup_participants",
"cachedResultName": "n8n_meetup_participants"
},
"schema": {
"__rl": true,
"mode": "list",
"value": "public"
},
"columns": {
"value": {},
"schema": [
{
"id": "id",
"type": "string",
"display": true,
"removed": false,
"required": true,
"displayName": "id",
"defaultMatch": true,
"canBeUsedToMatch": true
},
{
"id": "nama_lengkap",
"type": "string",
"display": true,
"required": true,
"displayName": "nama_lengkap",
"defaultMatch": false,
"canBeUsedToMatch": false
},
{
"id": "discord_username",
"type": "string",
"display": true,
"required": false,
"displayName": "discord_username",
"defaultMatch": false,
"canBeUsedToMatch": false
},
{
"id": "domisili_kota",
"type": "string",
"display": true,
"required": false,
"displayName": "domisili_kota",
"defaultMatch": false,
"canBeUsedToMatch": false
},
{
"id": "bio",
"type": "string",
"display": true,
"required": false,
"displayName": "bio",
"defaultMatch": false,
"canBeUsedToMatch": false
},
{
"id": "email",
"type": "string",
"display": true,
"required": false,
"displayName": "email",
"defaultMatch": false,
"canBeUsedToMatch": false
},
{
"id": "whatsapp",
"type": "string",
"display": true,
"required": false,
"displayName": "whatsapp",
"defaultMatch": false,
"canBeUsedToMatch": false
},
{
"id": "threads_username",
"type": "string",
"display": true,
"required": false,
"displayName": "threads_username",
"defaultMatch": false,
"canBeUsedToMatch": false
},
{
"id": "instagram_username",
"type": "string",
"display": true,
"required": false,
"displayName": "instagram_username",
"defaultMatch": false,
"canBeUsedToMatch": false
},
{
"id": "created_at",
"type": "dateTime",
"display": true,
"required": false,
"displayName": "created_at",
"defaultMatch": false,
"canBeUsedToMatch": false
},
{
"id": "event",
"type": "string",
"display": true,
"required": false,
"displayName": "event",
"defaultMatch": false,
"canBeUsedToMatch": false
}
],
"mappingMode": "autoMapInputData",
"matchingColumns": [
"id"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "upsert"
},
"credentials": {
"postgres": {
"name": "<your credential>"
}
},
"typeVersion": 2.6
},
{
"id": "7222a521-913f-4326-84c3-8b84e1d07735",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-800,
420
],
"parameters": {
"color": 6,
"width": 1660,
"height": 520,
"content": "\n## \ud83d\udccb Participant Registration Flow\n\nThis part of the workflow handles user submissions from a registration form.\n\n### \ud83d\udd04 Steps:\n1. **\ud83d\udcdd Participant Form**\n - Triggered when a participant submits the form.\n - Collects fields like `nama_lengkap`, `email`, `whatsapp`, `discord_username`, etc.\n\n2. **\ud83d\udee0\ufe0f Mapping Form to Database**\n - Manual mapping node that prepares form data for the database.\n - Can include trimming, validation, and formatting.\n\n3. **\ud83d\udcbe Save Participant to Database**\n - Uses an *upsert* operation to insert or update records in PostgreSQL.\n - Avoids duplicate entries based on `id`.\n\n4. **\u2705 Thank You Screen**\n - Displays a confirmation or success message to the participant after submission.\n"
},
"typeVersion": 1
},
{
"id": "0562529e-7a41-4a25-a949-87fed3007814",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-800,
980
],
"parameters": {
"color": 5,
"width": 1660,
"height": 480,
"content": "## \ud83c\udf81 Giveaway App\n\nThis section serve frontend app to display and select random winners.\n\n### \ud83d\udd04 Steps:\n1. **\ud83c\udf10 Webhook GET (Giveaway App)**\n - Exposes a public endpoint that delivers a ready-to-use HTML app.\n - Can be opened in a browser or projected during the event.\n\n2. **\ud83d\udce5 Fetch Participants**\n - Executes a SQL query to retrieve all participant records from the database.\n\n3. **\ud83e\uddee Format Participant Data**\n - Redacts personal details (e.g., masks WhatsApp numbers).\n - Encodes the `id` using Base64 for privacy and uniqueness.\n\n4. **\ud83d\udce4 Render Giveaway App**\n - Returns an HTML-based Single Page Application with the participant list included.\n - Allows the host to click a button to pick random winners live."
},
"typeVersion": 1
},
{
"id": "f166d098-c4c9-470f-9bb2-afbf7e9df119",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1500,
980
],
"parameters": {
"width": 660,
"height": 480,
"content": "# Preview\n"
},
"typeVersion": 1
}
],
"active": true,
"settings": {
"executionOrder": "v1"
},
"versionId": "48aa9f48-68b4-4434-99d4-376949171f6f",
"connections": {
"Giveaway App": {
"main": [
[
{
"node": "Get all participants",
"type": "main",
"index": 0
}
]
]
},
"Participant Form": {
"main": [
[
{
"node": "Mapping form to database",
"type": "main",
"index": 0
}
]
]
},
"Get all participants": {
"main": [
[
{
"node": "Format participant list",
"type": "main",
"index": 0
}
]
]
},
"Format participant list": {
"main": [
[
{
"node": "Respond to Giveaway App",
"type": "main",
"index": 0
}
]
]
},
"Mapping form to database": {
"main": [
[
{
"node": "Save Participant to Database",
"type": "main",
"index": 0
}
]
]
},
"Save Participant to Database": {
"main": [
[
{
"node": "Thank you screen",
"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.
postgres
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow contains community nodes that are only compatible with the self-hosted version of n8n.
Source: https://n8n.io/workflows/5758/ — 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.
This solution enables you to manage all your Notion and Todoist tasks from different workspaces as well as your calendar events in a single place. This is 2 way sync with partial support for recurring
Scraping. Uses httpRequest, postgres, @apify/n8n-nodes-apify, respondToWebhook. Webhook trigger; 61 nodes.
Workflow B — AI Listing Engine. Uses httpRequest, postgres, errorTrigger. Webhook trigger; 47 nodes.
This workflow automates data maturity evaluation to measure how well an organization uses data to create value by capturing assessment data through forms or APIs, processing and scoring responses usin