Recipe: webinars with recording, VOD and SRT transcripts
Host a webinar, record it to your own S3, publish the VOD, and generate subtitles automatically with a local Whisper worker. The full meeting-to-transcript pipeline.
Why own your webinars
A webinar is your content and, often, your leads. Running it on someone else's platform means their branding, their storage, their transcript quality and their price per attendee. StreamHub lets you host the meeting, record it to a bucket you own, publish the replay, and turn it into a searchable, subtitled asset — all on your infrastructure.
Architecture in words
Participants join a room with LiveKit tokens. When you record, egress writes an MP4 that a background job uploads to the app's S3 and indexes as a VOD. If transcription is enabled, the core extracts the audio, drops a file job for a local Whisper worker, builds an SRT from the result, and uploads it next to the VOD — so every recording gets subtitles with no API cost.
1. Create the app and configure S3
export BASE="https://your-server.example.com/api/v1"
export TOKEN="sk_...."
curl -s -X POST $BASE/apps -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"name":"webinars","displayName":"Webinars"}'
curl -X PUT $BASE/apps/webinars/s3 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"provider":"aws","bucket":"webinar-vods","region":"us-east-1","key":"AKIA...","secret":"..."}'
Credentials go to data/secrets.json, never the config or a log.
2. Admit participants
Mint join tokens per person. A host publishes; attendees can be subscribe-only:
# host
curl -s -X POST $BASE/apps/webinars/tokens -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"room":"q3-launch","identity":"host","canPublish":true}'
# attendee (watch only)
curl -s -X POST $BASE/apps/webinars/tokens -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"room":"q3-launch","identity":"guest-42","canPublish":false,"canSubscribe":true}'
3. Record the session
curl -s -X POST $BASE/apps/webinars/recording/start -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"roomName":"webinars-q3-launch"}'
# → { "data": { "vodId": 12, "egressId": "EG_xxx", "status": "recording" } }
When egress ends, the upload job runs and the VOD moves through uploading to ready, firing vod_ready. Recording honors max_recording_minutes_month.
4. Turn on transcription
Install the transcription app with the local Whisper provider (open source, no API bill):
curl -X POST $BASE/apps/webinars/plugins/transcription/install -H "Authorization: Bearer $TOKEN"
curl -X PATCH $BASE/apps/webinars/plugins/transcription -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"enabled": true, "config": {"provider": "local", "model": "small", "language": "auto", "autoTranscribe": true}}'
With autoTranscribe: true, every VOD is transcribed when it turns ready. The core drops jobs into apps/webinars/transcripts/jobs/, the worker writes results to .../results/, and the SRT is uploaded to your bucket next to the MP4.
5. Fetch the VOD and the subtitles
curl -s $BASE/apps/webinars/vods -H "Authorization: Bearer $TOKEN"
curl -s $BASE/apps/webinars/vods/12/transcript -H "Authorization: Bearer $TOKEN"
curl -s $BASE/apps/webinars/vods/12/transcript.srt -H "Authorization: Bearer $TOKEN" -o q3-launch.srt
GET .../transcript returns the status, full text, timed segments and a fresh presigned srtUrl; .../transcript.srt rebuilds the file from stored segments even if the S3 upload failed. To re-run on demand, POST .../vods/12/transcribe.
What you should see
After the webinar ends, a VOD appears and turns ready; shortly after, its transcript status goes ready with an SRT in your bucket and downloadable subtitles. Point your VOD player at the url and load the SRT as a caption track.
Troubleshooting
- Transcript never appears — confirm the transcription app is enabled and the VOD reached
ready(transcription runs off the finished recording). - Only one giant subtitle cue — the OpenAI
gpt-4o-transcribemodels return text only; use the local worker orwhisper-1, which return timed segments for proper SRT. - Recording heavy on CPU — composite recording uses headless Chrome; for a single-presenter webinar,
recordMode: trackrecords one publisher via ffmpeg instead.
Closing
Your webinars, your bucket, your transcripts — no per-attendee pricing and no third-party transcript service. If you want a gated replay portal, automatic chaptering, or translated subtitles built on this pipeline, our team assembles that on top of the open-source core.