This site is being rebuilt and some pages are out of date. For current details, write to reach@inorbit.hr. This notice goes away when the rebuild is done.

No analytics unless you allow it, no tracking. This site keeps in your browser the language you pick, the theme, its colour, which site you chose, the currency on the pricing page and that you closed this notice; signing in adds session cookies. The legal page has the details.

Sign in

← Back to Platform

RFC 0055open2026-10-05

Trails, how people move through a site, recorded with their consent

A first-party script of a few kilobytes and browser extensions (Vivaldi first, then Chrome, Edge, Opera, Brave, Firefox and Safari) that record paths, clicks, scrolls, timings and errors on a site, never what anyone types, only after consent, on our own servers; trails become journeys to replay as tests and evidence of what changed, and we are the first site measured.

Problem

This is the observe step of the loop in RFC 0045, for the part of a system nobody models well: the people using it.

We cannot say today how anyone moves through our own site, docs or console. The analytics we run, , self-hosted and loaded only after a visitor allows it, counts page views. It cannot answer the questions that decide what to build and what to test: which path a person took before they gave up, which button they pressed three times because nothing happened, which page broke for them and with what error, how long the console took to become usable on their connection. Our customers cannot answer them for their own sites either, without sending their visitors' behaviour to an American analytics vendor.

The second use is testing. A browser journey test (RFC 0040.13) is only as good as the path it follows, and the paths people really take are not the ones engineers write down.

The constraint that shapes all of it: in the EU, reading or storing anything on a visitor's device that the service does not strictly need requires their consent (ePrivacy Directive, Art. 5(3); the EDPB's Guidelines 2/2023 extend it beyond cookies to pixels, URL tracking and identifiers), and recording a person's behaviour is processing of personal data under the GDPR. Recording people without their knowledge is not an option, for us or for a customer; the design has to make the honest way the easy way.

Proposal

Three pieces, one record

  1. The script (trail.js). Served from our own domain, under 5 KB compressed, no dependencies, no cookies of its own. It does nothing until the page tells it that the visitor consented: on our sites that is the existing analytics answer; on a customer's site, their consent tool calls trail.consent(true). Global Privacy Control with no answer counts as no.
  2. The browser extension, one code base built for Chromium (Vivaldi first, then Chrome, Edge, Opera and Brave, which all install from the Chrome Web Store or its equivalent) and for Firefox and Safari. It is for a person recording their own session on purpose: an engineer walking through a flow to turn it into a test, a customer showing support what went wrong. It records only on sites the person allowed, shows that it is recording, and pauses with one click.
  3. The trail service, which takes both, keeps them per account and turns them into what the rest of the platform uses.

A diagram is drawn here in the RFCs product; this page does not show diagrams yet.

What a trail holds, and what it never holds

Recorded Never recorded
page and route, with the query string's keys but not its values anything typed: input values, text areas, contenteditable, passwords
clicks: the element's role, accessible name and a stable selector the text of the page outside those names
scroll depth, focus and visibility changes keystrokes, clipboard, file contents
timings: navigation, the Core Web Vitals, long tasks cookies, storage, request or response bodies, headers
JavaScript errors: type and location, the message scrubbed screenshots or video of the page (the extension's replay, below, is a separate opt-in)
repeated clicks with no response, dead ends anything on a site the person did not allow, or after they paused

A trail is identified by a random id that lives as long as the tab. There is no fingerprinting and nothing that links one site's trail to another's. Every value that could carry personal data is scrubbed in the browser before it is sent, so what reaches our servers is already minimised.

The extension's replay, opt-in on top

The extension can also keep the page's structure as it changed (a DOM replay, the way session-replay tools do), so a reviewer sees what the person saw. Off by default; when on, every text node and every input is masked in the browser, and a site can mark more with a data-trail-mask attribute. It never applies to the script on other people's visitors.

What a trail becomes

  • A journey: a trail turned into a browser journey test (RFC 0040.13) that a bench run replays against a new deployment.
  • Evidence: a change's verdict (RFC 0047) can say "the five most common paths still complete, and none got slower".
  • Signals: a burst of errors or dead ends on one page raises a signal (RFC 0038).

Ours first

We run it on our own site, docs and console first, behind the same consent banner as the analytics, and the extension in our own browsers. Customers get it once the record, the retention and the controls have held on our own traffic.

Data protection

On our sites we are the controller and the legal page says so. On a customer's site the customer is the controller and we are the processor under a data processing agreement. Trails are kept 90 days by default, deletable per trail and per person, exported and erased with the account like everything else, and never sent to any model provider.

Code

The script lives with the site in this repository. The extension gets its own private repository, inorbithr/browser, built with WXT, a framework that builds one Manifest V3 code base for Chromium browsers and Firefox (WXT); Safari's build is the same extension packaged by Apple's converter, which needs a Mac with Xcode (Apple). Vivaldi installs from the Chrome Web Store (Vivaldi), so the Chromium build is the Vivaldi build.

Alternatives considered

Record everything, ask nobody. Unlawful in the EU, and the evidence it produces is worthless the moment someone asks how it was collected.

A third-party product. The analytics vendors and session-replay services do most of this, and send every visitor's behaviour to someone else's servers, usually outside the EU. The point of the platform is that the record is ours and the customer's.

Extend . It counts pages well and is built around them; clicks, errors and paths as first-class records would fight its model. stays for page counts.

Decision

Open. The owner asked for it on 2026-10-05. The consent rule and the never-recorded list are proposed as fixed; everything else is open to change as it is built.

Publication

The legal page describes trails before the script runs on our site. The extension's store pages say what it records and what it never records. Nothing claims compliance with any regulation.

Status log

  • 2026-10-05: Written. The script and the extension's skeleton started in branches; no roll while the cluster is frozen after the storage failure of the same day.
  • 2026-10-05: The script built (phase 1): trail.js under 5 KB gzipped, recording nothing until trail.consent(true) and only the Recorded column above; the never-recorded rules tested and proved in a headless browser (nothing before consent, a button's role and name after it, nothing of a typed value). On our site it follows the analytics answer but stays switched off until the trail service exists and the legal page describes it; the endpoint it posts to is a stub. The extension's skeleton is in inorbithr/browser: per-site permission asked at click time, a recording badge, pause, recordings kept in the browser. The trail service, customers' consent wiring and the extension's sign-in and upload are next.
  • 2026-10-05: A review before switching it on found three gaps and six smaller ones, all fixed: a yes then a no while the script loaded could leave it recording (the answer is now read when it arrives); quoted text in error messages could carry a name (now <str>); and an accessible name could be a person's (an avatar's alt, an account menu, an autocomplete option). Names now come only from authored hooks unless a site opts in to visible text, alt and title are never used, options are never named, and our account menu is masked. The size cap counts bytes, drops are reported, a failed send falls back to the beacon, and the build refuses to switch trails on before the endpoint is routed and the legal page describes them. The browser proof is in the tree.
  • 2026-10-05: The extension's sign-in and upload built (phase 2, extension side). It signs in as its own public client (iohr-trails-ext: PKCE, no secret, the exact redirect addresses of its pinned IDs and no wildcard, scopes trail:read and trail:write and nothing else on the API), keeps the access token in memory and a refresh token on disk only when the person asks to stay signed in, and revokes both at sign-out. A recording is uploaded only when the person presses Upload, built from an allow-list of the recorded fields; uploads are admin-only while the service is new.
  • 2026-10-05: The trail service built (phase 2, track A): recordings uploaded with a person's sign-in, kept per account in our own database, the recorder's kinds and fields checked again on arrival (anything else dropped and counted), names and messages scrubbed again, 5000 events or 256 KiB per upload, 500 uploads per account a day, kept 90 days, deleted one by one, erased and exported with the account and the person. Scopes trail:read and trail:write; admin-only until the owner opens it. Nothing of a recording reaches a log line, which a test proves. The script's endpoint waits for site keys; the extension's uploads land here.
  • 2026-10-06: The legal basis is consent, the owner's decision, recorded in our compliance programme (inorbithr/compliance#35): the script records only after a visitor's yes, and the extension only on sites its user allowed. The trail service is live since bf58be04. The console has a Trails page: the account's recordings (when, source, pages, events kept and rejected, length, size; by day and source; delete with a confirmation) and one recording's replay, each page load with its route (the path and the query's keys), clicks by role and name, rage and dead clicks marked, scroll depth, focus and visibility, navigation timing and Core Web Vitals against their thresholds, long tasks and scrubbed errors, under a scrubber across the recording. Recorded strings are shown as text only. The service no longer asks for the admin role: every signed-in person and key reads and deletes their own account's recordings, another account's are not found. The page shows in the console to admins and partners until the owner opens it.
  • 2026-10-07: What is not released yet has its own parts: 0055.1 packaged releases and store listings, 0055.2 the site script's anonymous upload with site keys, 0055.3 Firefox and Safari, 0055.4 Trails over MCP, the first two with a diagram of their flow, and this document with one from consent to replay. The console's Trails page is now the product page (core#506): the recordings lead when there are any, and the parts are shown as cards, each marked live only when the system answers for it (the trail service, the package host's latest.json) and otherwise with its part's status and latest status log line, read from the RFCs product at runtime. Not rolled yet.
  • 2026-10-07: Checked: the recorder (#295, #335), the trail service (#395) and the console page (#466) are live (trails at 05ccf3b6, console-ui at 3a40912a); the extension's client (#356) is in the sign-in. The Trails landing page (#506) is merged, not rolled. Parts 0055.1 to 0055.4 were made in the RFCs product on 2026-10-07; 0055.3 and 0055.4 are now in the repository too. Open.
  • 2026-10-08: Uploads are open to any signed-in person, into their own account, the owner decision: the trail service keeps [access] require_role empty. The console Trails page says so (core#611), and the extension popup has since inorbithr/browser#9 (a 403 reads: not allowed to upload to this account). Showing the console page to everyone stays a separate step.

← Back to Platform