Personal Loom
Screen and camera recording, self-hosted. The record to link loop, no pricing gate.
- Python
- FastAPI
- Browser recorder
Loom's free plan stops a recording at five minutes, caps you at twenty-five videos, and lets the old ones go inactive. Business is $18 a seat per month, $24 with AI. I record short walkthroughs a few times a week, mostly for myself. That isn't a $216-a-year problem.
The part worth paying for is one interaction. You press stop and the link is already on your clipboard. So that's what I rebuilt. Press record in a browser tab, press stop, land on the watch page with the link copied. No upload screen. No confirm step.
Counting what Loom actually is
Before writing code I sorted Loom's documented surface: 169 capabilities across 34 categories, from 88 source pages. Fifty-seven to keep. Thirty-one optional. Eighty-one to skip.
That last number is the argument. Roughly half of Loom is single sign-on, role permissions, workspace admin, seat billing and security training. None of it exists when the workspace is one person. What's left is a video app small enough to finish.
The scan turned up one more thing. When I checked in July, loom.com/record was a 404. Loom had moved recording into a desktop app or an extension. Mine needs nothing installed.
Two bugs that broke the only promise
The first version composited screen and camera onto a canvas driven by requestAnimationFrame. Browsers pause that in background tabs. So the recording froze the moment you switched tabs, which is the entire use case. Screen-only and camera-only now record the source track directly and can't freeze. Screen plus camera drives the canvas from a Web Worker timer, which browsers don't throttle.
The second looked fine until playback. A full Retina capture is 3456 by 1924, variable frame rate, almost no keyframes, and the decoder gave up partway through with MEDIA_ERR_DECODE. So the server re-encodes on upload: 1920 wide at most, constant 30fps, a keyframe every two seconds, moov atom at the front so it seeks. If ffmpeg fails it keeps the raw file rather than lose the take. Eight in my own library are still WebM.
The take is sacred
A recorder that loses a finished take is worse than one with fewer features. So the blob goes into IndexedDB before the upload starts, and clears only when the server confirms receipt. A failed upload keeps the take and offers Retry and Download. A take that never made it up is handed back next time you open the app. Over the cap returns a 413, out of disk a 507, each with a sentence a person wrote.
The same stubbornness went into the password gate. Locking a video withholds the file, the thumbnail, the hover preview, the captions, the transcript cues, the title and the social unfurl. Not just the stream. The signing secret is generated per install and written 0600 into the data directory, never a shared default.
What it doesn't do
No accounts, no teams, no multi-tenant anything. That's the design, not a gap. Transcripts and chapters are an opt-in layer. faster-whisper writes the WebVTT, gpt-4o-mini writes the title, summary and chapters, and the app runs fine with neither installed. The required install is five Python packages.
The recorder captures WebM even in Chrome, because Chrome's own MP4 path can emit a bitstream that stalls the decoder. That one is a choice. On macOS, Chrome can't capture system audio at all, only your microphone or the sound of a shared tab. That one is a gap, and it's logged in the manual.
It runs on localhost. Sharing past my own machine means putting the server behind HTTPS myself, the honest price of self-hosting. Thirteen recordings in the library so far. One of them is thirteen seconds long, came back transcribed into German, and got four AI chapters. Three of them start after the video ends.
Stack: Python and FastAPI over SQLite with FTS5, because the server is really just "store a blob, return an id, serve it back with Range support" and that wants a database file rather than a server. Capture is plain browser JavaScript with no framework, since getDisplayMedia and MediaRecorder only exist there anyway. ffmpeg does the rest: re-encode, thumbnails, hover previews, silence detection, trimmed exports.