Privacy policy for RealHandles
RealHandles by David V. Kimball
Last updated: 2026-08-14. Applies to the RealHandles browser extension for
Chrome and Firefox. The realhandles.com website has its own policy at
https://realhandles.com/privacy.
Every statement below was checked against the source before it was written, and
the file that checks it is named beside it. Nothing here is a promise about
intent; it is a description of what the code does.
The extension does not collect anything. There is no account, no sign-in, no
analytics, no telemetry, no advertising, and no tracking of any kind. Nothing
about you or your browsing is sent to RealHandles or to anyone else.
The address of the page you are on is read on your device, turned into a lookup
key on your device, and matched on your device against a copy of the public
RealHandles directory that the extension has already downloaded. That address
is never transmitted.
- It reads the URL of the active tab (the
tabspermission). src/detect.jsturns it into a lookup key such asgithub:someuseror
domain:example.com, entirely in the browser.src/index-set.jshashes that key with SHA-256 and a fixed published salt,
and looks up the first 8 bytes of the digest in the copy of the directory
held in local storage. The directory artifact contains hashed keys, not a
plaintext list of accounts.- If there is no match, which is what happens on the overwhelming majority of
pages, the process ends there and nothing leaves the device.
test/no-network.test.js is the proof of step 4. It replaces the browser'sfetch with a recorder that throws on any call, runs a browsing session throughthe real pipeline, and fails if a single request is attempted.
test/background.test.js asserts the same thing one level up, against the realevent listeners the extension installs. Both run under
pnpm test.All four go to
https://realhandles.com, which is the only entry inhost_permissions and therefore the only origin the extension is able tocontact at all. All four ask for data that is already public and that anybody
can fetch without the extension.
| Request | When | What it reveals |
| --- | --- | --- |
|
GET /directory-index.json | Once every 24 hours, on a timer | Nothing about you. The file is byte identical for every user and the request is triggered by a clock, not by anything on screen ||
GET /directory-index.json | When you click "Refresh now" in the popup | The same file. This is the only request in the extension a user can trigger directly ||
GET /<username>/realhandles.json | Only after a local match, to fetch that identity's published signed manifest | That somebody asked for a public profile. See "What this does reveal" below ||
GET /<username>/realhandles-chain.json | Only in the rarer case where the identity's signing key changed since the local copy was built | The same |None of these requests carries the URL of the page you are on, a page title, a
page's contents, a user identifier, or any header the extension adds. The code
calls
fetch(url) with no options at all, so there is nothing attached to it.The daily refresh being on a clock rather than on a page visit is
deliberate, and it is the reason the extension asks for the
alarms permission.The downloaded file is identical for every user, so its contents leak nothing,
but a download timed to a page visit would still reveal when you were looking at
something worth looking up.
test/background.test.js fires the alarm with nobrowsing at all and asserts the refresh still happens, which shows the two
triggers are separate by construction.
A verification tool should not be vague about its one leak.
When a page matches locally, the extension requests that identity's public
manifest. RealHandles' web server sees that request the same way it sees any
other visitor: the URL requested, and an IP address. So a match tells the server
that somebody, somewhere, was on one of that identity's pages, or on a page that
collided with one.
What it does not tell the server is which page, or that it was you rather than
anybody else, and no miss produces a request at all. There is no per-user request
path: the directory index is a static artifact that varies with nothing about
who is asking, and the manifest is the same public file the profile itself
serves.
This is the residual cost of answering the question at all, and it is smaller
than the alternative by a large margin. The design this replaces asks the server
about every page you visit.
Nothing is stored on any RealHandles server. Two areas of browser storage are
used, and the split between them is the point.
storage.local (survives a browser restart, written to disk):
index, the downloaded copy of the public RealHandles directoryindexFetchedAt, when that download last succeededindexCheckedAt, when one was last attempted
None of the three says anything about the person using the browser. The
directory is public and identical for everybody who has it, and the two
timestamps describe a clock.
storage.session (memory only, cleared when the browser closes):
- verified manifests fetched during this session, so revisiting a profile needs
no network at all - the verdict currently shown on each tab's toolbar badge
Everything derived from browsing is deliberately kept here rather than in
storage.local, because writing it to disk would build a local browsing log,which is a smaller version of the thing this design refuses to build on a
server. The cost is that the first match after a restart fetches again. That is
the right side of the trade.
One precise note, because it is the only place the paragraph above has an edge:
src/api.js falls back to storage.local on a browser that does not implementstorage.session. Every browser this extension supports does implement it(Chrome 102 and later, Firefox 115 and later, against declared minimums of
Chrome 123 and Firefox 142), so the fallback is unreachable in practice. It is
described here rather than omitted.
You can erase all of it at any time by removing the extension.
- No content script. Nothing is injected into any web page, and nothing is
read out of one. The extension does not have permission to touch the sites you
visit, and the verdict is shown only in the toolbar icon and the popup, which
the browser draws out of the extension's own package. - No
<all_urls>permission and no host permission for any site you visit.
The only host permission ishttps://realhandles.com/*. - No remote code. Everything executable ships inside the package. Nothing is
downloaded and run. - No third parties. The extension contacts one origin. There is no analytics
provider, no error reporter, no advertising network, and no data broker. - No sale or sharing of data, which follows from there being none.
- No cookies set by the extension.
The claims above are checkable without reading all the code.
- Load the extension, open the background script's devtools network panel
(chrome://extensionsthen Service Worker, orabout:debuggingthen Inspect),
and browse. Pages that do not match produce no entries. - Run
pnpm test. The two files named above assert the no-request behavior
directly. - Read
BUILD.md, which documents a reproducible build so that the package in
the store can be shown to come from this source.
The popup shows links to a profile on realhandles.com and to accounts an
identity has published. Those are ordinary links that open in a new tab when you
click them. The extension makes no request to any of those addresses on its own,
and only ever renders a link whose scheme is
http or https.The extension is not directed at children and collects no information from
anyone, including children.
If the extension's behavior ever changes in a way that affects anything above,
this policy changes in the same release, and the "Last updated" date at the top
changes with it.
TODO: David to supply the contact address for privacy questions. No address has
been invented here. Until one is set, https://realhandles.com is the point of
contact.