8e6db8f477
- Move INTERACTIVE_MESSAGES.md to docs/ folder - Remove all third-party name references from code comments - Temporarily remove docs from .gitignore to allow tracking Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
11 KiB
11 KiB
⚠️ EXPERIMENTAL: Interactive Messages Guide
🚨 CRITICAL WARNING
These features MAY NOT WORK and can cause ACCOUNT BANS.
- ❌ WhatsApp actively blocks non-business accounts from sending interactive messages
- ❌ Can result in temporary or permanent account bans
- ❌ Messages may not be delivered
- ✅ Use ONLY for testing with DISPOSABLE accounts in DEV environment
📋 Table of Contents
- Configuration
- Simple Text Buttons
- Buttons with Image
- Buttons with Video
- List Messages
- Template Buttons (Action Buttons)
- Carousel Messages
- Metrics and Monitoring
Configuration
Enable Interactive Messages
import makeWASocket from '@whiskeysockets/baileys'
const sock = makeWASocket({
auth: state,
// ⚠️ Enable experimental interactive messages
// WARNING: Can cause account bans!
enableInteractiveMessages: true, // default: true
logger: pino({ level: 'warn' })
})
Disable in Production
const sock = makeWASocket({
auth: state,
// ✅ Disable for production safety
enableInteractiveMessages: false,
logger: pino({ level: 'info' })
})
1. Simple Text Buttons
Send a message with up to 3 clickable buttons.
Example
await sock.sendMessage(jid, {
text: 'Choose an option:',
buttons: [
{
buttonId: 'btn1',
buttonText: { displayText: 'Option 1' }
},
{
buttonId: 'btn2',
buttonText: { displayText: 'Option 2' }
},
{
buttonId: 'btn3',
buttonText: { displayText: 'Option 3' }
}
],
footerText: 'Optional footer text'
})
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
text |
string | ✅ | Main message text |
buttons |
ButtonInfo[] | ✅ | Array of buttons (max 3) |
footerText |
string | ❌ | Footer text below buttons |
2. Buttons with Image
Send an image with interactive buttons.
Example
await sock.sendMessage(jid, {
image: { url: 'https://example.com/image.jpg' },
caption: 'Image description',
buttons: [
{
buttonId: 'view_more',
buttonText: { displayText: 'View More' }
},
{
buttonId: 'buy_now',
buttonText: { displayText: 'Buy Now' }
}
],
footerText: 'Available now'
})
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
image |
WAMediaUpload | ✅ | Image URL or Buffer |
caption |
string | ❌ | Image caption |
buttons |
ButtonInfo[] | ✅ | Array of buttons (max 3) |
footerText |
string | ❌ | Footer text |
3. Buttons with Video
Send a video with interactive buttons.
Example
await sock.sendMessage(jid, {
video: { url: 'https://example.com/video.mp4' },
caption: 'Watch this!',
buttons: [
{
buttonId: 'watch',
buttonText: { displayText: 'Watch Now' }
}
],
footerText: 'New release'
})
4. List Messages
Send a message with a menu of up to 10 options organized in sections.
Example
await sock.sendMessage(jid, {
text: 'Choose a product:',
title: 'Product Catalog',
buttonText: 'View Options',
sections: [
{
title: 'Electronics',
rows: [
{
rowId: 'laptop_1',
title: 'Laptop Pro',
description: '$999 - High performance'
},
{
rowId: 'phone_1',
title: 'Smartphone X',
description: '$699 - Latest model'
}
]
},
{
title: 'Accessories',
rows: [
{
rowId: 'case_1',
title: 'Phone Case',
description: '$29 - Protective'
}
]
}
],
footerText: 'Free shipping'
})
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
text |
string | ✅ | Message description |
title |
string | ❌ | List title |
buttonText |
string | ✅ | Text on button that opens list |
sections |
ListSection[] | ✅ | Array of sections (max 10 items total) |
footerText |
string | ❌ | Footer text |
Limits
- Maximum 10 sections
- Maximum 10 rows total across all sections
- Row title: 24 characters max
- Row description: 72 characters max
5. Template Buttons (Action Buttons)
Send buttons with actions: Quick Reply, URL, or Call.
Example
await sock.sendMessage(jid, {
text: 'Contact us or visit our website',
templateButtons: [
// Quick Reply Button
{
index: 1,
quickReplyButton: {
displayText: 'Quick Reply',
id: 'reply_1'
}
},
// URL Button
{
index: 2,
urlButton: {
displayText: 'Visit Website',
url: 'https://example.com'
}
},
// Call Button
{
index: 3,
callButton: {
displayText: 'Call Us',
phoneNumber: '+551199999999'
}
}
],
footer: 'We are here to help'
})
Button Types
| Type | Description | Parameters |
|---|---|---|
quickReplyButton |
Quick response button | displayText, id |
urlButton |
Opens URL in browser | displayText, url |
callButton |
Initiates phone call | displayText, phoneNumber |
6. Carousel Messages
Send up to 10 scrollable cards with images/videos and buttons.
Example
await sock.sendMessage(jid, {
text: 'Check out our products',
carousel: {
cards: [
// Card 1
{
header: {
title: 'Product 1',
imageMessage: {
url: 'https://example.com/product1.jpg',
mimetype: 'image/jpeg'
},
hasMediaAttachment: true
},
body: { text: 'Amazing product - $99.90' },
footer: { text: 'Limited stock' },
nativeFlowMessage: {
buttons: [
{
name: 'quick_reply',
buttonParamsJson: JSON.stringify({
display_text: 'Buy Now',
id: 'buy_1'
})
},
{
name: 'cta_url',
buttonParamsJson: JSON.stringify({
display_text: 'More Info',
url: 'https://example.com/product1'
})
}
]
}
},
// Card 2
{
header: {
title: 'Product 2',
imageMessage: {
url: 'https://example.com/product2.jpg',
mimetype: 'image/jpeg'
},
hasMediaAttachment: true
},
body: { text: 'Great deal - $149.90' },
footer: { text: 'Best seller' },
nativeFlowMessage: {
buttons: [
{
name: 'quick_reply',
buttonParamsJson: JSON.stringify({
display_text: 'Buy Now',
id: 'buy_2'
})
}
]
}
}
],
messageVersion: 1
}
})
Limits
- Maximum 10 cards per carousel
- Each card requires an image or video
- Up to 3 buttons per card
- All cards must have same media type (all images or all videos)
Metrics and Monitoring
All interactive messages are tracked with Prometheus metrics:
Available Metrics
// Messages sent by type
metrics.interactiveMessagesSent.inc({ type: 'buttons' })
// Successful sends
metrics.interactiveMessagesSuccess.inc({ type: 'list' })
// Failures with reason
metrics.interactiveMessagesFailures.inc({
type: 'template',
reason: 'feature_disabled'
})
// Send latency
metrics.interactiveMessagesLatency.observe({ type: 'carousel' }, 1234)
Monitoring Dashboard
Query these metrics in Prometheus/Grafana:
# Total interactive messages sent
sum(interactive_messages_sent_total) by (type)
# Success rate
sum(interactive_messages_success_total) / sum(interactive_messages_sent_total)
# Failure breakdown
sum(interactive_messages_failures_total) by (type, reason)
# P95 latency
histogram_quantile(0.95, interactive_messages_latency_ms)
Handling Responses
Button Response
sock.ev.on('messages.upsert', async ({ messages }) => {
const msg = messages[0]
// Button response
if (msg.message?.buttonsResponseMessage) {
const buttonId = msg.message.buttonsResponseMessage.selectedButtonId
const displayText = msg.message.buttonsResponseMessage.selectedDisplayText
console.log(`User clicked: ${buttonId} - "${displayText}"`)
}
// Template button response
if (msg.message?.templateButtonReplyMessage) {
const selectedId = msg.message.templateButtonReplyMessage.selectedId
const selectedText = msg.message.templateButtonReplyMessage.selectedDisplayText
console.log(`User clicked template: ${selectedId} - "${selectedText}"`)
}
// List response
if (msg.message?.listResponseMessage) {
const rowId = msg.message.listResponseMessage.singleSelectReply.selectedRowId
const title = msg.message.listResponseMessage.title
console.log(`User selected from list: ${rowId} - "${title}"`)
}
})
Troubleshooting
Message Not Showing
- ✅ Verify
enableInteractiveMessagesistrue - ✅ Check logs for
[EXPERIMENTAL]warnings - ✅ Ensure you're using a test/disposable account
- ❌ Interactive messages don't work on production accounts
Account Banned/Restricted
- ⚠️ This is expected behavior
- ⚠️ WhatsApp blocks non-business accounts
- ✅ Create a new test account
- ✅ Use official WhatsApp Business API for production
Metrics Not Showing
Check feature flag:
if (buttonType && !enableInteractiveMessages) {
// Metrics will show reason: 'feature_disabled'
}
Migration to WhatsApp Business API
For production use, migrate to official API:
Evolution API (Cloud Mode)
// config.ts
export const evolutionConfig = {
apiUrl: 'https://your-evolution-api.com',
apiKey: 'your-api-key',
instance: 'your-instance'
}
// Send button via Evolution API
await fetch(`${evolutionConfig.apiUrl}/message/sendButton`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': evolutionConfig.apiKey
},
body: JSON.stringify({
number: '5511999999999',
options: {
delay: 1200,
presence: 'composing'
},
buttonMessage: {
text: 'Choose an option',
buttons: [
{ id: '1', text: 'Option 1' },
{ id: '2', text: 'Option 2' }
],
footer: 'Footer text'
}
})
})
References
- WhatsApp Official Business API
- Evolution API Documentation
- Baileys GitHub Issues #56
- Baileys GitHub Issues #25
⚠️ Final Reminder
THESE FEATURES ARE EXPERIMENTAL AND UNRELIABLE
- Use only for testing
- Expect failures and bans
- Not suitable for production
- Official WhatsApp Business API is the only supported way
Generated by rsalcara/InfiniteAPI