A Chrome DevTools panel for the Web Locks API.
Current version: 0.6.0 · Changelog · Source
LockScope shows every lock held or requested by the inspected origin — across
tabs — with holders, FIFO waiters, observed durations, and a live timeline.
navigator.locks.query() is a point-in-time array with no timestamps or events;
LockScope makes that state observable.
- Contention lanes by lock name, with holders and waiters numbered
#1,#2, … - Observed durations for holds and waits, explicitly labelled as lower bounds.
- Timeline with solid held bars, dashed waiting bars, hover details, and 15 s / 60 s / 5 min windows.
- Filters and history by lock name or mode; pause without counting the gap; clear without losing the current lock set.
this tabbadge from a short-lived probe lock.- Optional tab labels — after a click and a per-origin permission grant, rows show which tab owns each lock.
- Optional instrumentation — patches
LockManager.requestfor exact request/acquire/release times and await-site stacks; reversible. - Ten demo scenarios including abort,
ifAvailable,steal, worker-held locks, and a two-tab deadlock.
cd lockscope
python3 -m http.server 8080 --directory demo # demo page- Open
chrome://extensions. - Enable Developer mode.
- Choose Load unpacked and select
extension/. - Open
http://localhost:8080/, then DevTools → LockScope.
No build step and no dependencies.
npm run package # dist/lockscope-<version>.zipThe archive contains only extension/ contents. Store copy, screenshots, and the
privacy policy live in store/.
- Queue 3 on the demo page: one holder and three waiters with growing
≥waits. - Start deadlock: opens a second tab; release from either side to unwind it.
- Tab labels: requests
scripting+ the inspected origin, then labels holders with tab titles. Toggle off to hide them. - Instrument → Exact: exact timings and stacks for main-world lock requests. Toggle off to restore the native method.
Keyboard: P pauses/resumes, / focuses the filter, Esc clears it.
The base extension has zero required permissions — only devtools_page.
- Tab labels are optional:
optional_permissions: ["scripting"]plusoptional_host_permissionsfor HTTP(S). Chrome asks only after the button click, only for the inspected origin. - Instrumentation needs no permission but patches the inspected page. It is off by default, main-world only, and reversible.
Everything runs locally: no network requests, analytics, accounts, or persistence of lock names, tab titles, or stacks. See the privacy policy.
Requirements: Chrome 120+, Node.js 20+, Python 3 (demo server).
| Command | Purpose |
|---|---|
npm test |
Unit tests for the model, timeline intervals, instrumentation, and formatting |
npm run check |
node --check every script |
npm run demo |
Serve the demo at http://localhost:8080 |
npm run package |
Build dist/lockscope-<version>.zip (needs zip) |
See CONTRIBUTING.md for the full workflow and docs/manual-tests.md for the manual test sheet.
extension/ Manifest V3 extension (no build step)
panel/ Lanes, tabs/instrumentation controllers, model, timeline
page-agent.js Sampling agent injected into the inspected page
instrument.js Opt-in LockManager.request instrumentation
demo/ Web Locks demo page and worker
test/ Node test runner suites
docs/ Plan, verification notes, manual tests
store/ Chrome Web Store listing, privacy policy, screenshots
site/ Public landing and privacy page (GitHub Pages)
scripts/ Packaging script
.github/ CI, Pages deploy, issue forms, PR template
The privacy site is deployed by
.github/workflows/pages.yml. The policy URL is
https://hashimlokasher.github.io/lockscope/privacy.html.
Issues and pull requests are welcome. Please run npm test and npm run check
before opening a PR, and follow CONTRIBUTING.md and the
Code of Conduct. For security reports, see
SECURITY.md.
MIT © 2026 Hashim
