Skip to content

Blazor Screen Recorder

B. Ganesh
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 getDisplayMedia to 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

  1. Start Sharing: The user selects which screen or window to capture.
  2. Preview: The captured stream is displayed in an HTML video element.
  3. Record/Pause/Resume: The user controls the flow of the recording.
  4. Stop & Download: The recording is finalized, converted into a Blob URL, and made available for download as an .mp4 or .webm file.

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