P99

Got questions or doubts? Ping me on Discord

One widget on any site

One tag, every page: a small + for the people you invite, and a panel on the first click.

What it does

The people you invite see a small + on your site. It opens a panel where they file a bug, an idea, an improvement, a question or a task, with a capture of the screen, marked regions and files, and follow the replies.

The page talks only to its own origin: P99's Worker answers on your site's own domain at /_p99/*, so there is no CORS, no framework, no build step and nothing from your stack.

  • Nothing for everyone else

    The loader draws the + in its own closed Shadow DOM, only for people holding a personal code. For everyone else it reads nothing and draws nothing.

  • Under a strict CSP

    It adds one element and one global, P99, and works under a strict Content-Security-Policy: no 'unsafe-inline', no eval, no frames, nothing from another origin.

  • Captures that keep secrets

    Fields marked data-p99-redact, and every password field, are blanked in every capture, and the page's address is kept without its query string and hash.

  • The panel loads on the first click

    It files the item, lists what the person sent with what's new for them, and shows each thread with its replies, files, status changes and where its fix has landed, in the page's light or dark scheme.

Measured

What every page downloads, gzipped: the loader as served, nothing else
2,007 bytes
How it was measured
Loader start to the + painted, cold (3.4 ms warm)
8.9 ms
How it was measured
Click to the panel's form on screen, cold; the panel and its styles (29.1 KB gzipped) load only then
59.0 ms
How it was measured

How to use it

  1. Put the one tag in your site's <head>.

    <script src="/_p99/p99.js" async></script>
  2. Invite someone. P99 prints their personal link, and the code travels in its fragment, which browsers never send to a server.

    p99 invite example.com --name "Ada Lovelace" --email ada@example.com
  3. Keep P99 off a page, such as a checkout's receipt: there it draws nothing, reads nothing and captures nothing.

    <meta name="p99" content="off">