Betterloop docs
Betterloop is frontend analytics that produces fixes instead of charts. A dependency-free browser SDK collects real usage signals, a set of deterministic detectors plus an optional AI layer turns them into ranked insights, and you read those insights on the dashboard, in Slack, or inside your AI coding agent over MCP.
Quickstart
- 01 Create an account and a project. Every project gets a public write key that looks like fp_ followed by 24 characters.
- 02 Drop the snippet into your app. This is the whole install for a plain website:Your project's Setup tab shows the same snippet with your real write key already filled in. Bundled apps can import the SDK instead - see Install the SDK.
<script async src="https://betterloopai.com/sdk.js" data-key="bl_your_write_key"></script>
- 03 Load a page. The first batch is sent within 5 seconds, and the Setup tab flips to live as soon as the first event lands.
- 04 Wait for traffic. The detectors need a few sessions per pattern before they fire - see the exact thresholds in How insights work. You can also hit "Generate now" on the Insights tab to run them on demand.
- 05 Read the insights where you work: dashboard, Slack digest, or MCP in Claude Code.
What the SDK collects
Nine event types, all captured automatically except custom.
| Event | What it records |
|---|---|
| pageview | Path, query string, and document title on load and on SPA navigation. |
| click | Element descriptor (tag, id, up to 2 classes, 4 levels of ancestors) plus a short label. |
| rage_click | 3 clicks on the same element within 700ms of each other. |
| dead_click | A click on an interactive-looking element with no DOM change and no navigation for 800ms. |
| error | window.onerror: message, first 1000 chars of stack, file:line:col. Resource load failures too. |
| rejection | Unhandled promise rejections: message and stack. |
| vital | LCP, CLS, INP, FCP, TTFB, sampled from PerformanceObserver. |
| custom | Anything you send with track(), plus the internal $time_on_page timing. |
| session_end | Session duration, emitted on pagehide. |
No cookies, no fingerprinting, no input values, and Do Not Track is honored by default. The full list of what is and is not stored is on Privacy and data.
How the pipeline fits together
browser (sdk.js) | batches of up to 50 events, flushed every 5s | sendBeacon on page hide, fetch keepalive otherwise v POST /api/ingest write key auth, origin allowlist, monthly quota v events table raw signals, 7-day rolling analysis window v insight engine 5 rule detectors + optional AI layer v insights table deduped by fingerprint, status: new/ack/done/dismissed | +--> dashboard /app/<projectId>/insights +--> Slack per-project incoming webhook digest +--> MCP list_projects / get_insights / get_metrics / get_errors +--> REST GET /api/v1/* with a Bearer blk_ key
Plans and limits
| Limit | Free | Pro |
|---|---|---|
| Projects | 1 | 5 |
| Events per month, per project | 10,000 | 500,000 |
| Insight runs | weekly | daily |
Over quota, ingest returns 402 quota_exceeded and the batch is dropped - it is never billed silently, and the counter resets at the start of each calendar month (UTC). Pro checkout is not switched on yet; the plan limits above are what the code enforces today.
Where to go next
Install the SDK
Script tag, npm, React, Next.js, Vue, SPA behaviour, custom events.
How insights work
The five detectors, their exact thresholds, severity, and the status lifecycle.
Analytics and AI-drawn views
Every metric the analyst can reach, and why it never writes a query against your data.
MCP server
Give Claude Code or Codex read access to your production insights.
REST API
Bearer auth, the four v1 endpoints, and the ingest contract.