Detect browser automation while you were away
ccdeck's Browser Watch reads your Chromium browsers' own history for pages a program opened while nobody was browsing, and lists them as findings with every address in full; it is on by default, and reads only visits made after the deck started.
You will
- Open Browser Watch and read a finding
- Choose what the deck does when it finds one
- Follow the record it keeps on disk
The film’s lines, in order: Did something drive your browser while you were away? An agent with browser control opens pages through an API. Chromium records that: FROM_API, not LINK or TYPED. The panel behind the eye icon answers one question. The pages a program opened while nobody was browsing. It is usually your own agent working in the browser. None of what it reads leaves the machine. It ends on the ccdeck logo, npx ccdeck, “Detect browser automation while you were away.” and ccdeck.dev.
FROM_API: a link it clicks or a tab it opens straight at an address is not. Drawn as a reconstruction of the deck.Before you start
- ccdeck running (
npx ccdeck), with a deck page left open: a browser tab, or the desktop app’s window. The check every five minutes runs in that page. - A Chromium browser you have opened at least once, such as Google Chrome, Brave, Microsoft Edge or Vivaldi. Firefox and Safari are not read.
- Node.js 22.13 or newer, or a
sqlite3command on the PATH, to read the history. macOS shipssqlite3; Windows does not.
Steps
-
Open Browser Watch
Press B, or click the eye on the stripe on the right. On a phone, it is under More in the dock along the bottom.
Demo data The 2 counts the episodes that began since you last closed the panel. -
Read what the panel shows
The left column shows which browsers are watched, and how many pages a program opened in each since the deck started. On the right, Findings lists what a program opened while nobody was browsing.
Open the full-size picture
Demo data Both findings are in Google Chrome. The footer reads Watching while its Watch browser activity switch is on, as it is by default.
More about the panel
- Remote control says whether Claude in Chrome is live in a profile here, which would let a Claude Code session signed in to your Anthropic account drive this browser. What it can reach, and how to stop it gives a command that blocks the relay, for you to paste into a terminal; ccdeck never runs it.
- Live activity adds a line each time a browser’s history grew, counting your own pages without writing them down.
- The open panel reads the browsers every 10 seconds. The circular arrow in the header copies each history again, at most once a minute.
- While the watch is off, the panel shows only what this deck has seen since it started, and nothing new is kept.
-
Open a finding
Each card is one episode: one host in one browser. Click a card to list every address the program opened, in full, with its time.
Demo data The part after ? and the part after # are kept. A page counts only when a program opened it and nobody browsed that profile by hand for the Nobody browsing for time, 15 minutes by default, before and after it. Until that time has passed, its card says provisional: a visit of yours can still withdraw it. Nothing is kept or done until its first page is past that time.
A finding is not a verdict. It is usually your own agent working in the browser. The watch reports what a program opened; the judgement is yours.
More about what counts as away
The deck looks for Chromium’s
FROM_APImark. A page loaded withPage.navigateover the browser’s debugging protocol carries it, the way Playwright and Puppeteer go to an address, and so does an extension’stabs.update. A visit without the mark counts as you. The deck has no idle timer and does not watch the keyboard: it goes by the history alone.What it misses: a tab a program opens straight at an address (
Target.createTarget, an extension’stabs.create), a link it clicks, and an address handed over byopenorxdg-opencarry no mark. They are not reported, and like a visit of yours they can withdraw a finding near them.It never reports its own tabs. A card’s pages stay together while no two in a row are 15 minutes or more apart. While you are browsing, the overview counts down to when a program’s page would count.
-
Dismiss a finding you have checked
Click the × beside its card. The episode leaves the list for good, even while its run goes on. Addresses already kept stay in the log file.
-
Choose what happens when it finds one
Click the gear in the footer. Two menus open above it:
- Nobody browsing for: 1, 5, 15, 30 or 60 min. A shorter time catches more, including more of your own work.
- When it finds one: notify me, the default; close the tab, on macOS only; or quit the browser. On Linux it quits only the browser holding that profile, or nothing when it cannot tell which one that is, as with a Flatpak Brave.
Demo data This deck runs on Linux, so its menu holds notify me and quit the browser. Closing the tab is only cleanup. The page has already loaded by then. Only quitting takes the browser away from whatever was driving it.
More about reactions
Every reaction also shows a system notification titled “Browser watch”, unless the deck was started with
AGENTS_DECK_NO_NOTIFY=1. The Notifications while closed switch, in Settings › Notifications, does not change it.A reaction runs once for each new episode, only while the watch is on, once its first page is no longer provisional: with the default 15 minutes, about 16 minutes after that page, at the next check. Live activity then says what it did, as in “docs.example.com — notified”. When several decks with Browser Watch run, only the one on the lowest port writes the record and reacts. The others show the same findings.
-
Follow the record on disk
While the watch is on, each new episode goes into
watch.logonce its first page is no longer provisional, with every address under it. On macOS or Linux, follow it with:tail -f ~/.claude/agent-dag/browser-watch/watch.logOnly flagged episodes are kept, never your own browsing. The watch does not read cookies, saved passwords or page contents, and nothing from your history leaves the machine.
More about what the watch reads and keeps
- Beside the log,
state.jsonholds up to 500 episodes, your dismissals and the settings. Both move underCLAUDE_CONFIG_DIRwhen that is set;CCDECK_HOMEdoes not move them. watch.logkeeps each episode as first written, and rolls over towatch.log.1at 2 MiB.- To read a history, the deck copies the browser’s
Historyfile into a private folder underbrowser-watch/staging/, only when it changed, and deletes the copy after one query. - For Remote control, it also reads the hosts file and the settings of profiles with Claude in Chrome, and, while the panel is open and where
digis installed, looks up the relay’s name about every 30 seconds. That DNS query is the one thing the watch sends out. - What Browser Watch can access, in the settings, lists what the watch reads, keeps and never reads.
- Beside the log,
If something goes wrong
“No browser on this machine has a profile to read.”
Open Google Chrome, Chromium, Brave, Microsoft Edge or Vivaldi once (Arc too on macOS). It is watched from then on.
A profile “could not be read”
For no-sqlite-reader, run the deck on Node.js 22.13 or newer, or put a sqlite3 command on its PATH. For another reason, click the circular arrow in the header after a minute.
A program drove the browser, and nothing is under Findings
You may have browsed that profile by hand within the Nobody browsing for time: set it to 1 or 5 min to catch more. The watch also skips visits from before the deck started, unmarked pages (step 3), and a browser run from a folder of its own, such as an automation tool’s throwaway profile.
No notification arrived, or it arrived late
A reaction waits until the finding is no longer provisional, about 16 minutes by default, and with no deck page open, until the first check after one opens. Otherwise check that the watch is on, then read Live activity. It says “could not notify” when notify-send fails on Linux.
When it finds one is greyed out
The watch is off. Turn on Watch browser activity in the footer.
Something else? See Troubleshoot ccdeck: status, logs, port and hooks.