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

  1. 01 Create an account and a project. Every project gets a public write key that looks like fp_ followed by 24 characters.
  2. 02 Drop the snippet into your app. This is the whole install for a plain website:
    <script async src="https://betterloopai.com/sdk.js" data-key="bl_your_write_key"></script>
    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.
  3. 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.
  4. 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.
  5. 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.

EventWhat it records
pageviewPath, query string, and document title on load and on SPA navigation.
clickElement descriptor (tag, id, up to 2 classes, 4 levels of ancestors) plus a short label.
rage_click3 clicks on the same element within 700ms of each other.
dead_clickA click on an interactive-looking element with no DOM change and no navigation for 800ms.
errorwindow.onerror: message, first 1000 chars of stack, file:line:col. Resource load failures too.
rejectionUnhandled promise rejections: message and stack.
vitalLCP, CLS, INP, FCP, TTFB, sampled from PerformanceObserver.
customAnything you send with track(), plus the internal $time_on_page timing.
session_endSession 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

LimitFreePro
Projects15
Events per month, per project10,000500,000
Insight runsweeklydaily

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