Client-Agent
Browser
Was der Server nicht sehen kann: wie lange die Seite für einen echten Menschen tatsächlich gedauert hat, welche Klicks nichts bewirkt haben, und welche Komponente sich vierhundertmal neu gerendert hat.
- Paket
@sixty-sh/browserauf npm- läuft auf
- Jede Seite. Etwa 2,4 µs blockierende Kosten pro beobachteter Anfrage.
- Quellcode
- sixty-sh/sixty-browser
Installation
Next, Remix, SvelteKit and friends. The key stays server-side behind a proxy route.
Die Installation ist als Prompt für den Coding-Agenten geschrieben, den du ohnehin offen hast, nicht als Checkliste für dich. Das ist Absicht: sie benennt, was am Ende wahr sein muss, statt welche Dateien zu bearbeiten sind — denn wohin der Code gehört, hängt vom Framework ab, und ihn an die falsche Stelle zu setzen scheitert lautlos. Ein Agent kann dein Repository lesen und das herausfinden; ein Absatz auf einer Dokumentationsseite kann es nicht.
Denselben Text liefert install_sixty über den MCP-Server zurück, und den serviert der Collector unter /v1/setup?kind=browser. Es gibt genau eine Kopie davon.
die vollständige Browser-Installation
Set up @sixty-sh/browser in this project so page performance reports to sixty.
Before editing, ask the user: "Do you want privacy-masked session replay?"
Do not choose for them. If yes, use the replay-enabled init in step 3. If no,
use plain init() and do not add replay configuration.
1. Install @sixty-sh/browser.
2. Add a server-side endpoint at the path /api/drift whose GET and POST
handlers are both the same createSixtyProxy() handler from
"@sixty-sh/browser/proxy". Work out the correct
file and export style for this project's framework and router. It must run
on the server, not the client. POST receives measurements and recordings;
GET reads the Sessions policy. Omitting either method is an incomplete install.
3. Call init() from "@sixty-sh/browser" exactly once in the browser, in a
client component that is mounted on every page (the root layout is usually
right). If the user chose replay, call
init({ replay: { enabled: true } }); otherwise call init(). The default
endpoint is /api/drift.
@sixty-sh/browser owns the compatible recorder dependency, so do not install
or import rrweb separately. Replay remains privacy-masked and the Sessions
setting decides whether recordings are off, incident-only, or sampled.
4. Set these server-side environment variables (never client-exposed ones):
SIXTY_API_KEY = a secret key starting sixty_sk_ — ask me for it, I can
generate one on the Settings page. Do not invent one.
SIXTY_SERVICE = my-app
SIXTY_ENDPOINT = https://ingest.sixty.sh
5. If this project has a router that knows its route patterns, call setRoute()
from "@sixty-sh/browser" with the pattern (e.g. "/orders/[id]") on each
navigation. Without it, routes are guessed from the URL, which is close but
not exact.
Constraints — these are correctness requirements, not style preferences:
- SIXTY_API_KEY must never reach the browser. Do not prefix it with NEXT_PUBLIC_,
VITE_, or PUBLIC_, do not pass it to init(), and do not import it into any
client component. The whole point of the proxy is that the key stays server-side.
- Do not add any analytics, user id, session id, or cookie. The agent is
deliberately anonymous and must stay that way.
- Do not call init() during server rendering. It returns null there, so guard it
in an effect or a client-only component rather than at module scope.
When you are done, tell me which files you changed and how to deploy so I can
confirm data is arriving.Er braucht einen geheimen Schlüssel — er beginnt mit sixty_sk_ und bleibt serverseitig. Erzeuge einen auf der Einstellungsseite, sobald du angemeldet bist.
Was er misst
| Signal | Einheit | was es bedeutet |
|---|---|---|
web_vital | ms | a page-speed metric got worse for real users |
render_storm | renders | a component re-renders many times for one interaction |
dead_interaction | of clicks | users click this and nothing observable happens |
stuck_loading | of loads never finish | a loading state is entered and never left |
client_error | of views | this error is being thrown in real users’ browsers |
auth_failures | — | The server is turning these away on permission grounds rather than failing. People see an empty page or a save that quietly does nothing. |
silent_empty | — | The query runs and succeeds, and returns no rows where it used to return plenty. Nothing reports an error, so the page just renders blank — this is what a broken permission rule looks like from the outside. |
latency | ms per call | this operation takes longer end to end than it used to |
errors | error rate | a larger fraction of calls are throwing |
runaway | calls per minute | this operation is being called far more often than anything triggers it |
Wo er sich einhängt
- Next, Remix, SvelteKit — Ein eigener Server bedeutet, dass der Schlüssel serverseitig hinter einer Proxy-Route bleibt — nimm diese Stufe, nicht die von Lovable.
- Gar kein Server — Lovable, ein statischer Host, eine reine Supabase-Anwendung: siehe die Lovable-Stufe, die einen öffentlichen, an das Origin gebundenen Schlüssel benutzt.
Was nur dieser kann
- Seitengeschwindigkeit pro Route und pro Land — LCP, INP, CLS und TTFB aus echten Besuchen, verglichen mit dem letzten Release statt mit einem Labordurchlauf.
- Render-Schleifen — Eine Interaktion, die die Seite hunderte Male neu rendert. Serverseitig kann das nichts sehen, und es wird kein Fehler geworfen.
- Klicks, die nichts tun — Ein Element, das geklickt wird und keine messbare Änderung erzeugt — keine Anfrage, keine Navigation, keine DOM-Mutation.
- Nie fertiges Laden — Ein Ladezustand, der betreten und nie verlassen wird — der Fehler, der ein Supportticket erzeugt und keine Logzeile.
Was er nicht kann
- Es wird keinerlei Nutzeridentität erhoben — keine ID, keine Sitzung, kein Cookie. Das ist eine Design-Beschränkung und keine Einstellung, „welcher Nutzer hat das gesehen“ ist also eine Frage, die dieses Produkt niemandem beantworten kann, uns eingeschlossen.
- Stack-Frames zeigen in der Produktion auf gebündelte Chunks. Was einen Browser-Fehler identifiziert, sind der Name der Operation und die Meldung, nicht die Zeilennummer.
Konfiguration
Jeder Agent liest dieselben vier Variablen, und DRIFT_* antwortet weiterhin überall dort, wo SIXTY_* es tut — das Produkt wurde umbenannt, und dieser Name ist nicht unserer, um ihn aus fremden Deployments zu entfernen.
SIXTY_API_KEY | Ohne sie bleibt der Agent untätig und sagt das auch. Er rät nie, versucht es nie erneut gegen einen unbekannten Endpunkt, und wirft nie. |
|---|---|
SIXTY_SERVICE | Wie dieser Dienst heißen soll. Standardmäßig der Projektname, wo einer lesbar ist. |
SIXTY_RELEASE | Die wichtigste. Wird auf Vercel, Render, Railway, Fly, Heroku und GitHub Actions automatisch abgeholt; überall sonst setze sie auf den Commit-SHA. Ohne sie landet jede Messung in einem einzigen namenlosen Eimer, und kein Vergleich ist je möglich. |
SIXTY_ENDPOINT | Wohin gemeldet wird. Standardmäßig http://localhost:4319, was auf einem Laptop richtig ist und in dem Moment falsch, in dem die Anwendung jemand anderem ausgeliefert wird. |
Der Rest — Flush-Intervall, Sample-Rate, was instrumentiert wird — steht im README des Pakets selbst, wo es wahr bleiben kann, während sich der Agent verändert.