English | 中文
Many online assessments, coding interviews, and proctored hiring tests track when you leave the exam tab — via the Page Visibility API and window focus/blur events. On pages like detect-tab-focus, OS-level screenshots do not fire any JS events. What actually gets flagged is: switching tabs, switching windows, or switching to another app (for example, opening the ChatGPT, Claude, or Gemini desktop app to paste a screenshot).
This tool is for studying those detection boundaries on local demo pages. It keeps the browser in the foreground during an assessment-style session, runs capture and AI inference in the background, and shows results in a non-activating overlay — so the exam page stays focused.
| Action | Page detects it? |
|---|---|
| Switch to another tab | ✅ visibilitychange → hidden |
| Switch to another browser window | ✅ window blur |
| Switch to ChatGPT / Claude / Gemini / Terminal / Raycast | ✅ window blur |
Silent macOS screenshot (screencapture -x, Hammerspoon snapshot) |
❌ |
| Background process calling Claude/OpenAI API | ❌ |
| On-screen overlay showing text (without activating a window) | ❌ |
| Built-in ⌘⇧4 region select (crosshair briefly steals focus) | |
| Copy to clipboard (browser stays foreground) | ❌ |
┌─────────────────────────────────────────────────────────┐
│ Chrome / Safari (always frontmost app, tab stays visible) │
│ ┌─────────────────────────────────────┐ │
│ │ assessment / interview question page │ │
│ └─────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
▲ │
│ no focus switch │ global hotkey
│ ▼
┌────────────────┐ PNG ┌──────────────────────┐
│ Hammerspoon │ ────────► │ ask_ai.py │
│ silent capture │ │ POST → Claude/GPT │
└────────────────┘ └──────────┬───────────┘
│ text
▼
┌──────────────────────┐
│ Overlay │
│ (non-activating) │
│ shows AI answer │
└──────────────────────┘
- Pros: Fully local and controllable; hotkey capture of window or region; overlay does not steal focus; swap any API provider.
- Cons: Requires Hammerspoon; first run needs Screen Recording + Accessibility permissions.
- Best for: Local proctoring research, interview-platform debugging, and iteration.
- Pros: Zero code; browser keeps focus on the primary display.
- Cons: Poor UX; clicking an app on the second monitor still triggers blur on the primary screen.
- Best for: One-off temporary use.
- Verdict: Always triggers blur, directly conflicts with the page’s focus-detection goal — not usable during an online assessment or live interview.
brew install hammerspoon
pip3 install anthropic # or openaiOr run the installer:
git clone https://github.com/autocue-interview-tools/stealth-capture.git
cd stealth-capture
./install.shexport ANTHROPIC_API_KEY="sk-ant-..."
# optional: custom model
export STEALTH_AI_MODEL="claude-sonnet-4-20250514"Recommended: add to ~/.zshrc or set via Hammerspoon os.setenv on startup.
Supported providers (via STEALTH_AI_PROVIDER): openrouter (default), gemini, openai, anthropic.
If you did not use ./install.sh, copy manually:
mkdir -p ~/.hammerspoon/stealth-capture
cp stealth_capture.lua ~/.hammerspoon/stealth_capture.lua
cp ask_ai.py ~/.hammerspoon/stealth-capture/ask_ai.pyAdd to ~/.hammerspoon/init.lua:
require("stealth_capture")System Settings → Privacy & Security:
- Screen Recording: enable Hammerspoon
- Accessibility: enable Hammerspoon
Restart Hammerspoon (menu bar icon → Reload Config).
| Hotkey | Action |
|---|---|
| ⌥ S | Drag to select a screen region → send to AI → show answer in overlay |
| ⌥ A | Full-screen capture (no drag) → send to AI → show answer in overlay |
| ⌥ R | Reopen last AI answer |
| Esc (while overlay visible) | Close overlay without switching focus |
- Open
detect-tab-focusin Chrome (simulates a typical online assessment focus tracker); confirm status is Tab Focused. - Press ⌥ S.
- On the page: no overlay should appear, and the Event Log should not gain a BLUR entry.
- An AI answer overlay should appear on screen.
Hammerspoon hs.canvas with:
level = floating(above normal windows)collectionBehavior = canJoinAllSpaces + stationary- No
win:focus()call; canvas does not accept keyboard focus by default
The browser remains NSWorkspace.shared.frontmostApplication, so document.hasFocus() stays true.
- Capture browser content only: use
hs.window.filterforChrome/Safariin Lua, or crop the toolbar after window capture. - Streaming output: change
ask_ai.pyto SSE and refresh the overlay incrementally (usehs.timerto avoid blocking).
This tool is designed for local demo pages such as detect-tab-focus, to understand how online assessments, interviews, and proctoring platforms detect focus — and to build your own anti-cheating logic. Bypassing monitoring in real online assessments, live interviews, certification exams, or employer proctoring may violate rules or law. Use only in authorized scenarios.