@rabolic/web
Browser analytics in a few lines, under 8 KB gzip.
Install from npm or paste a script tag. The web SDK sends a page view for every route of a single-page app, measures how long each page was read, keeps the campaign that brought the visitor, and waits for consent when you ask it to.
- No runtime dependencies
- No CORS preflight
- Calls never throw
import { rabolic } from '@rabolic/web'
rabolic.init({ projectKey: 'rb_pub_…', trackRoutes: true })
// after signup or login
rabolic.identify(user.id, { plan: 'pro' })
rabolic.track('signup_completed', { method: 'google' })trackRoutes: true
A page view for every route, with no router plugin.
The SDK listens to the browser’s history, so React, Vue, Svelte and plain sites all get a $pageview per route. When a visitor leaves a page, $page_leave records how long they were active on it and how far they scrolled.
$pageviewon load and onpushState,replaceStateandpopstate- Same-URL and hash-only changes are ignored
$page_leavewithactive_msandscroll_depth(0–1)- On page hide, the queue goes out with
sendBeacon
Plans for every routine
Create your account
Continue with GoogleWelcome, Lena
- Pick a program
- Install the app
- Start a workout
@rabolic/web
trackRoutes: true
- $pageview/pricing · campaign: newsletter
- $page_leaveactive_ms: 18400 · scroll_depth: 0.82
- $pageview/signup
- signup_completedmethod: google
- $identifyuser_id: usr_8f2k1x9q
- $page_leaveactive_ms: 9200 · scroll_depth: 1
- $pageview/welcome
context.campaign
Every event knows where the visit came from.
The landing URL’s campaign parameters and click id are kept for the whole visit, and a landing with different ones starts a new session. Sessions are shared by your tabs and end after 30 minutes without an event, or the timeout you set for the project.
Requests go out as text/plain with the key in the body and no credentials, so the browser sends no CORS preflight.
| Field | What it holds |
|---|---|
| platform | web |
| page | URL, path, title and referrer |
| campaign | utm_source, utm_medium, utm_campaign, utm_content, utm_term, and the click id type: gclid, fbclid, ttclid or msclkid |
| locale, timezone | From the browser, such as en-US and Europe/Berlin |
| screen | Width, height and pixel density |
| user_agent | Rabolic reads the browser, OS and device from it |
the api
The whole API fits on one screen.
Calls made before init are kept, up to 100, and replayed. No method throws into your page; pass debug: true to see why a call was dropped.
| Method | Does |
|---|---|
| init(options) | Starts the SDK. Logs and does nothing for a missing, invalid or secret key |
| track(event, properties?) | A custom event, in snake_case. Names starting with $ are reserved |
| page(properties?) | A manual $pageview |
| identify(userId, traits?) | Sets the user id on this and later events, and sends $identify with the traits |
| reset() | On logout: a new anonymous id and session, no user id, no super properties |
| register(properties) / unregister(key) | Super properties, sent with every later event. Event properties win |
| setConsent('granted' | 'pending' | 'denied') | Changes consent at runtime. optIn() and optOut() are short for granted and denied |
| flush() | Sends the queue now. Never rejects |
| getAnonymousId() | The anonymous id, or null before init |
| appLink(url) | Adds rb_aid to a store or deep link, so your app can link the visitor |
// A custom event, in snake_case
rabolic.track('checkout_completed', { plan: 'pro_yearly' })
// Super properties: sent with every later event
rabolic.register({ app_version: '2.4.0' })
rabolic.unregister('app_version')
// A manual $pageview
rabolic.page()
// Carry this visitor into your app (adds rb_aid)
const link = rabolic.appLink('https://apps.apple.com/app/id1234567890')
// Send the queue now; never rejects
await rabolic.flush()rabolic.init(options)
Options.
Only the key is required. With the script tag, set data-key and, for a proxy, data-host.
| Option | Default | Notes |
|---|---|---|
| projectKey | required | The publishable key, rb_pub_… |
| host | Rabolic’s ingest | https://ingest.rabolic.com, or your first-party proxy |
| trackRoutes | true | $pageview on single-page-app navigation |
| trackPageLeave | true | $page_leave with active time and scroll depth |
| persistence | 'localStorage' | 'memory' is cookieless: ids last one page lifetime |
| cookieDomain | current host | Such as .example.com, to share rb_aid across subdomains |
| consent | 'granted' | 'pending' until your consent banner answers |
| flushAt | 20 | Send when this many events are queued (1–500) |
| flushIntervalMs | 5000 | Send at least this often |
| debug | false | Log every call, and why a call was dropped |
consent: 'pending'
Wait for consent, or store nothing at all.
The SDK never reads form fields, the clipboard or location, and never fingerprints the browser. What it does store, and when, is up to you.
'granted'
Granted
The default. Tracks, stores the ids and sends.
'pending'
Pending
Writes no cookie and nothing to storage, and sends nothing. Events wait in memory until you call setConsent('granted').
'denied'
Denied
Drops the queue and removes everything the SDK stored, the cookie included.
persistence: 'memory'
Cookieless
No cookie and nothing in localStorage, without a banner. Ids live in memory for one page lifetime, so each page load is a new visitor.
// Cookieless: no cookie, nothing in localStorage.
// Ids last one page lifetime.
rabolic.init({ projectKey: 'rb_pub_…', persistence: 'memory' })
// Or wait for your consent banner:
// nothing is stored or sent until it answers.
rabolic.init({ projectKey: 'rb_pub_…', consent: 'pending' })
rabolic.setConsent('granted') // or 'denied'What it stores
With the default persistence: 'localStorage' and consent granted. Cookieless mode and pending consent store none of it.
| Where | Name | What |
|---|---|---|
| localStorage | rb_aid | The anonymous id: a random UUID |
| Cookie, first-party | rb_aid | The same id. SameSite=Lax, Secure on https, one year. It restores the id if localStorage was cleared |
| localStorage | rb_session | The session id and the time of the last event, shared by your tabs |
| localStorage | rb_queue | Events not sent yet, up to 1,000 |
| localStorage | rb_uid, rb_super, rb_config | The user id after identify(), super properties, and the project’s session settings |
web sdk faq
The web SDK, answered.
How big is the web SDK?
The script on cdn.rabolic.com is under 8 KB gzip, and its build fails if it grows past that. The package has no runtime dependencies.
Does it track single-page apps?
Yes. With trackRoutes on (the default), it sends a $pageview on every pushState, replaceState and popstate, and a $page_leave for the page before. Hash-only changes and navigation to the same URL are ignored.
Does it set cookies?
By default it keeps a random anonymous id in localStorage and mirrors it to a first-party rb_aid cookie for one year. With consent: 'pending' nothing is written until consent is granted, and with persistence: 'memory' (cookieless mode) nothing is ever written.
Do I need a consent banner?
That depends on the law where your visitors are, and on your own advice. The SDK supports both routes: consent: 'pending' waits for your banner, and cookieless mode stores nothing at all. rabolic.com itself uses cookieless mode and shows no banner.
What does the script tag loader do?
It defines a small window.rabolic stub that queues your calls, loads https://cdn.rabolic.com/v1/rabolic.js asynchronously, and replays the calls in order once it has loaded. Without the loader, a plain script tag with a data-key attribute starts the SDK on its own.
Can I pin a version of the script?
Yes. /v1/rabolic.js is the latest release, and every release is also published at /v1/<version>/rabolic.js, such as https://cdn.rabolic.com/v1/0.1.1/rabolic.js.
Which campaigns does it record?
The utm_source, utm_medium, utm_campaign, utm_content and utm_term parameters of the landing URL, and which click id it carried (gclid, fbclid, ttclid or msclkid). A landing with different campaign parameters starts a new session, so each campaign gets its own visit.
Can I use a secret key in the browser?
No. The web SDK refuses rb_live_ and rb_test_ keys and logs a warning to rotate the exposed key. Browsers use the publishable rb_pub_ key, which can only send events and can’t send revenue.
Add Rabolic to your site in a few lines.
Start a 3-day trial without a card. It begins with your first event, so you can set up the SDKs first.
- 1
Create a project
Sign up, name your project, and copy its publishable key.
- 2
Add an SDK
Web, React Native, Flutter or Node.js, or the HTTP API. Or run npx rabolic init.
- 3
Watch the first event arrive
It shows in live events within seconds, and your trial starts then.