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: