UI trace tool for macOS: record and playback user interactions
Project description
uitrace
UI trace tool for macOS: record and playback user interactions.
Features
- Record mouse clicks and scrolls in any macOS window
- Play back recordings with speed control and step slicing
- Structured JSONL trace format with strict Pydantic v2 validation
- Dry-run mode for CI/automated testing (no permissions required)
- Permission diagnostics via
doctorcommand
Requirements
- macOS (Apple Silicon or Intel)
- Python 3.12+
- uv (recommended)
Quick Start
uv sync
uv run uitrace --help
Permissions
uitrace requires macOS system permissions depending on the command:
| Command | Accessibility | Input Monitoring | Screen Recording |
|---|---|---|---|
list |
- | - | Optional (for window titles) |
doctor |
Check | Check | Check |
record |
Required | Required | --follow any mode |
play |
Required | - | - |
play --dry-run |
- | - | - |
validate / show |
- | - | - |
Grant permissions in: System Settings > Privacy & Security
Important: The permission target is your terminal app (Terminal.app, iTerm2, VS Code, Ghostty, etc.), not the Python binary. After granting, restart the terminal.
Usage Examples
# Check permissions
uv run uitrace doctor
uv run uitrace doctor --json
# List windows
uv run uitrace list
uv run uitrace list --json
# Record interactions (Ctrl+C to stop)
uv run uitrace record --out trace.jsonl --window-id 0 --countdown 3
# Validate a trace file
uv run uitrace validate trace.jsonl
# Show trace summary
uv run uitrace show trace.jsonl
uv run uitrace show --json trace.jsonl
# Playback (dry-run, no permissions needed)
uv run uitrace play --dry-run trace.jsonl
# Playback with speed and step slicing
uv run uitrace play --dry-run --speed 2 --from-step 0 --to-step 5 trace.jsonl
# Real playback (requires Accessibility)
uv run uitrace play trace.jsonl
Multi-Window Recording
Record interactions across multiple windows:
uitrace record --follow any --out trace.jsonl
Screen Recording permission is required for --follow any mode.
Exit Codes
| Code | Meaning |
|---|---|
| 0 | Success |
| 2 | Invalid usage |
| 10 | Window not found |
| 11 | Permission denied / platform unsupported |
| 20 | Assertion failed |
| 30 | Injection failed |
| 40 | Schema validation failed |
| 130 | Interrupted (Ctrl+C) |
Trace Format (v1)
JSONL file with one JSON object per line. All events have v: 1, type, and ts (seconds).
Event types: session_start, window_selector, window_bounds, assert, wait_until, click, scroll, session_end.
wait_until
kind="pixel": Wait until a pixel at a relative position matches an expected RGB color.kind="window_found": Wait until a window matching a selector appears. Used in multi-window recording to wait for newly opened windows.
Troubleshooting
- "Cannot create event tap": Grant Input Monitoring permission to your terminal, then restart it.
- Window titles show as null: Grant Screen Recording permission to your terminal, then restart it.
playexits with code 11: Grant Accessibility permission to your terminal, then restart it.- Permissions granted but still failing: Make sure you granted to the correct app (e.g., Ghostty, not Python) and restarted the terminal.
Development
uv run ruff check . # Lint
uv run mypy src # Type check
uv run pytest -q # Tests
Release
- Bump version in
pyproject.toml. - Run local checks and build:
uv run ruff check . && uv run mypy src && uv run pytest -q uv build
- Create and push a version tag:
git tag vX.Y.Z git push origin vX.Y.Z
Important: The tagvX.Y.Zmust match theproject.versioninpyproject.toml.
PyPI Setup
This project uses Trusted Publishing.
Configure the following on PyPI for the uitrace project:
- Owner:
mkdir700 - Repository:
uitrace - Workflow name:
publish.yml
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file uitrace-0.1.0.tar.gz.
File metadata
- Download URL: uitrace-0.1.0.tar.gz
- Upload date:
- Size: 171.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ee231474bd2c7b984d40431e592c68456525d8b24a27f7c59a6898f21c3bc586
|
|
| MD5 |
c77afcf4d3b6d13d2330b018c9fbcde7
|
|
| BLAKE2b-256 |
bd33e22d94b408de872b36fdef50581e3eef009b258a57ad42d4b8ca550d0978
|
File details
Details for the file uitrace-0.1.0-py3-none-any.whl.
File metadata
- Download URL: uitrace-0.1.0-py3-none-any.whl
- Upload date:
- Size: 34.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b7306f1e54d74b15e8fa6683290d4513a29d0a7538b3a70ffb5ed1817e112122
|
|
| MD5 |
9642ad1f99328cbb8074d7471db75cca
|
|
| BLAKE2b-256 |
3ac7ce6afc6f5d2c4973e2eba3288fe5aac0476710394761efe83e212f111310
|