← All field notes

Engineering

Building a privacy window with ScreenCaptureKit

What Apple’s public screen-capture APIs can filter, why ScreenK9 is a separate window, and where the product boundary must stay explicit.

ScreenK9 team 7 min read
SAFE / ENGINEERINGAudience view

ScreenK9’s core promise depends on a narrow architectural choice: create a filtered display representation inside an ordinary macOS window. Do not inject into Zoom or Meet. Do not claim control over a physical display shared directly from another app.

Apple’s public ScreenCaptureKit documentation supports this model. An app retrieves shareable displays, applications, and windows, creates an SCContentFilter, configures an SCStream, and receives video frames.

Application filters are the first privacy layer

ScreenCaptureKit provides display filters that can include only selected applications or exclude selected applications. It also supports window exceptions. That gives ScreenK9 two useful modes:

  • Allow only includes selected work applications. This is the default for a high-stakes profile.
  • Hide selected captures a broader display while excluding chosen applications and system surfaces.

ScreenK9 excludes its own process to avoid recursive capture. It can also exclude Finder, notification surfaces, Dock, and menu-bar components according to the active profile.

Apple’s macOS capture sample demonstrates the same basic pattern: retrieve SCShareableContent, construct a content filter, configure frame size and rate, and start a stream.

Why Chrome needs a companion

At the operating-system layer, multiple Chrome profiles still belong to Chrome. Application filtering alone cannot express “allow Acme Work, hide Personal.”

A Manifest V3 extension runs separately inside each Chrome profile, so it is a natural place for the user to classify that profile. Chrome’s Native Messaging API lets the extension exchange JSON messages with a local helper installed by the Mac app.

ScreenK9 excludes Chrome first. Fresh work-window matches are then added back as explicit window exceptions. If a work title collides with a personal title, neither match is trusted. This is intentionally stricter than guessing.

Redactions belong to the audience window

Some privacy rules are spatial rather than application-level: hide the browser identity bar, a customer-name panel, or a stable corner of a dashboard. ScreenK9 draws those zones on top of the captured frame in its audience window.

The presenter’s real screen remains unchanged. The meeting tool sees the composed window—including the privacy zones—because that is the window the user chose to share.

Redactions are not optical character recognition, automatic secret detection, or a guarantee that a page layout will never move. The MVP treats them as user-configured regions and describes them that way.

The separate-window boundary

ScreenK9 cannot rewrite another application’s full-display stream using public APIs. If someone chooses their physical display in Zoom, Zoom captures that display outside ScreenK9’s pipeline.

The safe workflow is therefore visible and testable:

  1. ScreenK9 prepares its stream.
  2. The audience window remains on a placeholder until a complete frame arrives.
  3. The user verifies the preview.
  4. The user shares that specific window.

Good architecture does not make the boundary disappear. Good product design makes it hard to misunderstand.