Skip to main content

Broadcast Messages

The Broadcast Messages feature enables you to send messages to multiple recipients efficiently while automatically handling WhatsApp API rate limits and providing real-time progress tracking.

Overview

Send the same message or personalized template messages to thousands of recipients with:
  • Intelligent Rate Limiting: Automatic compliance with WhatsApp’s 80 msg/sec and 1000 msg/min limits
  • Progress Tracking: Real-time updates on send status, success rate, and estimated completion time
  • Error Handling: Individual message failures don’t stop the entire broadcast
  • Batch Processing: Efficient chunked processing for optimal throughput
  • Abort Control: Stop broadcasts mid-process when needed

Use Cases

  • Order confirmations
  • Shipping updates
  • Delivery notifications
  • Cart abandonment reminders
  • Medical appointment confirmations
  • Service reminders
  • Event notifications
  • Promotional messages (using approved templates)
  • Product launches
  • Special offers
  • System status updates
  • Emergency alerts
  • Important announcements
  • Survey requests
  • Feedback collection
  • Service updates

Quick Start

Simple Text Broadcast

import { WhatsAppClient } from 'whatsapp-client-sdk';

const client = new WhatsAppClient({
  accessToken: 'your-token',
  phoneNumberId: 'your-phone-id'
});

const phoneNumbers = [
  '+1234567890',
  '+0987654321',
  '+1122334455'
];

const result = await client.sendBroadcastText(
  phoneNumbers,
  'Hello! This is a broadcast message.'
);

console.log(`Sent: ${result.successful}/${result.total}`);
console.log(`Failed: ${result.failed}`);
console.log(`Duration: ${result.duration}ms`);

Personalized Template Broadcast

const recipients = [
  {
    phoneNumber: '+1234567890',
    variables: {
      name: 'John',
      order_id: '#12345',
      amount: '$99.99'
    }
  },
  {
    phoneNumber: '+0987654321',
    variables: {
      name: 'Jane',
      order_id: '#12346',
      amount: '$149.99'
    }
  }
];

const result = await client.sendBulkTemplates(
  recipients,
  'order_confirmation',  // Your approved template name
  'en_US'
);

Advanced Usage

Progress Tracking

Monitor your broadcast in real-time:
const result = await client.sendBroadcastText(
  phoneNumbers,
  'Your message here',
  {
    onProgress: (progress) => {
      console.log(`Progress: ${progress.percentage.toFixed(1)}%`);
      console.log(`Sent: ${progress.sent}/${progress.total}`);
      console.log(`Failed: ${progress.failed}`);
      console.log(`Pending: ${progress.pending}`);
      console.log(`ETA: ${Math.round(progress.estimatedTimeRemaining / 1000)}s`);
    },
    onMessageSent: (result) => {
      if (result.success) {
        console.log(`✓ Sent to ${result.phoneNumber}`);
      } else {
        console.log(`✗ Failed to ${result.phoneNumber}: ${result.error}`);
      }
    }
  }
);

Custom Batch Configuration

const result = await client.sendBroadcastText(
  phoneNumbers,
  'Your message',
  {
    batchSize: 100,              // Messages per batch (default: 50)
    delayBetweenBatches: 5000,   // Delay in ms (default: auto-calculated)
    stopOnError: false           // Continue on errors (default: false)
  }
);

Abort Broadcast

// Start broadcast
const broadcastPromise = client.sendBroadcastText(
  largePhoneNumberList,
  'Message'
);

// Abort after 5 seconds
setTimeout(() => {
  if (client.isBroadcastRunning()) {
    client.abortBroadcast();
    console.log('Broadcast aborted!');
  }
}, 5000);

const result = await broadcastPromise;
console.log(`Sent before abort: ${result.successful}`);

Rate Limiting

The SDK automatically handles WhatsApp Business API rate limits:
LimitValueSDK Behavior
Messages per second80Throttles to ~77 msg/sec (safety margin)
Messages per minute1000Batches with calculated delays
Concurrent requestsNo official limitLimits to 10 concurrent within batch

How It Works

  1. Chunking: Large batches are split into chunks of 10 messages
  2. Throttling: Each message takes minimum 13ms (~77 msg/sec)
  3. Batch Delays: Automatic delays between batches to respect per-minute limits
  4. Sequential Processing: Chunks processed sequentially to prevent spikes

API Reference

sendBroadcast(phoneNumbers, message, options?)

Send the same message to multiple recipients. Parameters:
  • phoneNumbers (string[]): Array of recipient phone numbers
  • message (OutgoingMessage): Message object with type and content
  • options (BroadcastOptions): Optional configuration
Returns: Promise<BroadcastResult>

sendBroadcastText(phoneNumbers, text, options?)

Shorthand for sending text broadcasts. Parameters:
  • phoneNumbers (string[]): Array of recipient phone numbers
  • text (string): Message text
  • options (BroadcastOptions): Optional configuration
Returns: Promise<BroadcastResult>

sendBulkTemplates(recipients, templateName, languageCode, options?)

Send personalized template messages to multiple recipients. Parameters:
  • recipients (BroadcastRecipient[]): Recipients with variables
  • templateName (string): Approved template name
  • languageCode (string): Template language (e.g., ‘en_US’)
  • options (BroadcastOptions): Optional configuration
Returns: Promise<BroadcastResult>

abortBroadcast()

Stop the currently running broadcast. Returns: void

isBroadcastRunning()

Check if a broadcast is currently in progress. Returns: boolean

Types

BroadcastOptions

interface BroadcastOptions {
  batchSize?: number;                              // Messages per batch (default: 50)
  delayBetweenBatches?: number;                    // Delay in ms (default: auto)
  onProgress?: (progress: BroadcastProgress) => void;
  onMessageSent?: (result: MessageSendResult) => void;
  stopOnError?: boolean;                           // Stop on first error (default: false)
}

BroadcastResult

interface BroadcastResult {
  broadcastId: string;           // Unique broadcast identifier
  total: number;                 // Total messages attempted
  successful: number;            // Successfully sent
  failed: number;                // Failed to send
  results: MessageSendResult[];  // Individual results
  duration: number;              // Total duration in ms
  startTime: number;             // Start timestamp
  endTime: number;               // End timestamp
}

BroadcastProgress

interface BroadcastProgress {
  total: number;                 // Total messages
  sent: number;                  // Messages sent (successful + failed)
  failed: number;                // Failed messages
  pending: number;               // Remaining messages
  percentage: number;            // Completion percentage (0-100)
  startTime: number;             // Start timestamp
  currentTime: number;           // Current timestamp
  estimatedTimeRemaining?: number; // Estimated ms remaining
}

MessageSendResult

interface MessageSendResult {
  phoneNumber: string;
  success: boolean;
  messageId?: string;            // WhatsApp message ID if successful
  error?: string;                // Error message if failed
  timestamp: number;             // Send attempt timestamp
}

BroadcastRecipient

interface BroadcastRecipient {
  phoneNumber: string;
  variables?: Record<string, string>; // Template variable substitutions
}

Best Practices

1. Use Templates for Marketing

Text messages only work within the 24-hour conversation window. For marketing or notifications outside this window, use approved message templates.
// Using templates
await client.sendBulkTemplates(recipients, 'promo_template', 'en_US');

2. Handle Individual Failures

const result = await client.sendBroadcastText(numbers, text);

// Check failed messages
const failedNumbers = result.results
  .filter(r => !r.success)
  .map(r => ({ phone: r.phoneNumber, error: r.error }));

if (failedNumbers.length > 0) {
  console.log('Failed messages:', failedNumbers);
  // Implement retry logic or alert system
}

3. Respect User Preferences

// Filter opt-out users before sending
const activeUsers = await getActiveSubscribers(); // Your DB logic
const phoneNumbers = activeUsers.map(u => u.phoneNumber);

await client.sendBroadcastText(phoneNumbers, message);

4. Optimize Batch Size

// For smaller lists (< 500), use larger batches
await client.sendBroadcastText(numbers, text, {
  batchSize: 100
});

// For very large lists (10k+), use default or smaller batches
await client.sendBroadcastText(numbers, text, {
  batchSize: 50  // More frequent progress updates
});

5. Monitor and Log

const result = await client.sendBroadcastText(numbers, text, {
  onProgress: (progress) => {
    // Log to your monitoring system
    logger.info('Broadcast progress', {
      broadcastId: result.broadcastId,
      progress: progress.percentage,
      failed: progress.failed
    });
  }
});

// Store results for analysis
await db.saveBroadcastResults(result);

Examples

Example 1: Simple Broadcast with Progress Tracking

async function sendAnnouncementBroadcast() {
  const phoneNumbers = [
    '+1234567890',
    '+0987654321',
    '+1122334455',
    // Add more recipients...
  ];

  const message = 'Hello! This is an important announcement for all our customers. 🎉';

  try {
    const result = await client.sendBroadcastText(phoneNumbers, message, {
      batchSize: 50,
      onProgress: (progress) => {
        console.log(`📊 Progress: ${progress.sent}/${progress.total} (${progress.percentage.toFixed(1)}%)`);
        console.log(`   ✅ Successful: ${progress.sent - progress.failed}`);
        console.log(`   ❌ Failed: ${progress.failed}`);
        if (progress.estimatedTimeRemaining) {
          console.log(`   ⏱️  ETA: ${Math.round(progress.estimatedTimeRemaining / 1000)}s\n`);
        }
      },
    });

    console.log('\n✅ Broadcast completed!');
    console.log(`   Total: ${result.total}`);
    console.log(`   Successful: ${result.successful}`);
    console.log(`   Failed: ${result.failed}`);
    console.log(`   Duration: ${(result.duration / 1000).toFixed(2)}s`);

    // Handle failed messages
    if (result.failed > 0) {
      const failedNumbers = result.results
        .filter(r => !r.success)
        .map(r => ({ phone: r.phoneNumber, error: r.error }));

      console.log('\n❌ Failed recipients:', failedNumbers);
      // Implement retry logic here
    }
  } catch (error) {
    console.error('❌ Broadcast failed:', error.message);
  }
}

Example 2: Detailed Message Tracking

async function sendPromotionWithTracking() {
  const phoneNumbers = ['+1234567890', '+0987654321', '+1122334455'];
  const message = '🎁 Special offer! Use code WELCOME10 for 10% off.';

  const successfulRecipients = [];
  const failedRecipients = [];

  const result = await client.sendBroadcastText(phoneNumbers, message, {
    onMessageSent: (msgResult) => {
      if (msgResult.success) {
        successfulRecipients.push(msgResult.phoneNumber);
        console.log(`✅ Sent to ${msgResult.phoneNumber} (ID: ${msgResult.messageId})`);
      } else {
        failedRecipients.push(msgResult);
        console.log(`❌ Failed: ${msgResult.phoneNumber} - ${msgResult.error}`);
      }
    },
    onProgress: (progress) => {
      // Visual progress bar
      const bar = '█'.repeat(Math.floor(progress.percentage / 5)) +
                  '░'.repeat(20 - Math.floor(progress.percentage / 5));
      console.log(`[${bar}] ${progress.percentage.toFixed(1)}%`);
    },
  });

  console.log('\n📊 Final Report:');
  console.log(`   Broadcast ID: ${result.broadcastId}`);
  console.log(`   Success Rate: ${((result.successful / result.total) * 100).toFixed(1)}%`);
  console.log(`   Duration: ${(result.duration / 1000).toFixed(2)}s`);
}

Example 3: Personalized Template Broadcast

async function sendOrderConfirmations() {
  // Each recipient with personalized data
  const recipients = [
    {
      phoneNumber: '+1234567890',
      variables: {
        name: 'John Doe',
        orderNumber: 'ORD-12345',
        deliveryDate: 'December 25, 2024',
      },
    },
    {
      phoneNumber: '+0987654321',
      variables: {
        name: 'Jane Smith',
        orderNumber: 'ORD-12346',
        deliveryDate: 'December 26, 2024',
      },
    },
  ];

  try {
    const result = await client.sendBulkTemplates(
      recipients,
      'order_confirmation', // Your pre-approved template name
      'en_US',
      {
        batchSize: 30,
        onProgress: (progress) => {
          console.log(`📤 Sending: ${progress.sent}/${progress.total}`);
        },
        onMessageSent: (msgResult) => {
          if (msgResult.success) {
            console.log(`✅ Template sent to ${msgResult.phoneNumber}`);
          } else {
            console.log(`❌ Failed: ${msgResult.phoneNumber} - ${msgResult.error}`);
          }
        },
      }
    );

    console.log('\n✅ Template broadcast completed!');
    console.log(`   Success: ${result.successful}/${result.total}`);
    console.log(`   Avg time per message: ${(result.duration / result.total).toFixed(0)}ms`);
  } catch (error) {
    console.error('❌ Template broadcast failed:', error.message);
  }
}
Template Setup Required: Before using template broadcasts, ensure your template is approved in WhatsApp Business Manager. Template approval can take 1-48 hours.

Limitations

Important Limitations
  1. 24-Hour Window: Text broadcasts require an active conversation window (user messaged you in last 24h). Use templates otherwise.
  2. Template Approval: Template messages must be pre-approved by Meta. This can take 1-48 hours.
  3. Rate Limits: While the SDK handles rate limiting, sending to 100k+ recipients will take considerable time (~20+ minutes).
  4. No Retry Logic: Currently, failed messages are not automatically retried. Implement your own retry logic if needed.
  5. Single Broadcast: Only one broadcast can run at a time per client instance.

Troubleshooting

Solution: The SDK should handle this automatically. If you’re still seeing errors:
  • Reduce batchSize option
  • Increase delayBetweenBatches
  • Ensure you’re not running multiple broadcasts simultaneously
Possible causes:
  • Invalid access token or phone number ID
  • Messages sent to users outside 24-hour window (use templates)
  • Phone numbers incorrectly formatted
This is normal: For 10,000 recipients at 80 msg/sec, expect ~2 minutes minimum. The SDK prioritizes delivery success over speed.

Migration Guide

If you’re upgrading from a previous version without broadcast support:
// OLD: Sending one by one
for (const phone of phoneNumbers) {
  await client.sendText(phone, message);
}

// NEW: Broadcast
await client.sendBroadcastText(phoneNumbers, message);

Next Steps

Template Messages

Learn about using pre-approved templates

Text Messages

Learn about basic text messaging

Error Handling

Handle errors and implement retry logic

Message Overview

Explore all available message types

Version

Broadcast feature added in version 1.6.0