Bot WA AI untuk Survey & Feedback
Cara membuat bot AI WhatsApp untuk survey dan feedback. Collect insights, NPS, CSAT otomatis. Tutorial lengkap!
AI Survey = Higher response rate!
Survey via WhatsApp dengan AI bisa lebih conversational, adapt pertanyaan, dan mendapat response rate 3-5x lebih tinggi dari email survey.
Kenapa Survey via WhatsApp?
📊 PERBANDINGAN RESPONSE RATE:
Email Survey: 5-15%
SMS Survey: 10-20%
WhatsApp Survey: 35-50%
WhatsApp AI Survey: 45-60%
KENAPA LEBIH TINGGI:
- Familiar platform
- Conversational
- Quick to respond
- No app/link needed
- Personal feelJenis Survey
📋 SURVEY TYPES:
1. NPS (Net Promoter Score)
"Seberapa likely merekomendasikan kami?"
Scale: 0-10
2. CSAT (Customer Satisfaction)
"Seberapa puas dengan layanan kami?"
Scale: 1-5
3. CES (Customer Effort Score)
"Seberapa mudah menyelesaikan masalah?"
Scale: 1-5
4. POST-PURCHASE
"Gimana pengalaman belanja hari ini?"
5. POST-SUPPORT
"Apakah masalah terselesaikan?"
6. PRODUCT FEEDBACK
"Gimana pendapat tentang produk X?"NPS Survey Implementation
System Prompt:
javascript
const NPS_SURVEY_PROMPT = `Kamu adalah AI yang bertugas mengumpulkan feedback NPS untuk [BRAND].
FLOW SURVEY:
1. Sapa dan jelaskan survey singkat (30 detik)
2. Tanya NPS score (0-10)
3. Tanya alasan singkat
4. Ucapkan terima kasih
ATURAN:
- Conversational, tidak kaku
- Jangan memaksa jika tidak mau
- Validasi score 0-10
- Follow up berdasarkan score:
- 0-6 (Detractor): Tanya apa yang bisa diperbaiki
- 7-8 (Passive): Tanya apa yang bisa lebih baik
- 9-10 (Promoter): Minta testimonial/review
IMPORTANT:
- Jangan terlalu banyak pertanyaan
- Max 3 exchanges
- Extract score dengan [NPS_SCORE: X]
- Extract feedback dengan [FEEDBACK: text]`;Implementation:
javascript
const surveyStates = new Map();
async function handleNPSSurvey(userId, userMessage) {
let state = surveyStates.get(userId) || { step: 'intro', data: {} };
switch (state.step) {
case 'intro':
surveyStates.set(userId, { step: 'score', data: {} });
return `Hai Kak! 👋
Boleh minta waktu 30 detik untuk feedback?
Dari skala 0-10, seberapa likely kakak merekomendasikan [BRAND] ke teman/keluarga?
0 = Tidak akan sama sekali
10 = Pasti rekomendasikan
Ketik angkanya ya! 😊`;
case 'score':
const score = parseInt(userMessage);
if (isNaN(score) || score < 0 || score > 10) {
return 'Mohon masukkan angka 0-10 ya kak 🙏';
}
state.data.score = score;
state.step = 'reason';
surveyStates.set(userId, state);
if (score <= 6) {
return `Terima kasih kak!
Kami ingin improve. Boleh ceritakan apa yang perlu kami perbaiki? 🙏`;
} else if (score <= 8) {
return `Terima kasih kak!
Apa yang bisa kami lakukan agar bisa dapat nilai 9 atau 10 dari kakak? 😊`;
} else {
return `Wow, terima kasih banyak kak! 🎉
Boleh ceritakan apa yang paling kakak suka dari [BRAND]?`;
}
case 'reason':
state.data.feedback = userMessage;
state.step = 'done';
// Save to database
await saveSurveyResponse(userId, {
type: 'NPS',
score: state.data.score,
feedback: state.data.feedback,
timestamp: new Date()
});
// Clear state
surveyStates.delete(userId);
// Customize thank you based on score
if (state.data.score >= 9) {
return `Terima kasih banyak atas feedback positifnya kak! 💕
Kalau berkenan, boleh bantu kami dengan review di Google/Tokopedia? Akan sangat membantu! 🙏
[LINK REVIEW]
Sekali lagi, terima kasih! 🎁`;
} else {
return `Terima kasih atas masukannya kak! 🙏
Feedback kakak sangat berharga untuk kami improve.
Ada yang bisa kami bantu lagi hari ini?`;
}
}
}AI-Powered Conversational Survey
javascript
async function handleAISurvey(userId, userMessage, surveyType) {
const context = await getSurveyContext(userId);
const systemPrompt = buildSurveyPrompt(surveyType, context);
const response = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [
{ role: 'system', content: systemPrompt },
...context.history,
{ role: 'user', content: userMessage }
],
tools: surveyTools
});
const aiResponse = response.choices[0].message;
// Extract survey data from AI response
const extractedData = extractSurveyData(aiResponse.content);
if (extractedData.score !== null) {
await saveSurveyResponse(userId, extractedData);
}
// Check for survey completion
if (extractedData.complete) {
await markSurveyComplete(userId);
}
return cleanResponse(aiResponse.content);
}
const surveyTools = [
{
type: 'function',
function: {
name: 'save_survey_response',
description: 'Save survey response when customer provides a score or feedback',
parameters: {
type: 'object',
properties: {
score: { type: 'number' },
feedback: { type: 'string' },
category: { type: 'string' },
complete: { type: 'boolean' }
}
}
}
}
];Post-Purchase Survey
javascript
async function sendPostPurchaseSurvey(orderId) {
const order = await db.orders.findOne({ orderId });
const customer = await db.customers.findOne({ oderId
oderId
userId: order.userId });
// Wait 1 day after delivery
const surveyMessage = `Hai Kak ${customer.name}! 👋
Pesanan #${orderId} sudah sampai ya?
Kami mau tau pengalaman belanja kakak:
1️⃣ Gimana kualitas produknya?
⭐⭐⭐⭐⭐ (ketik 1-5)
2️⃣ Gimana pengiriman/packagingnya?
⭐⭐⭐⭐⭐ (ketik 1-5)
Reply dengan format: [rating produk] [rating pengiriman]
Contoh: 5 4
Atau ceritakan langsung pendapat kakak! 😊`;
await sendWhatsApp(order.customerPhone, surveyMessage);
// Track survey sent
await db.surveys.insertOne({
orderId,
userId: order.userId,
type: 'post_purchase',
sentAt: new Date(),
status: 'pending'
});
}
// Parse response
async function parsePostPurchaseResponse(userId, message) {
// Try to extract ratings
const ratingPattern = /(\d)\s*(\d)?/;
const match = message.match(ratingPattern);
if (match) {
const productRating = parseInt(match[1]);
const deliveryRating = match[2] ? parseInt(match[2]) : null;
return {
productRating,
deliveryRating,
rawFeedback: message
};
}
// Use AI to extract from free-form response
const extraction = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [{
role: 'user',
content: `Extract ratings and sentiment from this feedback.
Return JSON with: productRating (1-5), deliveryRating (1-5), sentiment (positive/neutral/negative), summary
Feedback: "${message}"`
}],
response_format: { type: 'json_object' }
});
return JSON.parse(extraction.choices[0].message.content);
}Survey Triggers
javascript
// Automated survey triggers
const surveyTriggers = {
// After purchase delivered
postPurchase: {
event: 'order_delivered',
delay: '24h',
condition: (order) => order.status === 'delivered'
},
// After support ticket closed
postSupport: {
event: 'ticket_closed',
delay: '1h',
condition: (ticket) => ticket.resolution !== 'spam'
},
// After first purchase
newCustomer: {
event: 'first_order',
delay: '7d',
condition: (customer) => customer.orderCount === 1
},
// Periodic NPS
periodicNPS: {
event: 'schedule',
schedule: '0 10 1 * *', // 1st of each month
condition: (customer) => customer.lastSurvey < daysAgo(90)
}
};
// Register triggers
async function setupSurveyTriggers() {
// Order delivered trigger
eventEmitter.on('order_delivered', async (order) => {
await scheduleSurvey(order.userId, 'postPurchase', {
delay: 24 * 60 * 60 * 1000, // 24 hours
context: { orderId: order.id }
});
});
// Support ticket closed
eventEmitter.on('ticket_closed', async (ticket) => {
if (ticket.resolution !== 'spam') {
await scheduleSurvey(ticket.userId, 'postSupport', {
delay: 60 * 60 * 1000, // 1 hour
context: { ticketId: ticket.id }
});
}
});
}Survey Analytics Dashboard
javascript
// NPS calculation
async function calculateNPS(startDate, endDate) {
const surveys = await db.surveys.find({
type: 'NPS',
completedAt: { $gte: startDate, $lte: endDate }
}).toArray();
const total = surveys.length;
const promoters = surveys.filter(s => s.score >= 9).length;
const detractors = surveys.filter(s => s.score <= 6).length;
const nps = ((promoters - detractors) / total * 100).toFixed(0);
return {
nps: parseInt(nps),
promoters: (promoters / total * 100).toFixed(1) + '%',
passives: ((total - promoters - detractors) / total * 100).toFixed(1) + '%',
detractors: (detractors / total * 100).toFixed(1) + '%',
totalResponses: total
};
}
// CSAT calculation
async function calculateCSAT(startDate, endDate) {
const surveys = await db.surveys.find({
type: 'CSAT',
completedAt: { $gte: startDate, $lte: endDate }
}).toArray();
const satisfied = surveys.filter(s => s.score >= 4).length;
const csat = (satisfied / surveys.length * 100).toFixed(1);
return {
csat: `${csat}%`,
avgScore: (surveys.reduce((a, s) => a + s.score, 0) / surveys.length).toFixed(2),
totalResponses: surveys.length
};
}
// Feedback analysis
async function analyzeFeedback(startDate, endDate) {
const feedbacks = await db.surveys.find({
feedback: { $exists: true, $ne: '' },
completedAt: { $gte: startDate, $lte: endDate }
}).toArray();
// Use AI to categorize and summarize
const analysis = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [{
role: 'user',
content: `Analyze these customer feedbacks.
Identify:
1. Top 5 positive themes
2. Top 5 areas for improvement
3. Common keywords
4. Overall sentiment
Feedbacks:
${feedbacks.map(f => f.feedback).join('\n---\n')}`
}]
});
return analysis.choices[0].message.content;
}Response Templates
javascript
const surveyResponses = {
declined: `Tidak masalah kak! 🙏
Terima kasih sudah menjadi customer [BRAND].
Kalau ada pertanyaan, chat aja ya!`,
lowScore: `Terima kasih atas kejujurannya kak 🙏
Feedback ini sangat berharga. Tim kami akan review dan improve.
Ada yang bisa kami bantu sekarang?`,
highScore: `Yeay, terima kasih kak! 🎉💕
Senang banget kakak puas dengan [BRAND]!
Kalau berkenan, boleh bantu review di:
⭐ Google: [link]
⭐ Tokopedia: [link]
Terima kasih banyak! 🙏`,
reminder: `Hai Kak! 👋
Kemarin kami kirim survey singkat, belum sempat isi ya?
Cuma butuh 30 detik dan sangat membantu kami improve!
Mau isi sekarang? Reply YES 😊`
};Best Practices
DO ✅
- Keep survey short (2-3 questions)
- Conversational tone
- Timing yang tepat
- Follow up low scores
- Celebrate high scores
- Analyze trendsDON'T ❌
- Terlalu banyak pertanyaan
- Kaku seperti form
- Survey saat tidak tepat
- Ignore negative feedback
- No follow up action
- Survey terlalu seringFAQ
Berapa pertanyaan ideal?
2-3 pertanyaan max. Lebih dari itu, completion rate drop drastis.
Kapan timing terbaik kirim survey?
Post-purchase: 1-2 hari setelah terima. Post-support: 1 jam setelah resolved.
Kesimpulan
AI Survey = Actionable insights!
| Traditional Survey | AI WhatsApp Survey |
|---|---|
| 5-15% response | 45-60% response |
| Static questions | Adaptive |
| Delayed insights | Real-time |