📋 Overview
The WebSocket Chat plugin enables real-time messaging in your Bubble native mobile apps. This guide will walk you through setting up a basic WebSocket server and connecting it to your Bubble app.
🚀 Quick Start
1 Set Up WebSocket Server
First, let's create a simple WebSocket server. You'll need Node.js installed on your server.
Install Dependencies
mkdir websocket-chat-server
cd websocket-chat-server
npm init -y
npm install express ws
Create Server File
Create a file named server.js:
const express = require('express');
const http = require('http');
const WebSocket = require('ws');
const app = express();
const server = http.createServer(app);
const wss = new WebSocket.Server({ server });
// Store connected clients by room
const rooms = {};
// Store recent messages in memory (simple implementation)
const messageHistory = {};
// Helper: Add client to room
function addToRoom(roomId, ws) {
if (!rooms[roomId]) {
rooms[roomId] = new Set();
}
rooms[roomId].add(ws);
console.log(`Client added to room ${roomId}. Total: ${rooms[roomId].size}`);
}
// Helper: Remove client from room
function removeFromRoom(roomId, ws) {
if (rooms[roomId]) {
rooms[roomId].delete(ws);
if (rooms[roomId].size === 0) {
delete rooms[roomId];
}
}
}
// Helper: Broadcast message to room
function broadcastToRoom(roomId, message) {
if (!rooms[roomId]) return;
const messageStr = JSON.stringify(message);
rooms[roomId].forEach(client => {
if (client.readyState === WebSocket.OPEN) {
client.send(messageStr);
}
});
}
// Helper: Save message to history
function saveMessage(roomId, message) {
if (!messageHistory[roomId]) {
messageHistory[roomId] = [];
}
messageHistory[roomId].push(message);
// Keep only last 100 messages
if (messageHistory[roomId].length > 100) {
messageHistory[roomId].shift();
}
}
// Helper: Get message history
function getHistory(roomId, limit = 50) {
if (!messageHistory[roomId]) return [];
const history = messageHistory[roomId];
const start = Math.max(0, history.length - limit);
return history.slice(start);
}
// WebSocket connection handler
wss.on('connection', (ws) => {
console.log('New client connected');
let currentRoom = null;
ws.on('message', (data) => {
try {
const message = JSON.parse(data);
console.log('Received:', message);
// Handle get_history request
if (message.action === 'get_history') {
currentRoom = message.room;
addToRoom(currentRoom, ws);
const history = getHistory(currentRoom, message.limit || 50);
ws.send(JSON.stringify({
type: 'history',
messages: history
}));
}
// Handle send_message request
else if (message.action === 'send_message') {
const roomId = message.room;
const messageData = {
id: Date.now().toString() + Math.random(),
text: message.text,
sender: message.sender,
sender_id: message.user_id,
timestamp: message.timestamp || new Date().toISOString()
};
// Save to history
saveMessage(roomId, messageData);
// Broadcast to all clients in room
broadcastToRoom(roomId, {
type: 'message',
...messageData
});
console.log(`Message sent to room ${roomId}`);
}
} catch (error) {
console.error('Error:', error);
}
});
ws.on('close', () => {
if (currentRoom) {
removeFromRoom(currentRoom, ws);
}
console.log('Client disconnected');
});
});
// HTTP endpoint for sending messages via API
app.use(express.json());
app.post('/api/send-message', (req, res) => {
try {
const { user_id, room, text, sender, timestamp } = req.body;
if (!user_id || !room || !text) {
return res.status(400).json({
success: false,
error: 'Missing required fields: user_id, room, text'
});
}
const messageData = {
id: Date.now().toString() + Math.random(),
text: text,
sender: sender || 'User',
sender_id: user_id,
timestamp: timestamp || new Date().toISOString()
};
// Save to history
saveMessage(room, messageData);
// Broadcast to WebSocket clients
broadcastToRoom(room, {
type: 'message',
...messageData
});
res.json({ success: true, message_id: messageData.id });
} catch (error) {
res.status(500).json({ success: false, error: error.message });
}
});
// Health check endpoint
app.get('/health', (req, res) => {
res.json({ status: 'ok', connections: wss.clients.size });
});
// Start server
const PORT = process.env.PORT || 8080;
server.listen(PORT, () => {
console.log('========================================');
console.log(`WebSocket Server running on port ${PORT}`);
console.log(`WebSocket: ws://localhost:${PORT}`);
console.log(`HTTP API: http://localhost:${PORT}/api/send-message`);
console.log('========================================');
});
Run the Server
node server.js
2 Configure Bubble Plugin
In your Bubble app, add the WebSocket Chat element and configure these properties:
| Property | Value | Example |
|---|---|---|
| websocket_server | Your server URL | ws://your-domain.com:8080 |
| current_user_id | Current User's unique ID | Current User's unique id |
| current_user_name | Current User's name | Current User's name |
| room_id | Conversation/room identifier | Get data from URL → room_id |
3 Add Message Input
Create the UI for sending messages:
- Add a Text Input element
- Add a Button labeled "Send"
- Create a workflow on the button click:
- Action: Plugins → WebSocket Chat → Send Message
- Element: Your chat element
- message_text: Input's value
- Add another action to clear the input
📡 Message Protocol
Messages Plugin Sends to Server
Get History Request
{
"action": "get_history",
"user_id": "user123",
"room": "room456",
"limit": 50
}
Send Message Request
{
"action": "send_message",
"text": "Hello, this is my message",
"user_id": "user123",
"sender": "John Doe",
"room": "room456",
"timestamp": "2026-01-11T22:38:04.014Z"
}
Messages Server Sends to Plugin
History Response
{
"type": "history",
"messages": [
{
"id": "msg_001",
"text": "Hello!",
"sender": "Jane Smith",
"sender_id": "user789",
"timestamp": "2026-01-11T20:15:00.000Z"
}
]
}
New Message Broadcast
{
"type": "message",
"id": "msg_003",
"text": "New message here",
"sender": "Jane Smith",
"sender_id": "user789",
"timestamp": "2026-01-11T22:38:04.014Z"
}
🔧 Sending Messages via HTTP API
You can send messages to the chat from your backend using the HTTP endpoint:
Using cURL
curl -X POST http://your-domain.com:8080/api/send-message \
-H "Content-Type: application/json" \
-d '{
"user_id": "user123",
"room": "room456",
"text": "Hello from the server!",
"sender": "Admin"
}'
Using JavaScript
fetch('http://your-domain.com:8080/api/send-message', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
user_id: 'user123',
room: 'room456',
text: 'Hello from JavaScript!',
sender: 'System'
})
})
.then(response => response.json())
.then(data => console.log('Success:', data));
Using PHP
<?php
$url = 'http://your-domain.com:8080/api/send-message';
$data = array(
'user_id' => 'user123',
'room' => 'room456',
'text' => 'Hello from PHP!',
'sender' => 'Backend'
);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
$result = curl_exec($ch);
curl_close($ch);
echo $result;
?>
🎨 Customization Options
Display Options
- reverse_message_order: Show newest messages at top (yes) or bottom (no)
- show_built_in_ui: Use plugin's UI (yes) or build your own (no)
- show_status_bar: Display connection status
Styling Properties
Customize colors, sizes, and appearance:
- my_message_color - Background for your messages
- other_message_color - Background for other messages
- message_border_radius - Rounded corners
- container_background_color - Chat background
- And many more text colors and sizes!
🚢 Production Deployment
- Use wss:// (secure WebSocket) with SSL certificates
- Use a process manager like PM2 to keep the server running
- Add authentication and authorization
- Store messages in a database instead of memory
- Implement rate limiting and security measures
Using SSL (wss://)
To use secure WebSocket connections, modify your server:
const https = require('https');
const fs = require('fs');
const SSL_OPTIONS = {
key: fs.readFileSync('/path/to/your/ssl.key'),
cert: fs.readFileSync('/path/to/your/ssl.crt')
};
const server = https.createServer(SSL_OPTIONS, app);
// Then use wss://your-domain.com:8080
🔍 Troubleshooting
Can't Connect to Server
- Check if server is running: curl http://your-domain.com:8080/health
- Verify firewall allows connections on port 8080
- Use ws:// for testing (not wss://)
Messages Not Appearing
- Check server logs for errors
- Verify room_id matches between users
- Ensure all required fields are present in messages
"My" Messages on Wrong Side
- Ensure sender_id exactly matches current_user_id
- Both must be strings and match character-for-character