Inverse Interface
See how people actually use your app, with their consent, and hand it to your coding agent as an intent package: what they tried to do, where they got stuck, and the evidence.
What it is
A small script records what people do in your app as semantic events: pages, the buttons and links they click, form submits, errors, rage clicks, dead clicks and scroll depth. It never records what they type. Inverse turns a session into an intent.v1 package that an agent can read.
Open snippet, metered API
The formats and the browser snippet are open. Turning sessions into intent runs on Inverse's API, with your key.
| Layer | What | Cost |
|---|---|---|
| Open format | interface-event.v1, intent.v1 | Free |
| Open snippet | The recorder, redaction, consent prompt and room link, MIT in inverse-interface and /v1.js. | Free |
| Inverse API | Sessions and intent packages built and analyzed on Inverse's servers | Metered per package that passes the quality gate |
The hosted API takes events from anywhere. They don't need to come from the Inverse script, an Inverse room, or an app hosted on Inverse. Your browser never reports usage; Inverse counts only what its own servers produce.
Add the snippet
Use your project's publishable key (pk_live_…). It works only from the domains you allow. Pin the version with its integrity hash:
<script src="https://www.inverse.at/v1-0.3.0.js" integrity="sha384-xOx29+7qQagCloCIx75FiNuQGMzkH5CKflpmvKlYYtroFwn1SBOYmuQeoA/C2Ugg" crossorigin="anonymous"></script>
<script>Inverse.capture({ key: "pk_live_…", task: "Sign up and create a project" });</script>/v1.js always serves the latest 1.x without a pinned hash. Inverse.capture asks for consent first and resolves null if the person chooses Not now. Pass solo: true for an unmoderated session.
Inverse.on("event", (e) => console.log(e.kind, e.target));
Inverse.on("end", (pkg) => console.log(pkg.friction)); // intent.v1
const capture = await Inverse.capture({ key, task, solo: true });
await capture?.end();
Inverse.room({ url: "https://your-app.com" }); // open an Inverse room around a URLFrom npm
npm i inverse-interface. Plain ESM with no dependencies and no build step: the same recorder, consent prompt and client as /v1.js, for apps that bundle their own scripts.
Bring your own events
Already record sessions another way? Send interface-event.v1 events with a secret key, from your server, and get an intent package back.
curl https://www.inverse.at/v1/intent-packages \
-H "Authorization: Bearer sk_live_…" -H "Content-Type: application/json" \
-d '{"task":"Check out","events":[{"v":1,"t":1793491200000,"session":"s1","kind":"click","path":"/cart","target":{"label":"Pay","role":"button"}}]}'Your own model
Store an OpenAI, Anthropic or OpenAI-compatible key on your project (Interface dashboard → LLM). It's encrypted and shown only as its last four characters. When a session ends, Inverse calls your model, validates the result against intent.v1, re-runs the quality gate and meters it at $0.50 per intent package instead of $2.00. Participant data always goes to the model inside an untrusted block, and the model's answer is only ever data. quality.billable is decided by Inverse from the events.
Privacy
- Consent first. Nothing is recorded until the person chooses Allow. The answer is remembered for your site. Every batch carries the consent record, and the API rejects events without it.
- Never input values. The recorder never reads what's in a field. A submit says that a form was sent, not what was in it.
- Redacted at the source. It skips password fields, payment fields (
autocomplete="cc-*"), and anything insidedata-inverse-redact. It keeps the path only, never the query string or hash. The server redacts again. - Who sees it. The team that runs the app and their coding agent, as “Speaker A”. A small indicator lets the person pause or stop at any time.
<div data-inverse-redact>
<!-- nothing in here is recorded, not even clicks -->
</div>