Union type representing the different ways to provide media for upload to WhatsApp.
type WAMediaUpload = Buffer | WAMediaPayloadStream | WAMediaPayloadURL
WAMediaUpload accepts three formats:
- Buffer - Raw binary data
- Stream - Readable stream (useful for large files)
- URL - URL string or URL object pointing to the media
Buffer Upload
Provide media as a raw Buffer object. Best for small to medium-sized files already in memory.
Raw binary data of the media file
Example:
import fs from 'fs'
import makeWASocket from '@whiskeysockets/baileys'
const sock = makeWASocket({ /* auth */ })
// Read file into Buffer
const imageBuffer = fs.readFileSync('./image.jpg')
// Send as buffer
await sock.sendMessage(jid, {
image: imageBuffer,
caption: 'Sent from buffer'
})
Use Cases:
- Small images and files
- In-memory media processing
- Generated content (QR codes, charts, etc.)
Provide media as a readable stream. Recommended for large files to avoid loading entire file into memory.
Node.js Readable stream containing the media data
Type Definition:
type WAMediaPayloadStream = {
stream: Readable
}
Example:
import fs from 'fs'
import { Readable } from 'stream'
const sock = makeWASocket({ /* auth */ })
// Create read stream for large video file
const videoStream = fs.createReadStream('./large-video.mp4')
// Send as stream
await sock.sendMessage(jid, {
video: { stream: videoStream },
caption: 'Large video uploaded via stream'
})
Use Cases:
- Large video files (>50MB)
- Large audio files
- Streaming from external sources
- Memory-efficient uploads
Benefits:
- Lower memory usage
- Better performance for large files
- Supports backpressure handling
Provide media as a URL. Baileys will download the file from the URL before uploading to WhatsApp.
URL pointing to the media file (can be string or URL object)
Type Definition:
type WAMediaPayloadURL = {
url: URL | string
}
Example with String URL:
const sock = makeWASocket({ /* auth */ })
// Send image from URL (string)
await sock.sendMessage(jid, {
image: { url: 'https://example.com/image.jpg' },
caption: 'Image from URL'
})
// Send document from URL
await sock.sendMessage(jid, {
document: { url: 'https://example.com/document.pdf' },
mimetype: 'application/pdf',
fileName: 'document.pdf'
})
Example with URL Object:
import { URL } from 'url'
const imageUrl = new URL('https://example.com/photo.png')
await sock.sendMessage(jid, {
image: { url: imageUrl },
caption: 'Photo from URL object'
})
Use Cases:
- Remote media files
- CDN-hosted content
- Public image URLs
- Webhook media downloads
Important Notes:
- URL must be publicly accessible
- Baileys downloads the file first, then uploads to WhatsApp
- Consider timeout settings for large files
- HTTP/HTTPS protocols supported
All media message types support WAMediaUpload:
Image
await sock.sendMessage(jid, {
image: buffer | { stream } | { url },
caption: 'Image caption'
})
Video
await sock.sendMessage(jid, {
video: buffer | { stream } | { url },
caption: 'Video caption',
gifPlayback: false
})
Audio
await sock.sendMessage(jid, {
audio: buffer | { stream } | { url },
ptt: true // voice note
})
Document
await sock.sendMessage(jid, {
document: buffer | { stream } | { url },
mimetype: 'application/pdf',
fileName: 'document.pdf'
})
Sticker
await sock.sendMessage(jid, {
sticker: buffer | { stream } | { url },
isAnimated: false
})
Complete Examples
Example 1: Image with All Three Methods
import fs from 'fs'
import makeWASocket from '@whiskeysockets/baileys'
const sock = makeWASocket({ /* auth */ })
const jid = '[email protected]'
// Method 1: Buffer
const imageBuffer = fs.readFileSync('./photo.jpg')
await sock.sendMessage(jid, {
image: imageBuffer,
caption: 'Sent as Buffer'
})
// Method 2: Stream
const imageStream = fs.createReadStream('./photo.jpg')
await sock.sendMessage(jid, {
image: { stream: imageStream },
caption: 'Sent as Stream'
})
// Method 3: URL
await sock.sendMessage(jid, {
image: { url: 'https://example.com/photo.jpg' },
caption: 'Sent from URL'
})
Example 2: Large Video with Stream
import fs from 'fs'
const sock = makeWASocket({ /* auth */ })
// Stream large video file (memory efficient)
const videoStream = fs.createReadStream('./movie.mp4')
await sock.sendMessage(jid,
{
video: { stream: videoStream },
caption: 'Full movie upload',
mimetype: 'video/mp4'
},
{
// Increase timeout for large file
mediaUploadTimeoutMs: 300000 // 5 minutes
}
)
Example 3: Document from URL with Custom Options
const sock = makeWASocket({ /* auth */ })
await sock.sendMessage(jid,
{
document: { url: 'https://cdn.example.com/report.pdf' },
mimetype: 'application/pdf',
fileName: 'Monthly_Report_2024.pdf',
caption: 'Here is the monthly report'
},
{
quoted: previousMessage,
mediaUploadTimeoutMs: 60000
}
)
Example 4: Voice Note from Buffer
import fs from 'fs'
const sock = makeWASocket({ /* auth */ })
// Read audio file
const audioBuffer = fs.readFileSync('./voice-note.ogg')
// Send as voice note (PTT)
await sock.sendMessage(jid, {
audio: audioBuffer,
ptt: true, // Push-to-talk (voice note)
mimetype: 'audio/ogg; codecs=opus'
})
Example 5: Product Image Upload
import fs from 'fs'
const sock = makeWASocket({ /* auth */ })
const productImageBuffer = fs.readFileSync('./product.jpg')
await sock.sendMessage(jid, {
product: {
productImage: productImageBuffer, // WAMediaUpload type
productId: '12345',
title: 'Amazing Product',
description: 'Best product ever',
currencyCode: 'USD',
priceAmount1000: 99000, // $99.00
retailerId: 'shop123'
},
businessOwnerJid: '[email protected]'
})
Best Practices
When to Use Buffer
- Files < 10MB
- In-memory generated content
- Already loaded data
- Quick operations
When to Use Stream
- Files > 10MB
- Large videos (>50MB)
- Memory-constrained environments
- Processing pipelines
When to Use URL
- Remote hosted files
- CDN content
- Webhook media
- Public images
Upload Configuration
Timeout Settings
Control upload timeout using mediaUploadTimeoutMs option:
// Default timeout
const UPLOAD_TIMEOUT = 30000 // 30 seconds
// Custom timeout for large files
await sock.sendMessage(jid,
{ video: largeVideoStream },
{ mediaUploadTimeoutMs: 120000 } // 2 minutes
)
Upload Intervals
// Minimum interval between uploads
const MIN_UPLOAD_INTERVAL = 5000 // 5 seconds
To avoid rate limiting, space out media uploads:
const mediaFiles = [file1, file2, file3]
for (const file of mediaFiles) {
await sock.sendMessage(jid, { image: file })
// Wait 5 seconds before next upload
await new Promise(resolve => setTimeout(resolve, 5000))
}
To optimize media uploads and avoid re-uploading the same file, implement caching in your custom store by tracking media URLs and hashes:
import makeWASocket from '@whiskeysockets/baileys'
// Implement your own media cache
const mediaCache = new Map()
const sock = makeWASocket({
// ... auth config
})
// Cache media URLs after upload
sock.ev.on('messages.upsert', ({ messages }) => {
for (const msg of messages) {
if (msg.message?.imageMessage) {
const { url, fileSha256 } = msg.message.imageMessage
if (url && fileSha256) {
const hash = Buffer.from(fileSha256).toString('base64')
mediaCache.set(hash, url)
}
}
}
})
// Reuse cached URLs when sending same media
const cachedUrl = mediaCache.get(mediaHash)
if (cachedUrl) {
await sock.sendMessage(jid, { image: { url: cachedUrl } })
}
Type Reference
Complete Type Definitions
import type { Readable } from 'stream'
import type { URL } from 'url'
type WAMediaPayloadURL = {
url: URL | string
}
type WAMediaPayloadStream = {
stream: Readable
}
type WAMediaUpload =
| Buffer
| WAMediaPayloadStream
| WAMediaPayloadURL
type MediaType =
| 'image'
| 'video'
| 'document'
| 'audio'
| 'sticker'
| 'thumbnail-link'
| 'product-catalog-image'
| 'md-app-state'
| 'md-msg-hist'
| 'biz-cover-photo'
Upload Function Type
type WAMediaUploadFunction = (
encFilePath: string,
opts: {
fileEncSha256B64: string
mediaType: MediaType
timeoutMs?: number
}
) => Promise<{
mediaUrl: string
directPath: string
meta_hmac?: string
ts?: number
fbid?: number
}>