Skip to main content

openadapt-capture

Build Status PyPI version Python 3.10+ License: MIT

Record what a person does on a Windows or macOS desktop, then read it back in Python. Capture saves mouse clicks, drags, scrolls, keystrokes, and screen video to one local folder, and pairs every action with the screen frame from the moment it happened.

Use it when you need real demonstrations of GUI work: to build an automation or replay tool, to collect training or test data for a computer-use model, or to study how a task gets done. OpenAdapt uses it to record the demonstrations that it compiles into replayable programs.

Status: maintained. OpenAdapt uses it to record the demonstrations it compiles. Everything stays in a local folder.

Platform Records Notes
macOS Mouse, keyboard, screen video, accessibility Needs Screen Recording, Input Monitoring, and Accessibility permissions
Windows Mouse, keyboard, screen video, accessibility Needs a signed-in desktop session
Linux Mouse, keyboard, screen video; accessibility with the linux extra X11 only, not Wayland
Remote desktop Pixels only No accessibility data across the connection

Quick start

You need Python 3.10 or later, and before the first recording:

  • FFmpeg. Capture writes video with the ffmpeg executable on your PATH. If you don't have one, install FFmpeg with your package manager. On Capture 1.3.0 or later, capture install-ffmpeg can instead install a pinned, checksum-verified build for your user account.
  • macOS. In System Settings > Privacy & Security, allow your terminal app under Screen Recording, Input Monitoring, and Accessibility. Then quit and reopen the terminal.
  • Windows. Run from a signed-in desktop session.
pip install openadapt-capture
capture record ./my-capture --description "Rename a file"

If FFmpeg or a permission is missing, capture record stops before it records and says what to fix. Otherwise, do the task. To stop, press Ctrl+C in the terminal, or press Ctrl three times in any app. Then look at what you recorded:

capture info ./my-capture
from openadapt_capture import CaptureSession

with CaptureSession.load("./my-capture") as capture:
    for action in capture.actions():
        print(action.timestamp, action.type, action.x, action.y, action.text)
        frame = action.screenshot  # PIL image of the screen at that moment

What a recording contains

my-capture/
├── recording.db                     # actions, raw input events, window metadata (SQLite)
├── oa_recording-*.mp4               # screen video
├── capture-state.json               # whether the session finished and passed its integrity check
├── capture-artifact-manifest.json   # size and SHA-256 of every other file
├── capture-terminal.json            # completion record that covers the manifest
└── *.json                           # profiling data, and sign-in markers if you used them

Each action has a type (click, double-click, drag, scroll, typed text, or keyboard shortcut), screen coordinates, any typed text, and a timestamp. action.screenshot and action.after_screenshot give the frames before and after it.

Where the operating system exposes it, Capture also stores the accessibility element under each action: its role, name, bounds, available actions, and window, from Windows UI Automation or macOS Accessibility. Read it with action.structural_observation. Capture never guesses these fields from pixels. Turn this off with Recorder(..., capture_structural_observations=False).

Record from Python

from openadapt_capture import Recorder

with Recorder("./my-capture", task_description="Rename a file") as recorder:
    recorder.wait_for_ready()
    input("Do the task, then press Enter...")

To record one window instead of the whole desktop, pass window={"owner": "Parallels", "title": None} (substring match), or use capture record --window-owner Parallels. Coordinates are then in that window's own pixels, which is what remote-desktop clients such as RDP and Citrix need. Details: docs/WINDOW_CAPTURE.md.

To control a running recording from another process:

capture status --session-id SESSION_ID
capture stop --session-id SESSION_ID

capture record prints the session ID when it starts. From Python, use status_recording(session_id) and stop_recording(session_id, timeout=60). stop waits until the video and database are written and checked, and returns an error if anything is incomplete.

If the task includes signing in, wrap the sign-in in an authentication handoff. Capture then stops recording the screen, input, and accessibility data until the sign-in ends, and stores only a marker:

handoff = recorder.begin_authentication(
    methods="password_manager",
    requires_user_presence=True,
)
# Sign in.
recorder.end_authentication(handoff, outcome="completed")

See docs/AUTHENTICATION_HANDOFF.md.

Use it with OpenAdapt

To compile a recording into a program that replays the task, install OpenAdapt with this package as an extra. OpenAdapt needs Python 3.10, 3.11, or 3.12.

pip install "openadapt[capture]"
openadapt flow record --backend windows --out recording --task "Rename a file"
openadapt flow compile recording --out bundle --name rename-file

Other platforms, replay, and remote desktops are covered in the desktop recording guide. The compiler accepts left and right clicks, left-button drags, typed text, named keys, key combinations, and scrolling. It rejects a recording that contains anything else, such as a middle click.

FFmpeg

capture install-ffmpeg downloads one pinned FFmpeg build for your platform, checks its SHA-256 against a digest stored in this package, and installs it under your user data folder. Builds exist for macOS (Apple silicon and Intel), Linux x86-64, and Windows x86-64. --dry-run prints the URL, digest, and destination without downloading anything, and capture uninstall-ffmpeg removes the build. The package itself contains no FFmpeg, and Capture downloads nothing unless you run that command.

An FFmpeg you already set up takes priority. Capture looks in this order: Recorder(ffmpeg_path=...) or OPENADAPT_FFMPEG_PATH, then OPENADAPT_DESKTOP_FFMPEG_PATH, then OpenAdapt Desktop's runtime, then your PATH, and the installed build last. Before recording, Capture runs a short encode-and-decode test and refuses to start if it fails.

Microphone narration

capture record --audio also records your voice and transcribes it on this computer. It's off by default. It needs a local transcription backend:

pip install "openadapt-capture[transcribe-fast]"

Capture refuses --audio before it opens the microphone if no local backend is installed, and it deletes the audio after transcription unless you set RECORD_AUDIO_RETAIN_WAVEFORM.

Privacy

A recording can contain anything that was on screen or typed, including passwords and personal data. It stays on your computer. Capture uploads nothing unless you run capture share or set send_profile=True. The privacy extra installs openadapt-privacy but doesn't remove anything from a recording by itself.

Shadow-mode pattern mining, which notices repeated tasks and offers a draft, is off by default, needs the person's acknowledgement to turn on, and keeps no typed values. Its encrypted buffer lives in the unsynced app-data folder and is cleared, with its key destroyed, at least every 24 hours and when shadow mode stops. OpenAdapt never sends shadow mode data off the computer, but OS backup, sync, and endpoint security tools can still copy local files. See docs/SHADOW_MINING.md.

How Capture handles sensitive data, its licensing boundaries, and how releases are qualified are covered in docs/COMPLIANCE.md.

Limits

  • Recording needs a signed-in desktop session and the permissions listed in the quick start.
  • On Linux, recording needs an X11 session. Capture doesn't record under Wayland. It saves the text of a key only when an application receives the key. After a click or key that no application receives (for example, typing with no window focused), the rest of that recording saves each key's code but not its text. scripts/linux_xvfb_quickstart.sh runs the quick start on Linux in a container.
  • Accessibility data appears only where the application exposes it. Across a remote-desktop connection, Capture sees pixels only.
  • Changing a display (connecting a monitor, rotating, or changing resolution or scale) ends the recording. Start a new one afterward.
  • These need Capture 1.3.0 or later: capture install-ffmpeg, capture status and capture stop (and status_recording and stop_recording), authentication handoffs, action.after_screenshot, and the capture-*.json files. If pip install --upgrade openadapt-capture gives you an earlier version, install from GitHub: pip install "git+https://github.com/OpenAdaptAI/openadapt-capture".
  • For web apps, use OpenAdapt's browser recorder. The Chrome extension in experimental/ is an unfinished prototype and isn't part of the package.

Extras

Extra Adds
transcribe-fast Local transcription with faster-whisper
transcribe Local transcription with openai-whisper
privacy The openadapt-privacy library, for your own integration
share capture share, using Magic Wormhole
linux Accessibility observation on Linux (AT-SPI)
all All of the above

Development

uv sync --extra dev
uv run pytest -m "not slow"

The slow tests record for real, so they need a desktop session and the operating system permissions above:

uv run pytest -m slow

docs/DESIGN.md describes the recording pipeline.

License

MIT

Metadata

Release files for openadapt-capture 1.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for openadapt-capture 1.3.0
File Size Uploaded Provenance
openadapt_capture-1.3.0.tar.gz 1.1 MB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for openadapt-capture 1.3.0
File Interpreter ABI Platform
openadapt_capture-1.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 1.5 MB

Release files / openadapt_capture-1.3.0.tar.gz

Download URL openadapt_capture-1.3.0.tar.gz
Size 1.1 MB
Tags Source
SHA-256 checksum
How to use checksums
ebe5751b7ef0ec1db055ba63fc703378d6212714c7ac0a4bb7f78abb1d4655de
BLAKE2b-256 checksum
How to use checksums
bb92b9bb684d7fed4b9ef72c95087809d70775532791b240ef8ff2420b333da9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.

Transparency log

Release files / openadapt_capture-1.3.0-py3-none-any.whl

Download URL openadapt_capture-1.3.0-py3-none-any.whl
Size 345.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
dde6c7d4eabbcf4ef4c7c7e05355dfd9c5b2e101025e52469e3893d7a6d13ee2
BLAKE2b-256 checksum
How to use checksums
1b186013b718f6d015e86591ac48ed8937587f52527b1b3d43de647464245c59
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.

Transparency log

Security for openadapt-capture 1.3.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for openadapt_capture-1.3.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page