for apps built on Lovable
Your app has no server. It still has bugs.
Everything your app does happens in two places a normal monitoring tool cannot see: the browser, and Supabase. Sixty measures both from inside the page — the queries and what they return, the realtime channels, what people clicked and whether it worked, and how fast any of it was — compares each publish against the last one, and hands what it finds to the agent that wrote the code.
What it measures
- Every Supabase query the page makes
- How many run per interaction, how many rows each one returns, how big the response is, and how long it took. This is where "it got slow" almost always turns out to live.
- How fast the page is, per route
- LCP, INP, CLS and TTFB at the real p75 across everyone who loaded it — not a lab score from one machine. Broken down by country, because a page that is fine for you can be unusable somewhere with worse latency.
- What people clicked, and whether it worked
- Clicks that did nothing, repeated clicking on the same control, and interactions that redraw the page hundreds of times.
- Auth, storage, edge functions and realtime
- A Supabase app is four services, not one, and the agent understands what each endpoint does rather than only what it cost — so a refused sign-in, a missing column, a rejected write and a channel that failed to subscribe each arrive as themselves instead of as an anonymous failed request.
- The code, before it runs
- A button with no handler, an effect whose dependencies guarantee it loops forever, a subscription that is never torn down. These emit nothing at runtime — a handler that was never attached cannot be measured — so they are read out of the source at build time and ranked by how much traffic the file actually serves.
What it finds
Every one of these is compared against the release before it, so the finding names the change rather than the day.
A query that started returning everything
A filter goes missing in a rewrite and a query that returned 30 rows returns 30,000. On your project's handful of rows it is instant, so nothing looks wrong until there is real data behind it.
An N+1 born inside a render
A fetch moves inside a list and one query becomes forty. Each one is fast, so no single request looks wrong — only the count is, and the count is the thing nothing else you can install will show you.
Users seeing each other's rows — or nobody's
When a row-level security policy is missing or wrong, Postgres does not raise an error. It returns rows that should not be there, or none at all, and the page renders blank. Sixty sees both halves: the statements the database refuses under a policy, and the ones it allows that come back empty where they used to come back full.
A page that never finishes loading
A spinner still on screen twelve seconds after it appeared — usually a request that failed inside a catch, or a loading flag set true and never set back.
The schema drifting out from under the code
A column, table or relationship the code expects and the database no longer has. It fails at runtime, in the browser, on whoever loaded that page.
Errors nobody reported
Grouped by where in the code they came from, including the React failures that never crash anything — the error boundary catches them, shows a blank area, and logs.
The same realtime channel, subscribed three times over
An effect opens a subscription and never tears it down, so every render adds another. Nothing throws and nothing is slow: the user just watches each new message arrive three times, while the connection count climbs toward the limit that will switch the feature off for everybody.
A button that measurably does nothing
Clicked, and no request went out, no data changed, no page moved — usually a handler that was never wired up. Plus the repeated clicking that follows it, which is what people do when the first click appeared to do nothing.
One click redrawing the page hundreds of times
A render loop. It never errors and it never fails a request; it drains the battery of whoever is holding the phone.
Sessions being refused
A share of calls to one endpoint coming back 401 or 403, or a token that expired where one was required. In an app with no server, this is the only place a refusal is visible at all.
What lands in your feed
Not a dashboard to read. One card per finding, with the numbers, the release that changed them, and the evidence your coding agent needs to write the fix.
Reconstructed. These are failures the detector genuinely produces from a published Supabase app — but unlike the Node examples they are not the output of a script you can run, so they are drawn rather than quoted.
select:ordersThis query returns every order in the table and filters them in the browser. It was written against a project with forty rows in it, where that was instant.
on /orders, since the publish before last
select:invoicesThe query still succeeds and the database still answers. It answers with nothing, the page renders empty, and no error is raised anywhere — which is what a row-level security policy looks like when it is wrong.
on /billing, from the publish that added the policy
How it installs
You do not install this by hand. Paste one prompt into Lovable's chat and it wires the agent in — a Vite plugin, an init call, and a route that forwards telemetry so no key ever ships in your bundle. Signing in writes that prompt for you with your key already in it.
npm install @sixty-sh/supabase
// vite.config.ts
import drift from '@sixty-sh/supabase/vite'
export default defineConfig({ plugins: [react(), drift()] })
// src/integrations/supabase/client.ts — the file every Lovable app has
import { withSixty } from '@sixty-sh/supabase'
export const supabase = withSixty(createClient(URL, ANON_KEY), {
key: 'sixty_pk_…',
service: 'my-app',
endpoint: 'https://ingest.sixty.sh',
})Then publish twice. Comparison is anchored to publishes rather than to the clock, so the first finding arrives after your next one — there is nothing to compare a single version against.
What it does not do
- Findings from a published build point at the query and the route, not at a line of your source. Production bundles are minified and the sourcemap that would undo that is not read yet, so you get "this query on this page" rather than "this file, line 40".
- The Lovable preview is not enough. It runs a dev server with no fingerprinted assets, so there is no version to anchor a comparison against — the comparison needs two real publishes.
- Nothing here watches a server, because you do not have one. If you later add edge functions of your own, they need the Node agent to be visible.
If one of these is why you are here
Find out what your last change did.
Try it!Building something else? See Node services or React Native apps — those pages are different, and so is what we can see.