Web
@rabolic/web is Rabolic for the browser. It has no runtime dependencies, and the CDN build is under 8 KB gzip. Source: github.com/rabolic/sdks/js/web.
Use the project's publishable key (rb_pub_…). Secret keys (rb_live_, rb_test_) are refused in the browser.
Install
The quickest way is npx rabolic init in your project. By hand:
npm install @rabolic/web
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' })
createRabolic() returns an independent instance if you need more than the rabolic singleton. Calls made before init are kept (up to 100) and replayed.
The simplest tag initializes itself from its data attributes:
<script async src="https://cdn.rabolic.com/v1/rabolic.js" data-key="rb_pub_…"></script>
Add data-host="https://ingest.example.com" to send events through your own proxy.
To call rabolic.track() from your own scripts before the file has loaded, paste the loader into <head> instead. It defines a stub window.rabolic that queues calls until the script has loaded, then replays them in order:
<script>
!(function (w, d, src) {
if (w.rabolic) return
var q = (w.rabolic = [])
var m = ['init', 'track', 'page', 'identify', 'reset', 'register', 'unregister', 'setConsent', 'optOut', 'optIn', 'flush']
for (var i = 0; i < m.length; i++)
(function (n) {
q[n] = function () {
q.push([n].concat([].slice.call(arguments)))
}
})(m[i])
q.getAnonymousId = function () {
return null
}
q.appLink = function (url) {
return url
}
var s = d.createElement('script')
s.async = true
s.src = src
d.head.appendChild(s)
})(window, document, 'https://cdn.rabolic.com/v1/rabolic.js')
rabolic.init({ projectKey: 'rb_pub_YOUR_KEY' })
</script>
The same code is exported from the npm package as SNIPPET (and snippetFor(projectKey)).
Options
Pass them to init().
| Option | Default | |
|---|---|---|
projectKey | required | Publishable key, rb_pub_… |
host | https://ingest.rabolic.com | For a first-party proxy or self-hosting |
trackRoutes | true | $pageview on SPA navigation (pushState, replaceState, popstate) |
trackPageLeave | true | $page_leave with active_ms and scroll_depth |
persistence | 'localStorage' | 'memory': cookieless, ids last one page lifetime |
cookieDomain | current host | Such as .example.com, to share rb_aid across subdomains |
consent | 'granted' | 'pending' until your cookie banner answers |
debug | false | Log every call |
flushAt | 20 | Send when this many events are queued (1–500) |
flushIntervalMs | 5000 | Send at least this often |
At start the SDK fetches remote config (GET /v1/config, cached for 5 minutes). Today it sets the session timeout from your project settings. The protocol has more switches, but no project setting controls them yet.
API
| Method | Does |
|---|---|
init(options) | Starts the SDK. Logs and does nothing for a missing, invalid or secret key |
track(event, properties?) | Custom event. snake_case; names starting with $ are reserved |
page(properties?) | A manual $pageview |
identify(userId, traits?) | Sets user_id on this and later events; sends $identify with traits |
reset() | Logout: 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 |
optOut() / optIn() | setConsent('denied') / setConsent('granted') |
flush() | Sends the queue now. Never rejects |
getAnonymousId() | The anonymous id, or null before init |
appLink(url) | Adds rb_aid=<anonymous id> to a store or deep link (needs consent) |
No method throws into your page. Pass debug: true to see why a call was dropped.
Automatic events
| Event | When |
|---|---|
$pageview | One on load and one per SPA route. Same-URL and hash-only changes are ignored |
$page_leave | One per page view, on route change or the first time the page is hidden. With active_ms and scroll_depth |
- Active time:
active_mscounts time the page was visible and interacted with in the last 30 s.scroll_depthis the furthest point seen, from 0 to 1. - Page hide: on
visibilitychangeto hidden orpagehide, queued events go out withnavigator.sendBeacon. - Campaigns:
utm_*and the click id type (gclid,fbclid,ttclid,msclkid) from the landing URL go incontext.campaign. - Context:
platform: 'web', locale, time zone, screen size and density, page URL, path, title and referrer, and the user agent.
Sessions
- Sessions are shared across tabs through
localStorage. - A new session starts after 30 minutes without events, or the web session timeout set in your project settings.
- A landing with different campaign parameters starts a new session.
reset()starts a new session.
See Sessions.
Identity
Call identify() after signup and after every login, with your own stable user id. Use the same id on every platform:
rabolic.identify(user.id, { plan: 'pro' })
Call reset() when someone logs out, so the next person on that device starts fresh:
rabolic.reset()
See Identity.
Links into your app
rabolic.appLink(url) adds rb_aid=<anonymous id> to a store or deep link. The React Native and Flutter SDKs report it in $deep_link as linked_anonymous_id. Rabolic stores it, but doesn't link the web visitor to the app user by it yet. To join them today, call identify() with the same user id on both sides.
Consent and privacy
consent | What happens |
|---|---|
'granted' (default) | Tracks and sends normally |
'pending' | Writes no cookie and nothing to storage, and sends nothing. Events wait in memory until setConsent('granted') |
'denied' | Drops the queue and removes everything stored, cookie included |
rabolic.init({ projectKey: 'rb_pub_…', consent: 'pending' })
// when your cookie banner answers
rabolic.setConsent('granted') // or 'denied'
Cookieless mode. persistence: 'memory' keeps the ids in memory only, for one page lifetime. Nothing is written to cookies or localStorage.
What the SDK stores, with the default persistence:
- the anonymous id, a random UUID, in
localStorage(rb_aid), mirrored to a first-partyrb_aidcookie (SameSite=Lax,Secureon https, one year); - the session id and last activity, in
localStorage; - the unsent queue, in
localStorage(rb_queue).
The SDK never reads form fields, the clipboard or location, and does no fingerprinting. See Consent and privacy.
Delivery and limits
| Requests | text/plain with the key in the body and no credentials, so the browser sends no CORS preflight |
| Queue | Up to 1,000 events in localStorage (rb_queue). It survives reloads. When full, the oldest go first |
| Batch | Up to 500 events or 900 KB |
| One event | 32 KB (32,768 bytes of UTF-8 JSON). Larger events are dropped |
| Event age | Events older than 7 days are dropped before sending |
See Limits.
Trial
Rabolic's 3-day free trial with Growth's features and a 250,000-event cap. It starts with your first accepted event, needs no card, and is one per person.
React Native and Expo
Install @rabolic/react-native in Expo or bare React Native apps for iOS and Android. Options, app lifecycle events, screens with React Navigation and Expo Router, identity, deep links, consent and limits.