sixty

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/browser auf 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

SignalEinheitwas es bedeutet
web_vitalmsa page-speed metric got worse for real users
render_stormrendersa component re-renders many times for one interaction
dead_interactionof clicksusers click this and nothing observable happens
stuck_loadingof loads never finisha loading state is entered and never left
client_errorof viewsthis 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.
latencyms per callthis operation takes longer end to end than it used to
errorserror ratea larger fraction of calls are throwing
runawaycalls per minutethis 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_KEYOhne 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_SERVICEWie dieser Dienst heißen soll. Standardmäßig der Projektname, wo einer lesbar ist.
SIXTY_RELEASEDie 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_ENDPOINTWohin 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.

Der Browser-Agent von sixty — was er misst und wie man ihn installiert