Overview
Once storage is enabled, the SDK provides powerful methods to query and analyze your WhatsApp messages. This guide covers all available query methods with practical examples.Make sure you’ve completed the Supabase Integration setup before using these methods.
Get Conversation History
Retrieve all messages from a conversation with a specific phone number.Method Signature
Copy
client.getConversation(
phoneNumber: string,
options?: {
limit?: number;
offset?: number;
dateFrom?: Date;
dateTo?: Date;
}
): Promise<ConversationResult>
Basic Usage
Copy
// Get last 50 messages
const conversation = await client.getConversation('+1234567890', {
limit: 50,
offset: 0
});
console.log(`Total messages: ${conversation.totalMessages}`);
console.log(`Returned: ${conversation.messages.length}`);
// Display messages
conversation.messages.forEach(msg => {
const direction = msg.direction === 'incoming' ? '📩' : '📤';
const content = msg.content.text || `[${msg.message_type}]`;
console.log(`${direction} ${content}`);
});
With Date Range
Copy
// Get messages from last 7 days
const lastWeek = new Date();
lastWeek.setDate(lastWeek.getDate() - 7);
const recentConversation = await client.getConversation('+1234567890', {
dateFrom: lastWeek,
dateTo: new Date(),
limit: 100
});
console.log(`Messages from last week: ${recentConversation.messages.length}`);
Pagination
Copy
async function getAllMessages(phoneNumber: string) {
const allMessages = [];
const pageSize = 100;
let offset = 0;
let hasMore = true;
while (hasMore) {
const result = await client.getConversation(phoneNumber, {
limit: pageSize,
offset: offset
});
allMessages.push(...result.messages);
offset += pageSize;
hasMore = result.messages.length === pageSize;
}
return allMessages;
}
// Usage
const allMessages = await getAllMessages('+1234567890');
console.log(`Total messages retrieved: ${allMessages.length}`);
Response Structure
Copy
interface ConversationResult {
phoneNumber: string;
totalMessages: number;
messages: Array<{
id: string;
whatsappMessageId: string;
fromPhone: string;
toPhone: string;
message_type: string;
content: {
text?: string;
caption?: string;
// ... other fields based on type
};
direction: 'incoming' | 'outgoing';
status: 'sent' | 'delivered' | 'read' | 'failed';
timestamp: Date;
metadata: Record<string, any>;
}>;
}
Search Messages
Search for messages containing specific text across all conversations or within a specific conversation.Method Signature
Copy
client.searchMessages(options: {
text: string;
phoneNumber?: string;
messageType?: string;
dateFrom?: Date;
dateTo?: Date;
limit?: number;
offset?: number;
}): Promise<SearchResult>
Basic Search
Copy
// Search for "order" across all conversations
const results = await client.searchMessages({
text: 'order',
limit: 20
});
console.log(`Found ${results.total} messages containing "order"`);
results.messages.forEach(msg => {
console.log(`From: ${msg.fromPhone}`);
console.log(`Text: ${msg.content.text}`);
console.log(`Date: ${msg.timestamp}`);
console.log('---');
});
Search Within Conversation
Copy
// Search for "invoice" in a specific conversation
const invoiceMessages = await client.searchMessages({
text: 'invoice',
phoneNumber: '+1234567890',
limit: 50
});
console.log(`Found ${invoiceMessages.total} invoice messages`);
Search by Message Type
Copy
// Find all image messages containing "receipt"
const receiptImages = await client.searchMessages({
text: 'receipt',
messageType: 'image',
limit: 10
});
// Find all document messages
const documents = await client.searchMessages({
text: '', // Empty string matches all
messageType: 'document',
limit: 100
});
Search with Date Range
Copy
// Search for "payment" in messages from January 2024
const januaryPayments = await client.searchMessages({
text: 'payment',
dateFrom: new Date('2024-01-01'),
dateTo: new Date('2024-01-31'),
limit: 50
});
Advanced Search Example
Copy
// Search for order-related messages in the last month
async function searchRecentOrders(customerPhone: string) {
const thirtyDaysAgo = new Date();
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
const results = await client.searchMessages({
text: 'ORDER-', // Matches ORDER-12345, ORDER-67890, etc.
phoneNumber: customerPhone,
dateFrom: thirtyDaysAgo,
limit: 100
});
// Extract order numbers from messages
const orderNumbers = results.messages
.map(msg => {
const match = msg.content.text?.match(/ORDER-\d+/);
return match ? match[0] : null;
})
.filter(Boolean);
return [...new Set(orderNumbers)]; // Remove duplicates
}
// Usage
const orders = await searchRecentOrders('+1234567890');
console.log('Recent orders:', orders);
Get Message Thread
Retrieve all replies to a specific message, useful for tracking conversation context.Method Signature
Copy
client.getMessageThread(
messageId: string
): Promise<MessageThread | null>
Basic Usage
Copy
// Get thread for a specific message
const thread = await client.getMessageThread('message_id_here');
if (thread) {
console.log('Original message:', thread.originalMessage.content.text);
console.log(`Replies: ${thread.replies.length}`);
thread.replies.forEach((reply, index) => {
console.log(`Reply ${index + 1}: ${reply.content.text}`);
});
} else {
console.log('No thread found');
}
Track Support Tickets
Copy
async function getSupportThreadDetails(ticketMessageId: string) {
const thread = await client.getMessageThread(ticketMessageId);
if (!thread) {
return null;
}
return {
originalIssue: thread.originalMessage.content.text,
customerPhone: thread.originalMessage.fromPhone,
totalReplies: thread.replies.length,
resolved: thread.replies.some(r =>
r.content.text?.toLowerCase().includes('resolved')
),
lastReply: thread.replies[thread.replies.length - 1],
timeline: thread.replies.map(r => ({
from: r.fromPhone,
text: r.content.text,
timestamp: r.timestamp
}))
};
}
// Usage
const ticketDetails = await getSupportThreadDetails('msg_123');
console.log('Support ticket:', ticketDetails);
Get Conversation Analytics
Analyze conversation patterns, response rates, and engagement metrics.Method Signature
Copy
client.getConversationAnalytics(
phoneNumber: string,
options?: {
from?: Date;
to?: Date;
}
): Promise<ConversationAnalytics>
Basic Usage
Copy
const analytics = await client.getConversationAnalytics('+1234567890', {
from: new Date('2024-01-01'),
to: new Date()
});
console.log('Analytics:', {
totalMessages: analytics.totalMessages,
incomingMessages: analytics.incomingMessages,
outgoingMessages: analytics.outgoingMessages,
averageResponseTime: analytics.averageResponseTime,
responseRate: analytics.responseRate
});
Response Structure
Copy
interface ConversationAnalytics {
phoneNumber: string;
totalMessages: number;
incomingMessages: number;
outgoingMessages: number;
firstMessageAt: Date;
lastMessageAt: Date;
averageResponseTime: number; // in milliseconds
responseRate: number; // percentage (0-100)
messagesByType: Record<string, number>;
messagesByDay: Array<{
date: string;
count: number;
}>;
}
Calculate Customer Satisfaction
Copy
async function calculateCustomerSatisfaction(phoneNumber: string) {
const analytics = await client.getConversationAnalytics(phoneNumber);
// Fast response time (< 5 minutes) = good satisfaction
const avgResponseMinutes = analytics.averageResponseTime / 1000 / 60;
let satisfaction: 'Excellent' | 'Good' | 'Fair' | 'Poor';
if (avgResponseMinutes < 5) {
satisfaction = 'Excellent';
} else if (avgResponseMinutes < 30) {
satisfaction = 'Good';
} else if (avgResponseMinutes < 120) {
satisfaction = 'Fair';
} else {
satisfaction = 'Poor';
}
return {
satisfaction,
avgResponseMinutes: Math.round(avgResponseMinutes),
totalConversations: analytics.totalMessages,
responseRate: analytics.responseRate
};
}
// Usage
const satisfaction = await calculateCustomerSatisfaction('+1234567890');
console.log('Customer satisfaction:', satisfaction);
Team Performance Dashboard
Copy
async function getTeamPerformance(customerPhones: string[]) {
const performanceData = await Promise.all(
customerPhones.map(async (phone) => {
const analytics = await client.getConversationAnalytics(phone, {
from: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000) // Last 7 days
});
return {
customer: phone,
messages: analytics.totalMessages,
responseTime: analytics.averageResponseTime,
responseRate: analytics.responseRate
};
})
);
// Calculate team averages
const teamAvg = {
totalMessages: performanceData.reduce((sum, p) => sum + p.messages, 0),
avgResponseTime: performanceData.reduce((sum, p) => sum + p.responseTime, 0) / performanceData.length,
avgResponseRate: performanceData.reduce((sum, p) => sum + p.responseRate, 0) / performanceData.length
};
return {
individual: performanceData,
team: teamAvg
};
}
Export Conversation
Export conversation data for backup, compliance, or analysis purposes.Method Signature
Copy
client.exportConversation(
phoneNumber: string,
options?: {
format?: 'json' | 'csv';
dateFrom?: Date;
dateTo?: Date;
}
): Promise<ExportResult>
JSON Export
Copy
// Export as JSON
const jsonExport = await client.exportConversation('+1234567890', {
format: 'json'
});
console.log('Export data:', jsonExport.data);
console.log('Message count:', jsonExport.messageCount);
// Save to file
import fs from 'fs';
fs.writeFileSync(
'conversation-export.json',
JSON.stringify(jsonExport.data, null, 2)
);
CSV Export
Copy
// Export as CSV
const csvExport = await client.exportConversation('+1234567890', {
format: 'csv'
});
// CSV string ready for download
console.log(csvExport.data);
// Save to file
import fs from 'fs';
fs.writeFileSync('conversation-export.csv', csvExport.data);
Export with Date Range
Copy
// Export Q1 2024 messages
const q1Export = await client.exportConversation('+1234567890', {
format: 'json',
dateFrom: new Date('2024-01-01'),
dateTo: new Date('2024-03-31')
});
console.log(`Exported ${q1Export.messageCount} messages from Q1 2024`);
Automated Daily Backups
Copy
async function dailyBackup(customerPhones: string[]) {
const today = new Date().toISOString().split('T')[0];
for (const phone of customerPhones) {
const export = await client.exportConversation(phone, {
format: 'json',
dateFrom: new Date(Date.now() - 24 * 60 * 60 * 1000), // Last 24 hours
dateTo: new Date()
});
if (export.messageCount > 0) {
const filename = `backup-${phone}-${today}.json`;
fs.writeFileSync(filename, JSON.stringify(export.data));
console.log(`✅ Backed up ${export.messageCount} messages to ${filename}`);
}
}
}
// Run daily
dailyBackup(['+1234567890', '+0987654321']);
Advanced Query Patterns
Multi-Customer Search
Copy
async function searchAcrossCustomers(
customerPhones: string[],
searchText: string
) {
const results = await Promise.all(
customerPhones.map(async (phone) => {
const messages = await client.searchMessages({
text: searchText,
phoneNumber: phone,
limit: 10
});
return {
phone,
matchCount: messages.total,
matches: messages.messages
};
})
);
// Filter customers with matches
return results.filter(r => r.matchCount > 0);
}
// Usage
const matches = await searchAcrossCustomers(
['+1234567890', '+0987654321'],
'urgent'
);
Time-Based Analysis
Copy
async function getHourlyMessageDistribution(phoneNumber: string) {
const conversation = await client.getConversation(phoneNumber, {
dateFrom: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000) // Last 7 days
});
const hourlyDistribution = Array(24).fill(0);
conversation.messages.forEach(msg => {
const hour = new Date(msg.timestamp).getHours();
hourlyDistribution[hour]++;
});
return hourlyDistribution.map((count, hour) => ({
hour: `${hour}:00`,
messageCount: count
}));
}
// Usage
const distribution = await getHourlyMessageDistribution('+1234567890');
console.log('Peak hours:', distribution.filter(h => h.messageCount > 10));
Customer Segmentation
Copy
async function segmentCustomersByActivity(customerPhones: string[]) {
const segments = {
active: [], // > 50 messages in last 30 days
moderate: [], // 10-50 messages
inactive: [] // < 10 messages
};
const thirtyDaysAgo = new Date();
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
for (const phone of customerPhones) {
const analytics = await client.getConversationAnalytics(phone, {
from: thirtyDaysAgo
});
if (analytics.totalMessages > 50) {
segments.active.push(phone);
} else if (analytics.totalMessages >= 10) {
segments.moderate.push(phone);
} else {
segments.inactive.push(phone);
}
}
return segments;
}
Performance Tips
1. Use Pagination
Always paginate large result sets:Copy
// Good
const page1 = await client.getConversation(phone, { limit: 50, offset: 0 });
const page2 = await client.getConversation(phone, { limit: 50, offset: 50 });
// Avoid
const all = await client.getConversation(phone, { limit: 10000 });
2. Filter by Date
Narrow down queries with date ranges:Copy
// Good - specific date range
const recent = await client.searchMessages({
text: 'order',
dateFrom: new Date('2024-01-01'),
dateTo: new Date('2024-01-31')
});
// Avoid - searching all history
const all = await client.searchMessages({ text: 'order' });
3. Cache Frequent Queries
Copy
const cache = new Map();
const CACHE_TTL = 5 * 60 * 1000; // 5 minutes
async function getCachedAnalytics(phoneNumber: string) {
const cached = cache.get(phoneNumber);
if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
return cached.data;
}
const analytics = await client.getConversationAnalytics(phoneNumber);
cache.set(phoneNumber, {
data: analytics,
timestamp: Date.now()
});
return analytics;
}