How OpenWhispr Implements Content Protection for the Dictation Window

OpenWhispr protects sensitive UI elements by dynamically invoking Electron’s native setContentProtection API on the main window and floating dictation pill whenever screen captures occur or the Agent Panel opens.

OpenWhispr is an Electron-based voice dictation application that handles transient transcripts and private assistant conversations. To prevent these elements from appearing in screen recordings or video conferencing streams, the application implements a content protection system that leverages native operating-system-level window flags. The implementation centers on two runtime state flags and a central window management class that coordinates protection across multiple BrowserWindow instances.

Understanding the Content Protection Architecture

The protection mechanism relies on a dual-flag system that monitors UI state and triggers protection accordingly.

Runtime Privacy Flags

OpenWhispr tracks two boolean state properties that determine when content protection should be active:

  • _screenContextProtection – Enabled when the application captures a screenshot of the current screen to send as context to the voice assistant.
  • _assistantPanelOpen – Set to true while the Agent Panel (the LLM response interface) is visible to the user.

When either flag evaluates to true, the application assumes sensitive information is on-screen and enables protection.

The WindowManager Central Controller

All window-related operations reside in src/helpers/windowManager.js, which exports a WindowManager class. This class owns references to the main application window and the floating "Agent Dictation Pill," exposing methods to synchronize their protection states based on the runtime flags.

Implementation Details in windowManager.js

The core logic lives in the WindowManager class, where Electron’s setContentProtection API is called reactively.

Dynamic Protection Updates

The _updateMainContentProtection() method (lines 176–181) evaluates the current privacy flags and applies protection to the main window:

_updateMainContentProtection() {
  if (!this.mainWindow) return;
  
  this.mainWindow.setContentProtection(
    Boolean(this._screenContextProtection || this._assistantPanelOpen)
  );
}

This method is invoked whenever _screenContextProtection or _assistantPanelOpen changes value, ensuring the window is hidden from screen capture only when necessary.

Protecting the Floating Pill Window

When the Agent Panel opens, the application spawns a floating pill window for dictation controls. During initialization (lines 174–176), this window is explicitly marked as protected:

pillWindow.setContentProtection(true);

Unlike the main window, the pill window remains permanently protected because it may display live transcription text that should never appear in recordings.

Triggering Protection via IPC

The renderer process communicates state changes to the main process through IPC channels, which ultimately invoke the window manager’s protection methods.

Screen Context Protection

When the voice assistant captures a screen thumbnail, the renderer enables protection temporarily:

// Enable protection while capturing screenshot
ipcRenderer.invoke('set-screen-context-protection', true);

// Disable after capture completes
ipcRenderer.invoke('set-screen-context-protection', false);

These IPC calls toggle the _screenContextProtection flag and trigger _updateMainContentProtection().

Assistant Panel State

Opening the Agent Panel implicitly enables protection because _assistantPanelOpen becomes true:

// Show the assistant panel (enables protection)
ipcRenderer.send('toggle-assistant-panel', true);

// Hide the panel (may disable protection if no screenshot active)
ipcRenderer.send('toggle-assistant-panel', false);

The IPC handlers (typically defined in src/helpers/ipcHandlers.js or similar) forward these events to the WindowManager instance, which updates the protection state accordingly.

Practical Code Examples

Query Current Protection State

For debugging or UI indicators, you can check whether the dictation window is currently protected:

const isProtected = await ipcRenderer.invoke('is-content-protected');
console.log('Dictation window protected:', isProtected);

Complete Protection Flow

The following pattern demonstrates how a voice-assistant request orchestrates protection:

// 1. Prepare to capture screen context
await ipcRenderer.invoke('set-screen-context-protection', true);

// 2. Capture screenshot (window is now hidden from capture APIs)
const screenshot = await captureScreen();

// 3. Open agent panel (forces protection to remain active)
ipcRenderer.send('toggle-assistant-panel', true);

// 4. Send request with context
await sendToAssistant({ image: screenshot });

// 5. Cleanup when done
await ipcRenderer.invoke('set-screen-context-protection', false);
// Protection remains active only if panel is still open

Summary

  • Dual-flag system: OpenWhispr uses _screenContextProtection and _assistantPanelOpen to track when sensitive data is visible.
  • Centralized control: The WindowManager class in src/helpers/windowManager.js orchestrates all protection state via _updateMainContentProtection().
  • API usage: Electron’s setContentProtection(true) prevents the OS from including the window in screen recordings or streams.
  • Permanent pill protection: The floating dictation pill is always protected via pillWindow.setContentProtection(true) during creation.
  • IPC integration: Renderer processes toggle protection via set-screen-context-protection and toggle-assistant-panel channels.

Frequently Asked Questions

What is the setContentProtection API in Electron?

setContentProtection is a native Electron method available on BrowserWindow instances that instructs the operating system to exclude the window from screen captures, screen sharing, and screenshot APIs. When enabled, the window appears as a black rectangle or is omitted entirely from video streams in applications like Zoom, Teams, or OBS.

Why does OpenWhispr use two separate flags for content protection?

The two-flag design separates transient protection (screenshot capture that lasts seconds) from persistent UI state (Agent Panel visibility). This allows the main window to remain unprotected during normal dictation while ensuring protection during sensitive operations, optimizing usability while maintaining privacy.

Is the floating dictation pill always protected?

Yes. According to the source code in src/helpers/windowManager.js (lines 174–176), the pill window receives setContentProtection(true) immediately upon creation. Since the pill may display live transcription text that could contain sensitive information, it remains hidden from screen capture regardless of other application states.

How can I verify that content protection is active?

You can invoke the is-content-protected IPC channel from the renderer process to query the current state, or check the window behavior by attempting to capture the screen using system tools (the protected window will appear blank or missing in the resulting image).

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →