Bot WA untuk Kuis, Polling & Games
Cara buat bot WhatsApp untuk kuis, polling, dan games interaktif. Tingkatkan engagement dengan cara seru!
Engagement rendah? Buat interaksi jadi FUN!
Bot kuis dan games membuat customer lebih engaged dan lebih ingat brand kamu.
Kenapa Kuis & Games?
š BENEFITS:
- Meningkatkan engagement 3-5x
- Customer lebih ingat brand
- Viral potential (share ke teman)
- Data collection yang fun
- Relationship building
- Bisa dikaitkan dengan promoJenis Interaktif
1. Quiz Trivia
š§ QUIZ TIME!
Pertanyaan 1/5:
Siapa presiden pertama Indonesia?
A. Soekarno
B. Soeharto
C. Habibie
D. Megawati
Ketik huruf jawabanmu!2. Polling/Survey
š POLLING
Produk baru mana yang kamu mau?
1ļøā£ Kaos Vintage (38 votes) āāāāāāāā
2ļøā£ Hoodie Oversized (52 votes) āāāāāāāāāā
3ļøā£ Kemeja Flanel (25 votes) āāāāā
4ļøā£ Jaket Denim (41 votes) āāāāāāāā
Ketik angka untuk vote!
Total: 156 votes3. Guessing Game
šÆ TEBAK HARGA!
[GAMBAR PRODUK]
Coba tebak harga produk ini!
Yang paling mendekati dapat voucher Rp 50k! š
Ketik angka (contoh: 250000)4. Word Games
š¤ SUSUN KATA
Susun huruf ini jadi nama produk kami:
S - A - O - K
Clue: Baju casual favorit š
Ketik jawabanmu!5. Lucky Draw
š° LUCKY SPIN!
Ketik SPIN untuk putar roda keberuntungan!
Hadiah:
š Voucher Rp 100k
š·ļø Diskon 20%
š Voucher Rp 50k
š Free Ongkir
š Bonus Gift
ā Coba Lagi
Kesempatan: 1x per hariImplementasi Quiz
Quiz Engine:
javascript
const quizzes = {
product_quiz: {
title: 'š§ Quiz Produk Kami!',
questions: [
{
q: 'Bahan utama kaos premium kami adalah?',
options: ['A. Polyester', 'B. Cotton Combed 30s', 'C. Rayon', 'D. Spandex'],
answer: 'B',
explanation: 'Betul! Kaos kami pakai Cotton Combed 30s yang super nyaman!'
},
{
q: 'Berapa lama garansi produk kami?',
options: ['A. 7 hari', 'B. 14 hari', 'C. 30 hari', 'D. 60 hari'],
answer: 'C',
explanation: 'Yes! Garansi 30 hari untuk semua produk!'
},
// ... more questions
],
rewards: {
perfect: 'Voucher Rp 50.000',
good: 'Voucher Rp 25.000',
participate: 'Diskon 10%'
}
}
};
const userQuizState = new Map();
async function startQuiz(phone, quizId) {
const quiz = quizzes[quizId];
userQuizState.set(phone, {
quizId,
currentQuestion: 0,
score: 0,
startedAt: Date.now()
});
const firstQ = quiz.questions[0];
return `${quiz.title}\n\nPertanyaan 1/${quiz.questions.length}:\n\n${firstQ.q}\n\n${firstQ.options.join('\n')}\n\nKetik huruf jawabanmu!`;
}
async function answerQuiz(phone, answer) {
const state = userQuizState.get(phone);
if (!state) return null;
const quiz = quizzes[state.quizId];
const question = quiz.questions[state.currentQuestion];
const isCorrect = answer.toUpperCase() === question.answer;
if (isCorrect) state.score++;
let response = isCorrect ? 'ā
BENAR!\n' : 'ā Salah!\n';
response += question.explanation + '\n\n';
// Next question or finish
state.currentQuestion++;
if (state.currentQuestion >= quiz.questions.length) {
// Quiz completed
const result = getQuizResult(state.score, quiz.questions.length, quiz.rewards);
userQuizState.delete(phone);
return response + result;
}
// Send next question
const nextQ = quiz.questions[state.currentQuestion];
response += `Pertanyaan ${state.currentQuestion + 1}/${quiz.questions.length}:\n\n`;
response += `${nextQ.q}\n\n${nextQ.options.join('\n')}`;
userQuizState.set(phone, state);
return response;
}
function getQuizResult(score, total, rewards) {
const percentage = (score / total) * 100;
let message = `š QUIZ SELESAI!\n\nSkor: ${score}/${total} (${percentage}%)\n\n`;
if (percentage === 100) {
message += `PERFECT! š\nHadiah: ${rewards.perfect}\nKode: PERFECT${Date.now().toString().slice(-6)}`;
} else if (percentage >= 60) {
message += `Bagus! š\nHadiah: ${rewards.good}\nKode: GOOD${Date.now().toString().slice(-6)}`;
} else {
message += `Terima kasih sudah ikut! š\nHadiah: ${rewards.participate}\nKode: THANKS${Date.now().toString().slice(-6)}`;
}
return message;
}Implementasi Polling
javascript
const polls = new Map();
async function createPoll(id, question, options) {
polls.set(id, {
question,
options: options.map(opt => ({ text: opt, votes: 0 })),
voters: new Set(),
createdAt: Date.now()
});
}
async function vote(pollId, phone, optionIndex) {
const poll = polls.get(pollId);
if (!poll) return 'Poll tidak ditemukan';
if (poll.voters.has(phone)) {
return 'Kamu sudah vote sebelumnya!';
}
if (optionIndex < 0 || optionIndex >= poll.options.length) {
return 'Pilihan tidak valid';
}
poll.options[optionIndex].votes++;
poll.voters.add(phone);
return formatPollResults(poll);
}
function formatPollResults(poll) {
const totalVotes = poll.options.reduce((sum, opt) => sum + opt.votes, 0);
let message = `š ${poll.question}\n\n`;
poll.options.forEach((opt, i) => {
const percentage = totalVotes > 0 ? (opt.votes / totalVotes * 100).toFixed(0) : 0;
const bar = 'ā'.repeat(Math.round(percentage / 10)) + 'ā'.repeat(10 - Math.round(percentage / 10));
message += `${i + 1}ļøā£ ${opt.text}\n ${bar} ${percentage}% (${opt.votes})\n\n`;
});
message += `Total: ${totalVotes} votes`;
return message;
}
// Usage
client.on('message', async msg => {
if (msg.body === 'POLL') {
await createPoll('weekly', 'Produk favorit kamu?',
['Kaos', 'Kemeja', 'Hoodie', 'Celana']
);
const poll = polls.get('weekly');
await msg.reply(`š POLLING MINGGUAN!\n\n${poll.question}\n\n1ļøā£ Kaos\n2ļøā£ Kemeja\n3ļøā£ Hoodie\n4ļøā£ Celana\n\nKetik angka untuk vote!`);
}
if (['1', '2', '3', '4'].includes(msg.body)) {
const result = await vote('weekly', msg.from, parseInt(msg.body) - 1);
await msg.reply(result);
}
});Implementasi Lucky Spin
javascript
const spinRewards = [
{ text: 'Voucher Rp 100k', weight: 5, code: 'LUCKY100' },
{ text: 'Diskon 20%', weight: 15, code: 'DISC20' },
{ text: 'Voucher Rp 50k', weight: 10, code: 'LUCKY50' },
{ text: 'Free Ongkir', weight: 25, code: 'FREEONG' },
{ text: 'Bonus Gift', weight: 20, code: 'GIFT' },
{ text: 'Coba Lagi Besok', weight: 25, code: null }
];
const spinHistory = new Map(); // Track daily spins
async function spin(phone) {
// Check daily limit
const today = new Date().toDateString();
const lastSpin = spinHistory.get(phone);
if (lastSpin === today) {
return 'ā° Kamu sudah spin hari ini!\nCoba lagi besok ya! š';
}
// Weighted random selection
const totalWeight = spinRewards.reduce((sum, r) => sum + r.weight, 0);
let random = Math.random() * totalWeight;
let selectedReward;
for (const reward of spinRewards) {
random -= reward.weight;
if (random <= 0) {
selectedReward = reward;
break;
}
}
// Record spin
spinHistory.set(phone, today);
// Animation effect
let message = 'š° SPINNING...\n\n';
message += 'š š š\n\n';
message += '...\n\n';
message += `š HASIL: ${selectedReward.text}!\n\n`;
if (selectedReward.code) {
message += `š Kode voucher: ${selectedReward.code}\n`;
message += `š
Berlaku 7 hari\n\n`;
message += `Selamat! Gunakan kode ini saat checkout! š`;
} else {
message += `Yah, belum beruntung! š
\nCoba lagi besok ya! š`;
}
return message;
}Implementasi Word Game
javascript
const wordGames = [
{ scrambled: 'ASOK', answer: 'KAOS', hint: 'Baju casual š' },
{ scrambled: 'JAEMK', answer: 'KEMEJA', hint: 'Baju formal š' },
{ scrambled: 'EHOODI', answer: 'HOODIE', hint: 'Baju hangat š§„' }
];
const gameState = new Map();
async function startWordGame(phone) {
const game = wordGames[Math.floor(Math.random() * wordGames.length)];
gameState.set(phone, {
answer: game.answer,
attempts: 3,
startedAt: Date.now()
});
return `š¤ SUSUN KATA!\n\nHuruf: ${game.scrambled}\nHint: ${game.hint}\n\nKamu punya 3 kesempatan!\nKetik jawabanmu:`;
}
async function guessWord(phone, guess) {
const state = gameState.get(phone);
if (!state) return null;
if (guess.toUpperCase() === state.answer) {
gameState.delete(phone);
return `š BENAR!\n\nJawabannya adalah "${state.answer}"!\n\nš Hadiah: Diskon 10%\nKode: WORD10`;
}
state.attempts--;
if (state.attempts <= 0) {
gameState.delete(phone);
return `ā Kesempatan habis!\n\nJawabannya adalah "${state.answer}".\n\nCoba lagi nanti ya! šŖ`;
}
gameState.set(phone, state);
return `ā Salah! Sisa kesempatan: ${state.attempts}\n\nCoba lagi:`;
}Guessing Game (Tebak Harga)
javascript
const priceGuessGames = new Map();
async function startPriceGuess(phone, product) {
priceGuessGames.set(phone, {
product: product.name,
actualPrice: product.price,
startedAt: Date.now()
});
return `šÆ TEBAK HARGA!\n\nš¦ ${product.name}\n[Gambar produk]\n\nCoba tebak harga produk ini!\nYang paling mendekati dapat voucher Rp 50k! š\n\nKetik angka (contoh: 250000)`;
}
async function guessPriceAnswer(phone, guess) {
const game = priceGuessGames.get(phone);
if (!game) return null;
const guessNum = parseInt(guess.replace(/\D/g, ''));
const diff = Math.abs(guessNum - game.actualPrice);
const percentage = (diff / game.actualPrice) * 100;
priceGuessGames.delete(phone);
let message = `šÆ HASIL TEBAKAN!\n\n`;
message += `Tebakan kamu: Rp ${guessNum.toLocaleString()}\n`;
message += `Harga asli: Rp ${game.actualPrice.toLocaleString()}\n\n`;
if (percentage <= 5) {
message += `š TEPAT SEKALI! (selisih ${percentage.toFixed(1)}%)\n`;
message += `š Hadiah: Voucher Rp 50k\n`;
message += `Kode: TEPAT50`;
} else if (percentage <= 15) {
message += `š Hampir! (selisih ${percentage.toFixed(1)}%)\n`;
message += `š Hadiah: Voucher Rp 25k\n`;
message += `Kode: CLOSE25`;
} else {
message += `š
Kurang tepat (selisih ${percentage.toFixed(1)}%)\n`;
message += `Coba lagi lain kali ya!`;
}
return message;
}Best Practices
DO ā
- Kasih reward yang menarik
- Keep it simple & fun
- Time-limited untuk urgency
- Share results (leaderboard)
- Tie ke produk/promo
- Mobile-friendly (tidak perlu banyak ketik)DON'T ā
- Terlalu rumit/banyak rules
- Reward tidak jelas
- Terlalu sering (spam)
- Tidak ada engagement setelahnya
- Susah ikutanFAQ
Seberapa sering bikin games?
1-2x per minggu cukup. Terlalu sering = boring, terlalu jarang = lupa.
Reward apa yang paling menarik?
Voucher diskon paling universal. Tapi sesuaikan dengan audience kamu.
Bisa untuk lead generation?
Absolutely! Minta nama/email sebelum ikut games = lead capture yang fun.
Kesimpulan
Games = Engagement yang fun!
| Boring Promo | Interactive Games |
|---|---|
| Ignored | Participated |
| Forgettable | Memorable |
| One-way | Two-way |
| Low engagement | High engagement |
Make marketing fun again!