Bot Jualan untuk Flash Sale & Limited Stock
Cara buat bot jualan WhatsApp untuk flash sale. Countdown, limited stock, queue system. Handle rush tanpa crash!
Flash sale = High pressure selling!
Bot yang siap flash sale harus bisa handle surge traffic, real-time stock, dan create urgency yang convert.
Flash Sale Challenges
🔥 TANTANGAN:
- Traffic 10-50x normal
- Stock harus real-time accurate
- Race condition (oversell risk)
- Customer frustration
- Bot overload
✅ SOLUSI:
- Queue system
- Stock locking
- Real-time updates
- Urgency messaging
- Scalable infrastructureTemplate Messages
Flash Sale Announcement:
🔥 FLASH SALE ALERT!
[PRODUCT NAME]
HARGA NORMAL: ~Rp 500.000~
FLASH PRICE: Rp 250.000 (50% OFF!)
📦 Stok: HANYA 50 PCS!
⏰ Mulai: HARI INI, 20:00 WIB
Set alarm sekarang! ⏰
Reply REMIND untuk dapat reminder
5 menit sebelum flash sale!
🔔 Siap-siap rebutan! 🔥Reminder:
⏰ REMINDER: 5 MENIT LAGI!
🔥 FLASH SALE dimulai 20:00 WIB!
[PRODUCT NAME]
💰 Rp 250.000 (50% OFF!)
📦 Stok: 50 pcs
⚡ TIPS CEPAT:
1. Siapkan alamat pengiriman
2. Langsung ketik: BELI [NAMA]
3. Konfirmasi dalam 5 menit
Ketik BELI [PRODUK] tepat jam 20:00!
Good luck! 🍀Flash Sale Live:
🔥 FLASH SALE LIVE!
[PRODUCT NAME] - Rp 250.000
📦 STOK TERSISA: 47/50
⚡ ORDER SEKARANG!
Ketik: FLASH [JUMLAH]
Contoh: FLASH 2
⏱️ Keranjang berlaku 5 menit!
Bayar langsung untuk amankan.
Cepat sebelum kehabisan! 🏃♂️Stock Update (Real-time):
📦 UPDATE STOK
[PRODUCT NAME]
TERSISA: 23 pcs! 🔥🔥🔥
Terjual: 27 pcs dalam 3 menit!
Belum order?
Ketik FLASH [JUMLAH] sekarang!
⚠️ Stok menipis sangat cepat!Queue System:
⏳ ANTRIAN FLASH SALE
Hai! Karena traffic tinggi,
kakak masuk antrian.
📊 Status:
━━━━━━━━━━━━━━━━━━━━
Posisi: #127
Estimasi: 2 menit
Stok saat ini: 35 pcs
━━━━━━━━━━━━━━━━━━━━
Jangan close chat ini!
Kami akan notify saat giliran.
💡 Tip: Siapkan alamat & pembayaran!Your Turn:
🎉 GILIRAN KAKAK!
Stok tersisa: 28 pcs
Waktu order: 3 menit!
⚡ KONFIRMASI ORDER:
━━━━━━━━━━━━━━━━━━━━
Produk: [NAMA]
Harga: Rp 250.000
Qty: 1 (max 2)
━━━━━━━━━━━━━━━━━━━━
Ketik OK untuk lanjut checkout!
Atau ketik QTY [JUMLAH] untuk ubah.
⏱️ 03:00 tersisa...Cart Reserved:
🔒 STOK DIAMANKAN!
Produk sudah di-lock untuk kakak!
📋 Order:
━━━━━━━━━━━━━━━━━━━━
[PRODUCT] x 2
Harga: Rp 500.000
━━━━━━━━━━━━━━━━━━━━
⏱️ BAYAR DALAM: 05:00
💳 Link pembayaran:
[PAYMENT LINK]
⚠️ Stok akan dilepas
jika tidak bayar dalam 5 menit!
Bayar sekarang! 💨Sold Out:
😢 SOLD OUT!
Maaf, [PRODUCT] sudah HABIS!
Terjual: 50 pcs dalam 8 menit! 🔥
Jangan sedih! Pilihan untuk kakak:
1️⃣ NOTIFY ME
Dapat notif kalau restock
2️⃣ SIMILAR PRODUCTS
Lihat produk serupa
3️⃣ NEXT FLASH SALE
Info flash sale berikutnya
Ketik angka untuk pilih!
Terima kasih sudah ikutan! 🙏Implementation
Stock Locking:
javascript
const redis = require('redis');
const client = redis.createClient();
async function lockStock(productId, quantity, sessionId) {
const stockKey = `stock:${productId}`;
const lockKey = `lock:${productId}:${sessionId}`;
// Use Redis transaction for atomicity
const multi = client.multi();
// Check current stock
const currentStock = await client.get(stockKey);
if (parseInt(currentStock) < quantity) {
return { success: false, reason: 'insufficient_stock' };
}
// Decrement stock
multi.decrby(stockKey, quantity);
// Set lock with expiry (5 minutes)
multi.setex(lockKey, 300, JSON.stringify({
quantity,
lockedAt: Date.now()
}));
await multi.exec();
return {
success: true,
lockId: lockKey,
expiresIn: 300
};
}
async function releaseStock(productId, sessionId, quantity) {
const stockKey = `stock:${productId}`;
const lockKey = `lock:${productId}:${sessionId}`;
// Check if lock exists
const lock = await client.get(lockKey);
if (lock) {
// Return stock
await client.incrby(stockKey, quantity);
await client.del(lockKey);
}
}
// Auto-release expired locks
setInterval(async () => {
const expiredLocks = await findExpiredLocks();
for (const lock of expiredLocks) {
await releaseStock(lock.productId, lock.sessionId, lock.quantity);
await notifyCustomerExpired(lock.phone);
}
}, 10000); // Check every 10 secondsQueue System:
javascript
const queue = [];
let processing = false;
async function addToQueue(phone, productId, quantity) {
const position = queue.length + 1;
queue.push({
phone,
productId,
quantity,
addedAt: Date.now()
});
// Notify customer
await sendQueueMessage(phone, position);
// Start processing if not already
if (!processing) {
processQueue();
}
return position;
}
async function processQueue() {
processing = true;
while (queue.length > 0) {
const customer = queue.shift();
// Check stock still available
const stock = await getStock(customer.productId);
if (stock >= customer.quantity) {
// Customer's turn
await sendYourTurnMessage(customer.phone, stock);
// Wait for response (with timeout)
const response = await waitForResponse(customer.phone, 180000); // 3 min
if (response === 'confirm') {
await lockStock(customer.productId, customer.quantity, customer.phone);
}
} else {
// No stock left
await sendSoldOutMessage(customer.phone);
}
// Small delay between processing
await sleep(500);
}
processing = false;
}Real-time Stock Updates:
javascript
// Broadcast stock updates to interested customers
async function broadcastStockUpdate(productId) {
const stock = await getStock(productId);
const watchers = await getStockWatchers(productId);
// Determine urgency level
let message;
if (stock <= 5) {
message = `🔴 HAMPIR HABIS! ${stock} pcs tersisa!`;
} else if (stock <= 20) {
message = `🟡 Stok menipis: ${stock} pcs tersisa!`;
} else {
message = `📦 Stok: ${stock} pcs`;
}
// Batch send
for (const watcher of watchers) {
await sendStockUpdate(watcher.phone, message);
}
}
// Call this after every sale
async function onSale(productId, quantity) {
await decrementStock(productId, quantity);
await broadcastStockUpdate(productId);
}Countdown Timer
javascript
// Visual countdown in messages
function generateCountdown(endTime) {
const now = Date.now();
const remaining = endTime - now;
if (remaining <= 0) return "⏰ WAKTU HABIS!";
const minutes = Math.floor(remaining / 60000);
const seconds = Math.floor((remaining % 60000) / 1000);
return `⏱️ ${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
}
// Send countdown updates
async function sendCountdownUpdates(phone, endTime) {
const intervals = [300, 60, 30, 10]; // seconds before end
for (const secondsBefore of intervals) {
const sendAt = endTime - (secondsBefore * 1000);
if (sendAt > Date.now()) {
setTimeout(async () => {
const countdown = generateCountdown(endTime);
await sendMessage(phone, `${countdown} tersisa!`);
}, sendAt - Date.now());
}
}
}Best Practices
DO ✅
- Real-time stock accuracy
- Queue system for fairness
- Time-limited cart holds
- Clear countdown/urgency
- Graceful sold-out handling
- Restock notificationsDON'T ❌
- Oversell (no stock locking)
- No queue (first come chaos)
- Unlimited cart hold time
- Vague stock info
- Crash during rush
- No follow-up for missedFAQ
Bagaimana prevent oversell?
Stock locking dengan Redis. Atomic operations, automatic release jika tidak bayar.
Queue system perlu?
Sangat recommended untuk fairness dan prevent server overload.
Berapa lama cart hold time?
5-10 menit ideal. Cukup untuk bayar, tidak terlalu lama block stock.
Kesimpulan
Flash sale bot = Speed + Accuracy!
| Unprepared | Flash Sale Ready |
|---|---|
| Oversell | Stock locking |
| Chaos | Queue system |
| No urgency | Countdown timer |
| Customer angry | Fair process |