sixty

agent client

Browser

Ce que le serveur ne peut pas voir : combien de temps la page a réellement pris pour une vraie personne, quels clics n’ont rien fait, et quel composant s’est re-rendu quatre cents fois.

paquet
@sixty-sh/browser sur npm
tourne sur
N’importe quelle page. Environ 2,4 µs de coût bloquant par requête observée.
source
sixty-sh/sixty-browser

L’installer

Next, Remix, SvelteKit and friends. The key stays server-side behind a proxy route.

L’installation est écrite comme un prompt pour l’agent de code que vous avez déjà ouvert, pas comme une liste de tâches pour vous. C’est délibéré : elle nomme ce qui doit être vrai une fois l’installation terminée plutôt que les fichiers à modifier, parce que l’endroit où va le code dépend du framework et que le mettre au mauvais endroit échoue silencieusement. Un agent peut lire votre dépôt et le déduire ; un paragraphe sur une page de documentation, non.

Le même texte est ce que renvoie install_sixty via le serveur MCP et ce que le collecteur sert à /v1/setup?kind=browser. Il n’en existe qu’une seule copie.

l’installation Browser, en entier
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.

Il lui faut une clé secrète — elle commence par sixty_sk_ et reste côté serveur. Générez-en une sur la page Réglages une fois connecté.

Ce qu’il mesure

signalunitéce que cela veut dire
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

Où il s’accroche

  • Next, Remix, SvelteKit — Avoir un serveur à soi signifie que la clé reste côté serveur derrière une route de proxy — prenez ce niveau, pas celui de Lovable.
  • Aucun serveur du tout — Lovable, un hébergement statique, une application uniquement Supabase : voyez le niveau Lovable, qui utilise une clé publique épinglée à l’origine.

Ce que seul celui-ci fait

  • La vitesse de page par route et par pays — LCP, INP, CLS et TTFB issus de vraies visites, comparés à la version précédente plutôt qu’à un passage en laboratoire.
  • Les boucles de rendu — Une interaction qui re-rend la page des centaines de fois. Rien côté serveur ne peut voir cela et aucune erreur n’est levée.
  • Les clics qui ne font rien — Un contrôle sur lequel on clique et qui ne produit aucun changement mesurable — pas de requête, pas de navigation, pas de mutation du DOM.
  • Un chargement qui ne finit jamais — Un état de chargement dans lequel on entre et dont on ne sort jamais : la panne qui produit un ticket de support et aucune ligne de journal.

Ce qu’il ne peut pas faire

  • Aucune identité d’utilisateur n’est collectée — pas d’id, pas de session, pas de cookie. C’est une contrainte de conception et non un réglage : « quel utilisateur a vu ça » est donc une question à laquelle ce produit ne peut répondre pour personne, nous compris.
  • En production, les images de pile pointent vers des chunks empaquetés. Ce qui identifie une erreur navigateur, c’est le nom de l’opération et le message, pas le numéro de ligne.

Configuration

Chaque agent lit les mêmes quatre variables, et DRIFT_* répond toujours partout où SIXTY_* répond — le produit a été renommé, et ce nom ne nous appartient pas au point de le retirer des déploiements des autres.

SIXTY_API_KEYSans elle l’agent reste inerte et le dit. Il ne devine jamais, ne réessaie jamais contre un point d’entrée inconnu, et ne lève jamais d’exception.
SIXTY_SERVICEComment appeler ce service. Par défaut le nom du projet là où il est lisible.
SIXTY_RELEASELa plus importante. Récupérée automatiquement sur Vercel, Render, Railway, Fly, Heroku et GitHub Actions ; partout ailleurs, mettez-y le SHA du commit. Sans elle, chaque mesure atterrit dans un unique seau sans nom et aucune comparaison n’est jamais possible.
SIXTY_ENDPOINTOù remonter. Par défaut http://localhost:4319, ce qui est juste sur un portable et faux dès l’instant où l’application est servie à quelqu’un d’autre.

Le reste — intervalle d’envoi, taux d’échantillonnage, quoi instrumenter — est dans le README du paquet lui-même, là où il peut rester vrai à mesure que l’agent change.

L’agent Browser de sixty — ce qu’il mesure et comment l’installer