Privacy policy
Local-first. Nothing leaves your machine.
Last updated: 2026-06-09.
peek is a local-first developer tool. The Chrome extension captures your real
browser session and ships it through a native-messaging stdio
bridge to a local MCP server (peek-mcp).
No remote endpoints, no telemetry, no analytics, no third-party SDKs.
This page is the canonical privacy policy used for the Chrome Web Store
listing. The source markdown lives at
docs/peek/PRIVACY_POLICY.md.
What peek processes
- DOM + interaction events — a masked rrweb session. PII heuristics mask form values and inputs with
password/email/ autocomplete tokens before forwarding. - Console events —
console.log/info/warn/error/debugarguments, with the same masking. - Network metadata — request URL (path masked), method, status, timing, initiator. Bodies are not captured at this level.
- Network bodies (opt-in “Deep capture” only) — when you toggle Deep capture for a specific origin, the extension attaches
chrome.debuggerto that tab and records response bodies. Bodies are masked and capped at 256 KB. - Shadow-DOM reports — counts of closed shadow roots peek could not recurse into (diagnostic only — no contents).
peek does not record:
- Sites you have not explicitly enabled. There is no
<all_urls>host permission. - Background tabs you are not actively recording.
- Any traffic outside the tab origins you opt in to.
Where the data goes
- Browser extension — masks events in the page (ISOLATED-world content script) before passing them to the service worker.
- Service worker — forwards events to the local native host via
chrome.runtime.connectNative('com.peekdev.host'). stdio pipe; no sockets, no localhost HTTP, no DNS. peek-mcpnative host — persists events to a local SQLite database at~/.peek/sessions.db(POSIX) or%APPDATA%\\peek\\sessions.db(Windows). Large event chunks are gzipped to~/.peek/rrweb-events/.- AI coding agents — when you point Claude Code / Cursor / Cline / Windsurf at the
peek-mcpMCP server, the agent reads sessions from the local SQLite database. Reads are gated by the permission model below.
No cloud sync. No telemetry endpoint. No third-party data sharing.
Permission model
Per-origin, 5 levels. Default is Level 1 — Observe only.
- Level 0 — Off: recording suppressed; tool surface disabled for the origin.
- Level 1 — Observe (default): read recorded sessions, plus on-demand masked reads of the live page — a page snapshot (
get_page_view) and a single-element detail drill-in (get_element_detail). Both non-mutating. - Level 2 — Suggest: read + propose actions (no execution).
- Level 3 — Confirm: read + execute one-shot actions with per-action user confirmation.
- Level 4 — Auto: read + execute without per-action prompts; stays on until you lower the trust level. Destructive-action terms still prompt.
Live page snapshot (get_page_view) — at Level 1+,
an agent may request an on-demand snapshot of the current page: a compact,
ref-tagged list of interactive elements (so it can act on a stable reference
instead of guessing a CSS selector). It is non-mutating and audit-logged.
Password/email/tel and PII-autofill values (card, address, birthday, name, etc.)
are masked in-page to •••. Any region marked
.rr-mask / data-private / data-dd-privacy /
data-peek-mask is masked to ••• in-page
across its element names, values, and text (not only input values); structured
PII in the remaining text is masked before it leaves the device. As with the
recorder, free-text values of non-annotated fields may be included
— mark sensitive free-text regions with a mask class to exclude them. Refs
are identity-stable across snapshots (an element keeps its ref) via a MAIN-world
WeakMap — a JS global, never a DOM attribute, so it is
invisible to recordings.
Element detail (get_element_detail) — also at
Level 1+, an agent may drill into a single element by its ref: role,
full accessible name, every aria-* attribute, state, value, type,
href, position, nearby heading/landmark, and interactive descendants. It is
non-mutating, audit-logged, and applies the same masking as
get_page_view (sensitive values become •••;
structured PII is scrubbed). A region marked .rr-mask /
data-private / data-dd-privacy / data-peek-mask
is masked to ••• across the element's name, value,
own/descendant text, every aria-* value, and every child name. It
never reads raw outerHTML / innerHTML. The same free-text
caveat applies.
Post-action delta (observe) — when an agent
passes observe: true on a mutating execute_action, peek
returns a masked delta of what changed after the action (added / removed / changed
refs), so it can verify the result without a second snapshot. The delta carries
the same masked fields as get_page_view (same caveats); a navigating
action returns only a “refs expired” marker, no element content.
Destructive-action blocklist override — even at Level 4 (Auto), targets matching “delete”, “remove”, “drop”, “uninstall”, “transfer”, “send”, “pay”, etc. require explicit confirmation.
Deep capture — separately gated. Requires (a) the optional
debugger Chrome permission, requested at user-gesture time, and
(b) per-origin opt-in via the “Deep capture” toggle. Disabling Deep
capture for an origin detaches the debugger from every tab on that
origin immediately.
User controls
- Per-site Enable / Disable in the side panel.
- Recording indicator — an always-on toolbar badge plus a default-on in-page glow (inside a closed shadow root, excluded from peek's own capture) shows when recording is active. The “Show recording border” toggle in the side panel hides the glow; the badge remains visible.
- Deep capture toggle — separate, per-origin. Off by default.
- Permission level — set per origin. Default Level 1.
- Delete a session —
peek delete <session-id>or remove rows from~/.peek/sessions.dbdirectly. - Delete all data —
rm -rf ~/.peek/(POSIX) or remove%APPDATA%\\peek\\(Windows). - Audit log — every action dispatched through the
execute_actionMCP tool is recorded to~/.peek/audit.log(mode 0600). - Pause — set permission level to 0 (Off) on an origin to suppress recording without losing the per-origin opt-in.
Open source
peek is Apache 2.0. The privacy posture above can be verified by reading the
source — particularly the masking in
packages/peek-extension/src/relay/mask.ts, the native port in
packages/peek-extension/entrypoints/background.ts, and the
stdin/stdout handler in packages/peek-mcp/src/native-host/.
No build phase, no installer, and no runtime path makes network calls to any
host outside chrome.runtime.connectNative('com.peekdev.host').
Contact & changes
For questions, open an issue on the
repository.
For a privacy or security vulnerability, use
GitHub's private vulnerability reporting
per the SECURITY.md
policy — coordinated disclosure with a 3-business-day acknowledgement target.
Material changes to this policy bump the date at the top and are noted in
the repository's CHANGELOG.