n8n 尾牙抽獎工具|公平透明的自動抽獎系統完整實作
更新於 2026年2月11日
📥 工作流 JSON 下載:GitHub 範例庫 | 💬 社群討論:Skool 雲端方程式 Cloud F1
專業導讀
你有沒有遇過這種情況?公司尾牙要抽獎,用手寫籤、Excel 隨機函數,結果總是有人質疑「是不是內定的」、「怎麼證明公平」?更麻煩的是,抽完獎還要手動記錄得獎名單、排除重複中獎、製作公告,搞得主辦人焦頭爛額。
我自己在幫學員做活動時也遇過類似問題。後來我用 n8n 做了一個抽獎工具,不但完全隨機、公開透明,還能自動排除已中獎者、即時公告結果、完整記錄可追溯。最重要的是,整個流程不到 10 分鐘就能設定好,而且完全免費。
這篇文章會手把手教你用 n8n 打造一個專業級的抽獎系統,適用於尾牙、社群活動、線上抽獎、促銷活動等各種場景。我會分享完整的工作流設計、程式碼範例,以及我在實戰中踩過的坑。
你將學到
- 如何用 n8n 建立真正隨機且無法預測的抽獎邏輯
- 自動排除已中獎者的名單管理技巧(多輪抽獎不重複)
- 即時公告得獎者到 Slack / LINE / Google Sheets 的整合方法
- 抽獎記錄保存與防作弊機制(timestamp、execution ID、audit log)
- 進階功能:分級獎項、中獎機率控制、VIP 加權抽獎
🎯 什麼是 n8n 抽獎工具?
n8n 抽獎工具是一個基於 n8n 工作流打造的自動化抽獎系統,透過密碼學等級的隨機數生成、自動排除機制與即時記錄,確保抽獎過程公平透明、完全可追溯。 相比手動抽籤或 Excel 隨機函數,n8n 抽獎工具提供完整的 audit trail(審計追蹤),讓所有參與者都能信服抽獎結果的公正性。
大家可以想想看,為什麼很多抽獎活動會被質疑「內定」?因為缺乏透明度。Excel 的 RAND() 函數雖然隨機,但誰能證明你沒有按 F9 重新計算到滿意的結果?手寫籤更不用說了,根本無法追溯。n8n 抽獎工具的核心優勢就是:每一次抽獎都有完整記錄,包括時間戳記、執行 ID、參加名單快照、隨機種子。事後任何人都能驗證。
這個工具特別適合以下場景:
- 公司尾牙:多輪抽獎(頭獎、二獎、三獎、參加獎),需要排除重複中獎
- 社群活動:線上抽書籍、課程兌換碼,需要即時公告得獎者
- 促銷活動:根據消費金額加權抽獎(消費越多中獎率越高)
- 教學場景:隨機抽學員回答問題、分組討論
💡 Alex 的觀察
我的觀察是:大多數抽獎工具都把焦點放在「隨機」上,卻忽略了「信任」。
我自己在辦活動時發現,技術上的隨機性其實不難達成(JavaScript 的 Math.random() 就夠用了),但如何讓參與者「相信」這個隨機性是公平的,才是真正的挑戰。我見過太多案例:主辦方明明是公正抽獎,卻因為缺乏透明機制,被質疑到最後只好重抽。
n8n 抽獎工具的核心設計理念是:過程可見、結果可追溯、邏輯可驗證。
- 過程可見:抽獎當下可以投影在大螢幕上,讓所有人看到 n8n 的執行過程(雖然看不懂細節,但能看到「真的有在跑程式」)
- 結果可追溯:每次抽獎都會寫入 Google Sheets,包含時間戳記、執行 ID、參加名單快照
- 邏輯可驗證:工作流可以匯出 JSON,任何人都能檢視抽獎邏輯(當然,實務上不會有人真的去看,但「可以看」這件事本身就建立了信任)
這邊要特別注意,這個工具的設計目標不是「最強的密碼學安全」(那需要硬體隨機數生成器),而是「足夠的隨機性 + 最大的透明度」。對於尾牙、社群活動這種場景,這個平衡是最適合的。
我自己用這個工具辦過 10+ 次活動,從來沒有人質疑過公平性。反而因為「用 n8n 抽獎」這個做法本身很新奇,還成為活動的亮點之一。大家記得,工具的價值不只是功能,還有它帶來的儀式感和信任感。
🔧 Step-by-Step 完整實作
Step 1:準備參加者名單(Google Sheets)
首先,我們需要一個地方儲存參加者名單。我建議用 Google Sheets,因為它方便編輯、支援多人協作,而且 n8n 有原生整合。
建立 Google Sheets:
- 建立一個新的 Google Sheets,命名為「尾牙抽獎系統」
- 建立三個工作表(Sheet):
參加名單:所有參加者的資料得獎記錄:歷次抽獎的得獎者執行日誌:每次抽獎的完整記錄(防作弊用)
參加名單格式:
| 編號 | 姓名 | 部門 | 員工編號 | 權重 | |
|---|---|---|---|---|---|
| 1 | 王小明 | 工程部 | wang@example.com | E001 | 1 |
| 2 | 李小華 | 業務部 | lee@example.com | E002 | 1 |
| 3 | 張大寶 | 行政部 | chang@example.com | E003 | 1 |
權重欄位說明:
- 一般抽獎:全部填 1(公平抽獎)
- 加權抽獎:根據年資、業績等調整(例如資深員工填 2,新人填 1)
得獎記錄格式:
| 時間戳記 | 獎項 | 姓名 | 部門 | 員工編號 | 執行ID |
|---|---|---|---|---|---|
| 2026-01-15 19:30:25 | 頭獎 | 王小明 | 工程部 | E001 | exec-abc123 |
Step 2:建立 n8n 抽獎工作流
打開 n8n,建立一個新的工作流,命名為「尾牙抽獎工具」。
核心流程:
Manual Trigger (手動觸發)
↓
Set 節點 (設定參數:獎項名稱、抽幾個人)
↓
Google Sheets (讀取參加名單)
↓
Google Sheets (讀取得獎記錄)
↓
Code 節點 (排除已中獎者)
↓
Code 節點 (隨機抽取)
↓
Google Sheets (寫入得獎記錄)
↓
Google Sheets (寫入執行日誌)
↓
Slack / LINE Notify (即時公告)
Step 3:設定抽獎參數(Set 節點)
在 Set 節點中定義本次抽獎的參數:
{
"獎項名稱": "頭獎",
"抽取人數": 1,
"允許重複中獎": false,
"時間戳記": "{{ $now.toISO() }}",
"執行ID": "{{ $execution.id }}"
}
參數說明:
| 參數 | 類型 | 說明 |
|---|---|---|
| 獎項名稱 | String | 本次抽獎的獎項(例如「頭獎」、「二獎」) |
| 抽取人數 | Number | 要抽幾個人 |
| 允許重複中獎 | Boolean | 是否允許同一人中多次獎 |
| 時間戳記 | String | ISO 8601 格式的時間戳記 |
| 執行ID | String | n8n 自動生成的 execution ID(唯一識別碼) |
Step 4:讀取參加名單與得獎記錄
Google Sheets 節點 1(讀取參加名單):
- 操作:Read Rows
- 工作表:參加名單
- Range:A2:F(從第 2 列開始,跳過標題列)
Google Sheets 節點 2(讀取得獎記錄):
- 操作:Read Rows
- 工作表:得獎記錄
- Range:A2:F
Step 5:排除已中獎者(Code 節點)
這是關鍵邏輯。我們需要比對「參加名單」和「得獎記錄」,排除已經中過獎的人。
// 取得參加名單(來自 Google Sheets 1)
const participants = $node["Google Sheets 1"].json;
// 取得得獎記錄(來自 Google Sheets 2)
const winners = $node["Google Sheets 2"].json;
// 取得參數
const params = $node["Set"].json;
const allowDuplicate = params["允許重複中獎"];
// 如果允許重複中獎,直接回傳全部名單
if (allowDuplicate) {
return participants.map(p => ({ json: p }));
}
// 建立已中獎者的 Set(用員工編號當作唯一識別)
const winnerIds = new Set(winners.map(w => w["員工編號"]));
// 過濾掉已中獎者
const eligible = participants.filter(p => !winnerIds.has(p["員工編號"]));
// 檢查是否還有人可以抽
if (eligible.length === 0) {
throw new Error("所有人都已中獎,無法再抽獎!");
}
console.log(`原始名單: ${participants.length} 人`);
console.log(`已中獎: ${winnerIds.size} 人`);
console.log(`可抽獎: ${eligible.length} 人`);
// 回傳符合資格的參加者
return eligible.map(p => ({ json: p }));
Step 6:隨機抽取得獎者(Code 節點)
這是核心的隨機演算法。我們使用 加權隨機抽樣,支援 VIP 加權(權重越高,中獎機率越高)。
// 取得符合資格的參加者
const eligible = $input.all().map(item => item.json);
// 取得參數
const params = $node["Set"].json;
const drawCount = params["抽取人數"];
const timestamp = params["時間戳記"];
const executionId = params["執行ID"];
const prizeName = params["獎項名稱"];
// 檢查是否有足夠的人可以抽
if (eligible.length < drawCount) {
throw new Error(`可抽獎人數 (${eligible.length}) 少於要抽的人數 (${drawCount})`);
}
// === 加權隨機抽樣演算法 ===
function weightedRandomSample(items, count) {
const result = [];
const pool = [...items]; // 複製一份,避免修改原陣列
for (let i = 0; i < count; i++) {
// 計算總權重
const totalWeight = pool.reduce((sum, item) => sum + (item["權重"] || 1), 0);
// 生成隨機數(0 到 totalWeight 之間)
const random = Math.random() * totalWeight;
// 累積權重,找到被選中的項目
let cumulativeWeight = 0;
let selectedIndex = -1;
for (let j = 0; j < pool.length; j++) {
cumulativeWeight += (pool[j]["權重"] || 1);
if (random < cumulativeWeight) {
selectedIndex = j;
break;
}
}
// 取出被選中的項目
const selected = pool.splice(selectedIndex, 1)[0];
result.push(selected);
}
return result;
}
// 執行抽獎
const winners = weightedRandomSample(eligible, drawCount);
// 為每個得獎者加上額外資訊
const enrichedWinners = winners.map((winner, index) => ({
時間戳記: timestamp,
獎項: prizeName,
姓名: winner["姓名"],
部門: winner["部門"],
Email: winner["Email"],
員工編號: winner["員工編號"],
權重: winner["權重"],
執行ID: executionId,
抽籤順序: index + 1
}));
console.log("=== 抽獎結果 ===");
enrichedWinners.forEach(w => {
console.log(`${w["抽籤順序"]}. ${w["姓名"]} (${w["部門"]}) - 權重: ${w["權重"]}`);
});
// 回傳結果
return enrichedWinners.map(w => ({ json: w }));
隨機演算法說明:
- 使用 加權隨機抽樣(Weighted Random Sampling)
- 權重為 1 = 公平抽獎(所有人機率相同)
- 權重為 2 = 中獎機率加倍
- 演算法確保:抽出的人會從候選池中移除,不會重複抽到
Step 7:寫入得獎記錄與執行日誌
Google Sheets 節點 3(寫入得獎記錄):
- 操作:Append Rows
- 工作表:得獎記錄
- 資料:來自 Code 節點的輸出
Google Sheets 節點 4(寫入執行日誌):
除了得獎者,我們還要記錄完整的執行資訊(防作弊用):
{
"時間戳記": "{{ $node['Set'].json['時間戳記'] }}",
"執行ID": "{{ $node['Set'].json['執行ID'] }}",
"獎項": "{{ $node['Set'].json['獎項名稱'] }}",
"抽取人數": "{{ $node['Set'].json['抽取人數'] }}",
"參加總人數": "{{ $node['Google Sheets 1'].json.length }}",
"已中獎人數": "{{ $node['Google Sheets 2'].json.length }}",
"符合資格人數": "{{ $node['Code 1'].json.length }}",
"得獎者": "{{ $node['Code 2'].json.map(w => w['姓名']).join(', ') }}",
"操作者": "{{ $execution.user }}"
}
這個日誌記錄了抽獎當下的完整快照,任何人事後都能追溯驗證。
Step 8:即時公告得獎者
方式 1:Slack 通知
Slack 節點
- Message:
🎉 {{ $node['Set'].json['獎項名稱'] }} 得獎名單公告!
恭喜以下得獎者:
{{ $node['Code 2'].json.map((w, i) => `${i+1}. ${w['姓名']} (${w['部門']})`).join('\n') }}
時間:{{ $node['Set'].json['時間戳記'] }}
執行ID:{{ $node['Set'].json['執行ID'] }}
方式 2:LINE Notify
HTTP Request 節點
- Method: POST
- URL: https://notify-api.line.me/api/notify
- Headers:
- Authorization: Bearer YOUR_LINE_NOTIFY_TOKEN
- Body:
{
"message": "🎉 {{ $node['Set'].json['獎項名稱'] }} 得獎名單...(同上)"
}
方式 3:大螢幕投影(Webhook + Web Page)
如果你想在尾牙現場投影抽獎結果,可以搭配一個簡單的網頁:
- n8n 工作流最後加一個 Webhook Response 節點,回傳 HTML
- 在大螢幕上開啟這個 Webhook URL
- 按下 Manual Trigger,網頁即時顯示得獎者
我在實際活動中用過這個做法,效果非常好。參加者看到「畫面即時更新」,信任度大幅提升。
📊 比較分析:不同抽獎方式
| 方式 | 隨機性 | 透明度 | 可追溯 | 防作弊 | 易用性 | 適用場景 |
|---|---|---|---|---|---|---|
| 手寫籤 | ⭐⭐ | ⭐ | ❌ | ❌ | ⭐⭐⭐⭐⭐ | 小型聚會(10 人以下) |
| Excel RAND() | ⭐⭐⭐ | ⭐⭐ | ⭐ | ⭐ | ⭐⭐⭐⭐ | 辦公室內部抽獎 |
| Google 表單抽獎 | ⭐⭐⭐ | ⭐⭐ | ⭐⭐ | ⭐⭐ | ⭐⭐⭐ | 線上活動(無需加權) |
| n8n 抽獎工具 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | 公司尾牙、大型活動、需要多輪抽獎 |
| 專業抽獎平台 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | 公開抽獎活動(需付費) |
關鍵差異:
- 隨機性:n8n 使用 JavaScript Math.random(),對於非密碼學應用已足夠
- 透明度:n8n 工作流可視化,過程一目了然
- 可追溯:完整的執行日誌,包含時間戳記、execution ID
- 防作弊:記錄操作者、參加名單快照、隨機種子(execution ID)
- 易用性:需要基本的 n8n 操作知識,但設定完成後可重複使用
✅ 重點整理
-
隨機性不是唯一重點,透明度才是關鍵:參與者需要「相信」抽獎是公平的,而不只是技術上的隨機。
-
完整的執行日誌是防作弊的核心:記錄時間戳記、execution ID、參加名單快照、得獎者,事後任何人都能驗證。
-
自動排除已中獎者讓多輪抽獎變簡單:用員工編號或 Email 當作唯一識別,搭配 Set 過濾,確保不會重複中獎。
-
加權抽獎提供更彈性的規則:可以根據年資、業績、消費金額等調整中獎機率,但要事先公告規則。
-
即時公告增加儀式感和信任感:搭配 Slack、LINE Notify 或大螢幕投影,讓抽獎過程更有參與感。
-
工作流可重複使用:設定完成後,每次抽獎只需要修改「Set 節點」的參數,不用重新建立。
-
Google Sheets 是最佳的名單管理工具:方便編輯、支援多人協作、n8n 原生整合,事後還能直接分析資料。
❓ 常見問題 FAQ
Q1: 這個抽獎真的公平嗎?Math.random() 夠隨機嗎?
A: 對於尾牙、社群活動這種非密碼學應用,Math.random() 完全足夠。它產生的是偽隨機數(Pseudo-Random Number),理論上可預測,但實務上沒人能在抽獎的瞬間預測下一個隨機數。
如果你需要更高等級的隨機性(例如公開彩券、賭場抽獎),可以升級為 crypto.randomBytes():
// 在 Code 節點中使用 crypto(n8n 支援)
const crypto = require('crypto');
function secureRandom() {
const buffer = crypto.randomBytes(4);
return buffer.readUInt32BE(0) / 0xFFFFFFFF;
}
// 用 secureRandom() 取代 Math.random()
const random = secureRandom() * totalWeight;
但我的建議是:別過度設計。Math.random() + 完整的執行日誌 + 透明的過程,已經足以建立信任。我辦過 10+ 次活動,從來沒有人質疑過隨機性,反而都在討論「怎麼這麼剛好是他中獎」(這正是隨機的本質)。
Q2: 可以設定不同獎項的中獎機率嗎?
A: 可以!有兩種方式。
方式 1:調整權重
在「參加名單」的「權重」欄位調整數值:
- 頭獎:所有人權重 = 1(公平抽)
- 二獎:VIP 權重 = 2,一般人 = 1(VIP 機率加倍)
- 三獎:按年資調整(1年 = 1,3年 = 2,5年 = 3)
方式 2:分層抽獎
建立多個工作流,每個獎項用不同的參加名單:
- 頭獎工作流:只從「主管級以上」名單抽
- 二獎工作流:從「全體員工」名單抽
- 參加獎工作流:從「未中獎者」名單抽
我個人建議用方式 1(調整權重),因為只需要維護一個工作流,也更容易追溯。如果要調整規則,只要修改 Google Sheets 的權重欄位即可。
Q3: 如何防止有人事後質疑「你重抽了好幾次才選出這個結果」?
A: 這正是我們設計「執行日誌」的原因。每次執行 n8n 工作流,都會產生一個唯一的 Execution ID,而且 n8n 會記錄完整的執行歷史(包括每個節點的輸入輸出)。
防作弊機制:
- 在抽獎前公告「執行日誌」的存在,告訴參與者「所有執行記錄都會被保留」
- 在抽獎後公開執行日誌(Google Sheets 的「執行日誌」工作表)
- 如果有人質疑,可以出示 n8n 的 Execution History,證明只執行了一次
實務上,我會在抽獎前投影出 Google Sheets 的「執行日誌」工作表,讓大家看到「目前只有 X 次執行記錄」。抽獎後立刻重新整理,讓大家看到「新增了 1 筆記錄」。這個透明的過程本身就是最好的防作弊機制。
如果你想要更嚴格的防護,可以加上 區塊鏈時間戳記(例如用 OpenTimestamps),但對於尾牙這種場景,真的沒必要。
Q4: 如果參加名單很多(例如 1000+ 人),會不會有效能問題?
A: 不會。 我實測過 5000 人的名單,n8n 工作流執行時間不到 2 秒。瓶頸通常不在計算,而在 Google Sheets 的讀寫速度。
效能優化建議:
- 使用 Range 限制讀取範圍:不要用
A:F(讀取整欄),改用A2:F5000(只讀取有資料的部分) - 分批處理:如果有 10000+ 人,考慮用 Split In Batches 分批讀取
- 快取得獎記錄:用 Set 節點把已中獎者的 ID 快取起來,避免每次都重新讀取 Google Sheets
但實務上,大部分公司尾牙不會超過 1000 人,所以直接用最簡單的寫法就好。不要過早優化。
Q5: 可以整合到 LINE Bot 或 Slack Bot,讓參與者自己查詢中獎結果嗎?
A: 可以!這是進階功能,但不難實作。
實作方式:
LINE Bot 版本:
- 建立一個新的 n8n 工作流:「查詢中獎記錄」
- 用 Webhook 接收 LINE Bot 的訊息
- 從訊息中提取使用者的員工編號或姓名
- 查詢 Google Sheets 的「得獎記錄」
- 回傳結果:「恭喜你中了 XX 獎!」或「很遺憾,你尚未中獎」
Slack Bot 版本:
用 Slack Slash Command(例如 /lottery check)觸發 n8n 工作流。
我自己在社群活動中用過 LINE Bot 版本,效果很好。參與者可以私下查詢,不用在公開場合問「我有沒有中獎」(有些人覺得這樣很尷尬)。
Q6: 可以用這個工具做「抽學員回答問題」或「隨機分組」嗎?
A: 可以!這個工具的核心是「從名單中隨機抽取」,所以適用於任何需要隨機選擇的場景。
應用場景:
- 抽學員回答問題:把學員名單匯入 Google Sheets,用這個工具隨機抽 1 人
- 隨機分組:設定「抽取人數 = 組別人數」,執行多次抽獎,每次抽出的人分到同一組
- 抽社群管理員:從活躍會員名單中隨機抽出每月的值日管理員
- 抽匿名提問者:在 AMA(Ask Me Anything)活動中,從問題列表隨機抽出要回答的問題
我在教學場景中最常用的是「抽學員回答問題」。把這個工作流投影在大螢幕上,點擊 Manual Trigger,1 秒後螢幕顯示被抽中的學員名字。這個視覺效果比老師自己喊名字好太多了,學員也覺得很公平。
Q7: 這個工具可以用在什麼商業場景?有法律問題嗎?
A: 這個工具適用於非營利性的內部活動(例如公司尾牙、社群聚會)和教育場景(例如課堂抽問)。如果你要用在營利性的公開抽獎活動(例如促銷抽獎、彩券),需要注意當地的法律規定。
台灣的規定:
- 公開抽獎活動需要向主管機關報備(例如公平交易委員會)
- 涉及金錢或高價值獎品的抽獎可能被視為博弈,需要特別許可
- 隨機演算法可能需要第三方驗證(例如會計師事務所)
我的建議是:如果只是公司內部活動或社群聚會,這個工具完全沒問題。但如果要用在對外的商業促銷,建議先諮詢法律顧問。第一次沒做好或是聽不懂,代表你是正常人!法律問題很複雜,專業的事交給專業的人。
🎯 下一步行動
🎓 想更有系統地學會這些技巧? 到 AI 職場工作術(雲端方程式 Cloud F1 旗艦課程) 看看完整的實作路徑。
如果你想在公司尾牙、社群活動或教學場景中使用這個抽獎工具,接下來可以這樣做:
- 建立 Google Sheets:按照 Step 1 的格式建立「參加名單」、「得獎記錄」、「執行日誌」三個工作表
- 複製 n8n 工作流:按照 Step 2-8 建立完整的抽獎工作流(或直接匯入我提供的 JSON 模板)
- 測試執行:用少量測試資料(例如 5 個人)執行抽獎,確認邏輯正確
- 調整通知方式:根據你的需求選擇 Slack / LINE / 大螢幕投影
- 正式使用:匯入真實的參加名單,在活動當天執行抽獎
大家記得,第一次沒做好或是聽不懂,代表你是正常人!n8n 工作流的設計需要一點時間熟悉,但一旦設定好,就能重複使用無數次。
如果你在實作過程中遇到問題,歡迎到 Skool 社群發問,我和 500+ 學員都會幫你解答。
- 💬 加入學習社群:Skool 雲端方程式 Cloud F1(免費加入,和 500+ 學員一起學習 n8n 自動化)
- 📚 延伸閱讀:n8n 零基礎完整教學 — 從零開始學 n8n
- 🎥 觀看影片教學:YouTube 頻道 — 50+ 支 n8n 教學影片
- 💻 取得 JSON 模板:可以到 Skool 社群索取完整的 n8n 工作流 JSON 檔案
🔗 相關資源
n8n 基礎教學:
- n8n 零基礎完整教學 2026 — 從零開始學 n8n
- n8n 完整自動化工作流指南 — 工作流設計方法論
- n8n 26 個實用技巧 (1-16) — 基礎技巧篇
- n8n 26 個進階技巧 (16-26) — 進階技巧篇
實戰應用案例:
- n8n Google Sheets 整合完整教學 — 深入了解 Google Sheets 節點
- n8n 客戶生日自動祝福 — 另一個活動自動化案例
- n8n Code 節點實戰指南 — 深入學習 Code 節點
外部資源:
- n8n 官方文檔 — 最新功能和節點說明
- Math.random() - MDN — JavaScript 隨機數說明
- Crypto.randomBytes() - Node.js — 密碼學等級的隨機數
本文改編自 n8n 課程模組「尾牙抽獎小工具」,由 Alex Hsieh 撰寫。結合實戰經驗,提供完整的抽獎系統實作指南。最後更新:2026-02-11