Skip to main content
Version: 0.28.0

How to Deploy Fishjam to Production

How-to Guide - Deploy your Fishjam backend safely to production

This guide covers the essential steps to move from development (using the Sandbox API) to a production-ready Fishjam backend deployment.

Prerequisites

  • Working Fishjam backend (see Backend Quick Start)
  • A Fishjam account on the Standard Jar plan (recommended for production deployments)
  • Domain and SSL certificates for your backend
  • Production database and infrastructure

Step 1: Get your Fishjam credentials

Get credentials from the dashboard

  1. Log in to Fishjam Dashboard
  2. Copy your Fishjam ID and Management Token from the dashboard

Environment variables setup

Create your environment variables:

# Fishjam credentials FISHJAM_ID="your-fishjam-id" FISHJAM_MANAGEMENT_TOKEN="your-management-token" # Your application settings NODE_ENV="production" PORT="3000" DATABASE_URL="your-production-database-url" # Security settings JWT_SECRET="your-secure-jwt-secret" CORS_ORIGIN="https://yourdomain.com"

Step 2: Replace Sandbox API with proper authentication

Replace Sandbox API calls

Remove any Sandbox API dependencies from your client code:

// ❌ Remove: Sandbox API calls const peerToken = await getSandboxPeerToken(roomName, userName); // ✅ Replace with: Your authenticated API const response = await fetch("https://your-backend.com/api/join-room", { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${userToken}`, }, body: JSON.stringify({ roomName, userName }), });

Implement user authentication

Wire up the Fishjam client and your own authentication. The middleware below verifies the caller and attaches the user, so the next handler can mint a peer token for them.

const fishjamClient = new FishjamClient({ fishjamId: process.env.FISHJAM_ID!, managementToken: process.env.FISHJAM_MANAGEMENT_TOKEN!, }); const app = express(); app.use(express.json()); // parse JSON request bodies // Your own auth (JWT, session, ...) const authenticateUser = async ( req: express.Request, res: express.Response, next: express.NextFunction, ) => { const token = req.headers.authorization?.replace("Bearer ", ""); if (!token) return res.status(401).json({ error: "Unauthorized" }); req.user = jwt.verify(token, process.env.JWT_SECRET); next(); };

Create a room and add a peer

Now expose the endpoint your client calls to join the room. Fishjam rooms are identified by an id, so keep a mapping from your own room name to the Fishjam room id and create the room lazily on first join. Then add a peer tagged with the authenticated user and return its peer token.

// Map your room name to a Fishjam room id (use your database in production) const roomIds = new Map<string, RoomId>(); const getOrCreateRoom = async (roomName: string): Promise<RoomId> => { const existing = roomIds.get(roomName); if (existing) return existing; const room = await fishjamClient.createRoom(); roomIds.set(roomName, room.id); return room.id; }; // Mint a Fishjam peer token for the authenticated user app.post("/api/join-room", authenticateUser, async (req, res) => { const { roomName } = req.body; const roomId = await getOrCreateRoom(roomName); const { peerToken } = await fishjamClient.createPeer(roomId, { metadata: { userId: req.user.userId }, }); res.json({ peerToken }); });

(Optional) Step 3: Handle webhooks and events

You may wish to receive events from Fishjam regarding created rooms and peers. All you need for this is a single api endpoint:

Webhook endpoint

Fishjam delivers notifications as a binary application/x-protobuf body. Read the raw body and decode it with the SDK, then react to the events you care about.

app.post( "/api/webhooks/fishjam", express.raw({ type: "application/x-protobuf" }), (req: express.Request, res: express.Response) => { for (const { type, notification } of decodeServerNotifications(req.body)) { switch (type) { case "peerConnected": handlePeerConnected(notification); break; case "peerDisconnected": handlePeerDisconnected(notification); break; case "roomDeleted": handleRoomDeleted(notification); break; default: break; } } res.status(200).json({ received: true }); }, );

Enabling webhooks

Now, with your endpoint setup, all you need to do is supply your webhook endpoint to Fishjam when creating a room. We also recommend enabling batchWebhookNotifications, which delivers notifications faster and with fewer HTTP requests for a better backend response time under load:

const createRoomWithWebhooks = async (roomType = "conference") => { const room = await fishjamClient.createRoom({ roomType, webhookUrl: `${process.env.BASE_URL}/api/webhooks/fishjam`, // Coalesce notifications into batches for faster delivery and fewer requests batchWebhookNotifications: true, }); return room; };

Common production issues

Issue: Token expiration handling

Peer tokens expire 24h after creation. We encourage keeping room and peer lifetimes as short as possible (typically a single room corresponds to a single video call or stream). However, if you wish to reuse a single peer over multiple days, you can make use of token refreshing:

const newToken = fishjamClient.refreshPeerToken(roomId, peerId);

See also

For scaling considerations:

For specific backend frameworks: