DocsAdministration

Jibri Recording Setup

Wiring Jitsi Broadcasting Infrastructure for live class recording

OptiLearn supports recording live classes via Jibri (Jitsi Broadcasting Infrastructure). The OptiLearn side is already wired — host UI, start/stop endpoints, webhook verification, recording-ready notification fan-out. What's left as ops work is provisioning Jibri itself in your Coolify Jitsi deployment.

If Jibri isn't configured, hosts will see a friendly "contact your administrator" message when they try to record. The rest of the live class system works fine.

What needs to happen

  1. Add the Jibri sidecar to your Coolify Jitsi deployment
  2. Configure Jibri to upload recordings to a reachable URL (R2 / S3 / any public storage)
  3. Configure Jibri's webhook plugin to call back to OptiLearn
  4. Set the two OptiLearn env vars

The actual Jibri setup steps are out of scope for this doc — they vary by Jitsi distribution and Coolify version. Use the official docs as your primary reference:

OptiLearn-side environment variables

Set both on the OptiLearn web service (and copy to the worker, though the worker doesn't read them directly):

VariablePurpose
JITSI_RECORDING_API_TOKENBearer token used by startJibriRecording / stopJibriRecording to call the Jibri-enabled meet server. Must match what Jibri's API is configured to accept.
JITSI_RECORDING_WEBHOOK_SECRETHMAC secret for verifying inbound Jibri callbacks. Must match the secret configured in Jibri's webhook plugin.

If JITSI_RECORDING_API_TOKEN is unset (or the meet server returns 404 on the recording endpoint), POST /api/live-sessions/[id]/recording/start returns 503 with a friendly message. The host UI can show "contact your administrator" without surfacing a generic 500.

If JITSI_RECORDING_WEBHOOK_SECRET is unset, the webhook endpoint refuses every inbound request with 503. This refuses-rather-than-defaults posture exists so anyone on the public internet can't post arbitrary recording URLs while you're mid-deploy.

The webhook endpoint

Jibri must be able to reach this URL with a public callback:

POST https://learn.opticrm.app/api/webhooks/jitsi-recording

Configure Jibri's webhook plugin to:

  • POST to that URL on recording_uploaded and recording_failed events
  • Sign the body with HMAC-SHA256 using the same secret as JITSI_RECORDING_WEBHOOK_SECRET
  • Send the signature in either X-Jibri-Signature: <hex> or X-Jibri-Signature: sha256=<hex> (both accepted)

Expected payload shape — see Recording API.

Local testing

Jibri must reach OptiLearn's webhook URL. For local dev you need a tunnel:

# Example with cloudflared
cloudflared tunnel --url http://localhost:3001
# → https://abc-def.trycloudflare.com

# Set NEXTAUTH_URL to the tunnel URL so Jibri's callback header is right
NEXTAUTH_URL=https://abc-def.trycloudflare.com npm run dev -- -p 3001

Then point Jibri's webhook config at https://abc-def.trycloudflare.com/api/webhooks/jitsi-recording.

End-to-end flow

Host clicks "Record"
  → POST /api/live-sessions/[id]/recording/start
  → OptiLearn flips status to PENDING, calls Jibri API
  → Jibri starts capturing, OptiLearn flips to RECORDING

Host clicks "Stop"
  → POST /api/live-sessions/[id]/recording/stop
  → OptiLearn flips status to PROCESSING, calls Jibri API
  → Jibri finishes, uploads to storage

Jibri callback
  → POST /api/webhooks/jitsi-recording (signature-verified)
  → OptiLearn stores recordingUrl, flips to READY
  → Fans LIVE_CLASS_RECORDING_READY out to enrolled students

Verifying setup

  1. Schedule a live session with a small test cohort
  2. Start the session, click Record (host only)
  3. Check OptiLearn's LiveSession row — recordingStatus = PENDING, then RECORDING
  4. Stop after ~30s — recordingStatus = PROCESSING
  5. Wait for Jibri to upload and call back — recordingStatus = READY, recordingUrl set
  6. Enrolled students should receive LIVE_CLASS_RECORDING_READY
  7. The recording link appears under the session detail

If anything stalls, check:

  • OptiLearn logs for the start/stop request and webhook receipt
  • Jibri logs for the upload result
  • That the webhook URL is publicly reachable (use curl -X POST from outside)
  • That HMAC signatures match (most common cause of 401 on the webhook)

Status state machine

See Recording API — Status state machine for the full diagram.