Blazor Screen Recorder
Blazor is a .NET web UI framework that offers a component-based programming model for building web UIs.
In this post, we’ll explore how I built a fully functional screen recorder using Blazor WebAssembly. This application allows users to capture their screen, include system audio, and download the resulting recording—all running entirely in the browser without server-side processing.
Let’s get started!
If you want a video-version of this article, watch here on YouTube:
Watch the Video: Blazor Screen Recorder
Link to the project source code:
Source code: Blazor Screen Recorder
The Core Concept: Browser APIs
To build a screen recorder that gets rendered in a web browser, we rely on specific Browser APIs built into modern browsers like Chrome, Firefox, and Edge:
- Media Devices API: Provides access to the user’s screen, camera, and microphone. Specifically, we use
getDisplayMediato capture screen content. - Media Recorder API: Takes the media stream from the devices and handles the actual recording of data.
When we build our app using Blazor, we bridge the gap between .NET and these JavaScript-based APIs using JavaScript Interop.
Application Workflow
- Start Sharing: The user selects which screen or window to capture.
- Preview: The captured stream is displayed in an HTML
videoelement. - Record/Pause/Resume: The user controls the flow of the recording.
- Stop & Download: The recording is finalized, converted into a Blob URL, and made available for download as an
.mp4or.webmfile.
Technical Implementation
1. The Component Structure
The project consists of a Razor component (ScreenRecorder.razor) and a collocated JavaScript module (ScreenRecorder.razor.js). This structure ensures JavaScript Isolation, meaning the scripts are only loaded when the component is active. The component contains a video element where the screen gets previewed.
2. Managing State
The UI transitions through different states using a RecorderState enum:
- Idle: Shows the “Start Sharing” button.
- NotRecording: Screen is being previewed; “Record” button is visible.
- Recording: Active recording; “Pause”, “Resume”, and “Stop” buttons are visible.
- RecordingComplete: Shows “Restart” and “Download” buttons.
3. JavaScript Interop Highlights
To start the process, Blazor uses IJSRuntime to call a JavaScript function called addScreenToVideo when the “Start Sharing” button is clicked. This function talks to the browser’s MediaDevices API:
export async function addScreenToVideo(videoElement, screenOptions, dotnetHelper) {
const stream = await navigator.mediaDevices.getDisplayMedia(screenOptions);
videoElement.srcObject = stream;
videoElement.muted = true; // Prevents feedback loops
// Handle the "Stop Sharing" button built into the browser
stream.getVideoTracks()[0].onended = () => {
dotnetHelper.invokeMethodAsync('ScreenEnded');
};
}
4. Handling the Recording
The MediaRecorder takes the stream and stores binary data in “chunks.” When the user stops the recording, these chunks are combined into a Blob.
// Determining the best format supported by the browser
const mimeType = MediaRecorder.isTypeSupported('video/mp4') ? 'video/mp4' : 'video/webm';
const recorder = new MediaRecorder(stream, { mimeType });
recorder.ondataavailable = (event) => {
chunks.push(event.data);
};
Once stopped, the JavaScript code creates a URL for the blob and passes it back to Blazor:
const blob = new Blob(chunks, { type: mimeType });
const mediaBlobUrl = URL.createObjectURL(blob);
dotnetHelper.invokeMethodAsync('RecordComplete', mediaBlobUrl, extension);
Error Handling
The entire Interop call is wrapped in a try-catch block. If a user cancels the screen-sharing prompt, the JSException is caught, and a user-friendly message is displayed in the UI.
Summary
By combining the power of .NET/C# with the native capabilities of the browser, we can create high-performance tools like screen recorders. This approach leverages JavaScript Interop for hardware access while maintaining the application logic within the Blazor ecosystem.
For the full source code review and a step-by-step demo, you can watch the original video here: https://www.youtube.com/watch?v=Hf00Y5XcESA