What better way to understand deeply media apis provided by modern browsers than to build something cool?
In this blog post, I’ll be documenting my approach, tools, implementation details, and services used while building my own Loom-inspired video recorder.
If you’re an engineer like me and want to dive straight into the code, the repo is available here 👉 GitHub Repository
Tech Stack & Third-Party Dependencies
The project is built using a modern web stack:
-
Next.js — App routing, server actions & API routes
-
React — Component-based UI architecture
-
PostgreSQL — Database for persisting user and video metadata
-
Google & GitHub OAuth — Seamless social authentication
-
Prisma — Type-safe ORM for database management
-
TailwindCSS — Rapid styling and responsive design
Understanding Social Auth (From My POV)
I implemented OAuth authentication with both Google and GitHub from scratch, which gave me a deeper understanding of how social authentication works under the hood.
This process involved:
- Handling the authorization code exchange
- Fetching access tokens
- Retrieving user profile data via Next.js API routes
Both providers have slightly different flows, but getting them to work seamlessly together was incredibly rewarding.
Video Recording with the MediaRecorder API
const [isRecording, setIsRecording] = useState(false);
const mediaRecorderRef = useRef<MediaRecorder | null>(null);
const recordedChunks: Blob[] = [];
const startRecording = async () => {
const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
mediaRecorderRef.current = new MediaRecorder(stream, { mimeType: "video/webm" });
mediaRecorderRef.current.ondataavailable = (e) => {
if (e.data.size > 0) recordedChunks.push(e.data);
};
mediaRecorderRef.current.onstop = () => {
const blob = new Blob(recordedChunks, { type: "video/webm" });
const videoUrl = URL.createObjectURL(blob);
console.log("Recorded video URL:", videoUrl);
};
mediaRecorderRef.current.start();
setIsRecording(true);
};
Handling Media Streams & Uploads
Once recording worked, I moved on to uploading videos efficiently.
I used the FormData
API to send the recorded blob to the backend, which handles storage via Cloudinary.
This allowed me to easily manage uploads, generate thumbnails, and display the video later on the frontend.
Listing & Deleting Videos
I also implemented endpoints, server actions, and a management UI for user videos.
This included:
- Fetching a user’s uploaded videos
- Deleting videos by ID
- Displaying thumbnails, titles, and timestamps
With this, the full loop was complete:
Record ➝ Upload ➝ Manage ✅
⚠️ Major Challenge — Mobile Recording
One ongoing challenge I’m facing is recording on mobile devices.
For some reason, mobile browsers often fail to start recording or capture either audio or video. I suspect this is due to:
- Permission handling differences across mobile browsers
- Limited MIME type support for MediaRecorder
- Streaming of videos in chunks instead of sending the whole binary Object accross a single request
Still debugging this. If you’ve solved this before, I’d love to hear from you!
🌐 Links
Live Demo: loop.oauife.uk
Source Code: github___repo
🧭 Conclusion
For me, building tools and clones is the best way to deeply understand new technologies.
Throughout this project, I learned a lot about:
- Browser APIs
- Real-time media handling
- The full-stack flow from recording to upload
Every challenge taught me something new and that’s what makes this journey fun.
If you’ve experimented with MediaRecorder or mobile stream capture, I’d love your insights!
Feel free to reach out at badejoemmanuel805@gmail.com
Please check out Loop let me know what you think! 🙌