Bot WA AI untuk Order Tracking
Cara membuat bot AI WhatsApp untuk tracking pesanan. Real-time status, proactive updates, smart notifications. Tutorial lengkap!
AI Order Tracking = Customer peace of mind!
Bot AI bisa handle pertanyaan tracking secara natural, proactive update, dan predict masalah sebelum customer komplain.
Fitur Order Tracking
📦 FITUR TRACKING:
1. NATURAL QUERY
"Pesanan saya sudah sampai mana?"
→ AI pahami dan cek status
2. PROACTIVE UPDATES
Status berubah
→ Auto notify customer
3. PREDICTIVE ALERTS
Detect delay
→ Notify sebelum customer tanya
4. MULTI-CARRIER SUPPORT
JNE, J&T, SiCepat, dll
→ Unified tracking
5. SMART ESCALATION
Stuck > 3 hari
→ Auto alert CS teamSystem Prompt
javascript
const ORDER_TRACKING_PROMPT = `Kamu adalah AI assistant untuk tracking pesanan [BRAND].
CAPABILITIES:
- Cek status pesanan dari nomor order atau nama
- Lacak posisi paket dari nomor resi
- Estimasi waktu sampai
- Handle pertanyaan seputar pengiriman
INFORMASI KURIR:
- JNE: Regular (2-3 hari), YES (1-2 hari), OKE (3-5 hari)
- J&T: Express (1-2 hari), EZ (2-4 hari)
- SiCepat: BEST (1-2 hari), REG (2-4 hari)
- Anteraja: Same Day, Next Day, Regular
STATUS PENGIRIMAN:
- pending: Menunggu pickup
- picked_up: Sudah diambil kurir
- in_transit: Dalam perjalanan
- out_for_delivery: Sedang diantar
- delivered: Sudah diterima
- returned: Dikembalikan
- failed: Gagal kirim
CARA RESPONSE:
- Selalu tunjukkan status terkini dengan jelas
- Berikan estimasi realistis
- Jika delay, jelaskan kemungkinan penyebab
- Tawarkan bantuan jika ada masalah
- Gunakan emoji untuk status visual`;Implementation
Track Order Function:
javascript
const trackingTools = [
{
type: 'function',
function: {
name: 'get_order_status',
description: 'Get order status by order ID or customer phone',
parameters: {
type: 'object',
properties: {
order_id: { type: 'string' },
phone: { type: 'string' }
}
}
}
},
{
type: 'function',
function: {
name: 'track_shipment',
description: 'Track shipment by tracking number',
parameters: {
type: 'object',
properties: {
tracking_number: { type: 'string' },
courier: { type: 'string' }
},
required: ['tracking_number']
}
}
}
];
async function getOrderStatus(params) {
let order;
if (params.order_id) {
order = await db.orders.findOne({ orderId: params.order_id });
} else if (params.phone) {
order = await db.orders.findOne({
customerPhone: params.phone,
status: { $ne: 'delivered' }
}).sort({ createdAt: -1 });
}
if (!order) {
return { found: false };
}
// Get shipping details if shipped
let shippingDetails = null;
if (order.trackingNumber) {
shippingDetails = await trackShipment({
tracking_number: order.trackingNumber,
courier: order.courier
});
}
return {
found: true,
order: {
orderId: order.orderId,
status: order.status,
items: order.items,
total: order.total,
createdAt: order.createdAt,
trackingNumber: order.trackingNumber,
courier: order.courier,
estimatedDelivery: order.estimatedDelivery
},
shipping: shippingDetails
};
}Multi-Carrier Tracking:
javascript
async function trackShipment({ tracking_number, courier }) {
// Auto-detect courier if not provided
if (!courier) {
courier = detectCourier(tracking_number);
}
const trackers = {
jne: trackJNE,
jnt: trackJNT,
sicepat: trackSiCepat,
anteraja: trackAnteraja,
ninja: trackNinja
};
const tracker = trackers[courier.toLowerCase()];
if (!tracker) {
return { error: 'Courier not supported' };
}
try {
const result = await tracker(tracking_number);
return normalizeTrackingResult(result, courier);
} catch (error) {
return { error: 'Tracking failed', message: error.message };
}
}
function detectCourier(trackingNumber) {
// JNE: starts with specific patterns
if (/^(JN|JP|JD)\d+/.test(trackingNumber)) return 'jne';
// J&T: usually starts with J
if (/^J[A-Z]\d+/.test(trackingNumber)) return 'jnt';
// SiCepat: starts with specific patterns
if (/^\d{12}$/.test(trackingNumber)) return 'sicepat';
// Default
return 'unknown';
}
// Normalize different courier responses to standard format
function normalizeTrackingResult(result, courier) {
return {
courier,
trackingNumber: result.tracking_number || result.awb,
status: mapStatus(result.status, courier),
currentLocation: result.current_location || result.last_position,
history: (result.history || result.manifest || []).map(h => ({
timestamp: h.timestamp || h.date,
status: h.status || h.description,
location: h.location || h.city
})),
estimatedDelivery: result.estimated_delivery,
recipient: result.receiver_name,
deliveredAt: result.delivered_at
};
}Natural Language Handler
javascript
async function handleTrackingQuery(userId, userMessage) {
const response = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [
{ role: 'system', content: ORDER_TRACKING_PROMPT },
{ role: 'user', content: userMessage }
],
tools: trackingTools,
tool_choice: 'auto'
});
const message = response.choices[0].message;
if (message.tool_calls) {
const toolResults = [];
for (const toolCall of message.tool_calls) {
const args = JSON.parse(toolCall.function.arguments);
let result;
switch (toolCall.function.name) {
case 'get_order_status':
// If no order_id, use user's phone
if (!args.order_id && !args.phone) {
args.phone = userId.replace('@s.whatsapp.net', '');
}
result = await getOrderStatus(args);
break;
case 'track_shipment':
result = await trackShipment(args);
break;
}
toolResults.push({
tool_call_id: toolCall.id,
role: 'tool',
content: JSON.stringify(result)
});
}
// Get final response with tracking data
const finalResponse = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [
{ role: 'system', content: ORDER_TRACKING_PROMPT },
{ role: 'user', content: userMessage },
message,
...toolResults
]
});
return finalResponse.choices[0].message.content;
}
return message.content;
}Proactive Updates
javascript
// Webhook from courier atau internal status change
async function onOrderStatusChange(orderId, newStatus, trackingData) {
const order = await db.orders.findOne({ orderId });
const customer = await db.customers.findOne({ oderId
oderId
userId: order.userId });
const statusMessages = {
picked_up: `📦 Pesanan Diambil Kurir!
Order #${orderId} sudah diambil ${order.courier}.
🔢 Resi: ${order.trackingNumber}
📍 Posisi: ${trackingData.currentLocation}
📅 Estimasi: ${trackingData.estimatedDelivery}
Track: ${getTrackingLink(order.courier, order.trackingNumber)}`,
in_transit: `🚚 Pesanan Dalam Perjalanan!
Order #${orderId} sedang dikirim.
📍 Posisi terakhir: ${trackingData.currentLocation}
📅 Estimasi tiba: ${trackingData.estimatedDelivery}`,
out_for_delivery: `🎉 Pesanan Sedang Diantar!
Order #${orderId} sedang dalam pengantaran!
📍 Kurir sedang menuju alamat kakak
⏰ Estimasi: Hari ini
Pastikan ada yang terima ya kak! 📱`,
delivered: `✅ Pesanan Diterima!
Order #${orderId} sudah sampai!
📍 Diterima oleh: ${trackingData.recipient}
⏰ Waktu: ${trackingData.deliveredAt}
Terima kasih sudah belanja di [BRAND]! 💕
Puas dengan pesanannya? Reply dengan rating 1-5 ⭐`
};
const message = statusMessages[newStatus];
if (message) {
await sendWhatsApp(customer.phone, message);
}
// Update order status in DB
await db.orders.updateOne(
{ orderId },
{ $set: { status: newStatus, lastUpdate: new Date() } }
);
}Delay Detection & Alert
javascript
// Run every hour
async function checkForDelays() {
const orders = await db.orders.find({
status: { $in: ['picked_up', 'in_transit'] },
estimatedDelivery: { $lt: new Date() }
}).toArray();
for (const order of orders) {
const daysPastDue = Math.floor(
(Date.now() - order.estimatedDelivery) / (1000 * 60 * 60 * 24)
);
if (daysPastDue >= 1 && !order.delayNotified) {
// Notify customer
await sendWhatsApp(order.customerPhone,
`⚠️ Update Pengiriman
Hai Kak! Order #${order.orderId} sepertinya mengalami keterlambatan.
📍 Status terakhir: ${order.lastTrackingStatus}
📅 Estimasi awal: ${formatDate(order.estimatedDelivery)}
Kami sudah follow up ke ${order.courier}.
Akan kami kabari perkembangannya ya!
Ada pertanyaan? Reply saja 🙏`
);
// Notify internal team
await alertCSTeam({
type: 'DELIVERY_DELAY',
orderId: order.orderId,
daysPastDue,
courier: order.courier,
trackingNumber: order.trackingNumber
});
// Mark as notified
await db.orders.updateOne(
{ orderId: order.orderId },
{ $set: { delayNotified: true } }
);
}
}
}
// Schedule
cron.schedule('0 * * * *', checkForDelays);Example Conversations
👤: Pesanan saya sudah sampai mana ya?
🤖: Hai Kak! Aku cek dulu ya...
📦 Order #ORD-20260215-001
Status: 🚚 Dalam Perjalanan
📍 Posisi terakhir:
Hub Jakarta Selatan (15 Feb, 14:30)
📅 Estimasi tiba: 17 Feb 2026
Resi: JN123456789
Track langsung: https://jne.co.id/track/JN123456789
Ada pertanyaan lain kak?
---
👤: Kok lama banget ya, harusnya kemarin sampai
🤖: Aku cek lebih detail ya kak...
Benar kak, ada sedikit keterlambatan 😔
📋 Timeline:
- 14 Feb: Diambil kurir ✓
- 14 Feb: Hub Jakarta ✓
- 15 Feb: Transit Bandung ✓
- 16 Feb: Estimasi sampai ← delayed
Sepertinya ada backlog di hub Bandung
karena volume tinggi.
Yang bisa kami lakukan:
1️⃣ Follow up ke JNE (sudah kami lakukan)
2️⃣ Pantau terus dan kabari kakak
Mohon maaf atas ketidaknyamanannya 🙏
Biasanya 1-2 hari lagi sampai.
Mau aku kabari begitu ada update?Best Practices
DO ✅
- Proactive updates setiap status change
- Detect delay early
- Multi-carrier support
- Natural language queries
- Clear timeline visualization
- Offer help for delaysDON'T ❌
- Only update when asked
- Ignore delays
- Single carrier only
- Rigid command format
- No status history
- Blame courierFAQ
Perlu integrasi API semua kurir?
Ideal ya. Atau pakai aggregator seperti Shipper, Biteship untuk simplify.
Update seberapa sering?
Setiap status change. Plus proactive check untuk delay setiap jam.
Kesimpulan
AI Order Tracking = Happy customers!
| Basic Tracking | AI Tracking |
|---|---|
| Manual check | Auto update |
| Reactive | Proactive |
| Single carrier | Multi carrier |