Web Analytics by ostr.io
ostr.io provides lightweight, privacy-respectful, real-time web analytics for modern SPAs and MPAs. The tracker works out-of-the-box with all websites and webpages, including: WordPress, WebFlow, React, Next.js, Vue, Nuxt, Svelte, Angular, Meteor/Blaze, Backbone, Ember, and vanilla JS.
Table of Contents
Why ostr.io analytics?
- 👐 Open-source tracking code
- 📦 Lightweight
- 🚀 Real-time metrics
- 😎 No DOM mutations; no heavy CPU tasks; no extra script chains
- 📡 Supports various transports:
fetch,img,beacon; falls back gracefully - 🤝 SPA-friendly: HTML5 History API and navigation events support out-of-the-box
- ⚡️ AMP tracking
- 🛑 AdBlock detection
- 🔍 Transparent data collection; GDPR/CCPA-aligned controls
- 🙆 Easy, hosted opt-out for end-users
- 🐞 Global runtime error reporting (including
unhandledPromise rejections)
What is tracked
- Real-time users, sessions, unique users.
- Pageviews
- Page title
- Page URL (sanitized per your config)
- Demographics
- Country
- City
- System
- Device (mobile/desktop)
- Browser
- OS
- Behavior
- Custom events (see
pushEvent) - Referrers
- Custom events (see
- Global script errors & exceptions
- Error message and source
- Browser and OS
- Device data
- File name and line/column
Installation
To get your trackingId, open the Analytics section in your ostr.io dashboard, select the domain, then click Show integration guide.
Script tag
[!TIP] Easiest way — no build tooling required. See "integration guide" in ostr.io analytics panel to copy-paste
<script>element
1<!-- 2After including script-tag 3analytics automatically executes in 'auto' mode, 4its instance is available in global scope as `OstrioTracker` 5Example: OstrioTracker.pushEvent(foo, bar); 6--> 7<link rel="preconnect" href="https://analytics.ostr.io/" crossorigin> 8<link rel="dns-prefetch" href="https://analytics.ostr.io/"> 9<script async defer src="https://analytics.ostr.io/{{trackingId}}.js"></script>
NPM
Install from NPM or YARN
npm install ostrio-analytics --save
Then import or require()
1// TypeScript 2import Analytics from "ostrio-analytics/source"; 3const analyticsTracker = new Analytics('{{trackingId}}'); 4 5// ESM 6import Analytics from 'ostrio-analytics'; 7const analyticsTracker = new Analytics('{{trackingId}}'); 8 9// CommonJS 10const analyticsClass = require('ostrio-analytics'); 11const analyticsTracker = new analyticsClass('{{trackingId}}');
Minified version
Copy-paste minified version of the analytics script. Or use Unpkg/JSDelivr to load minified version from CDN.
Load from Unpkg
1<script src="https://unpkg.com/ostrio-analytics@2.0.0/dist/ostrio-analytics.min.js"></script>
Load from JSDelivr
1<script src="https://cdn.jsdelivr.net/npm/ostrio-analytics@2.0.0/dist/ostrio-analytics.min.js"></script>
Copy-paste minified analytics script
[!NOTE] After adding minified analytics code to a project (using any of the methods above) — it will be available as
OstrioTrackerClassin the global scope
1// Example: 2const analyticsTracker = new OstrioTrackerClass('{{trackingId}}'); 3// Example 2: 4const analyticsTracker = new window.OstrioTrackerClass('{{trackingId}}');
Usage
Use default settings or extend with additional options object
Constructor
1new Analytics(trackingId: string, options?: OstrioWebAnalyticsConfig); 2 3interface OstrioWebAnalyticsConfig { 4 auto?: boolean; // default: true 5 trackErrors?: boolean; // default: true 6 trackHash?: boolean; // default: true 7 trackQuery?: boolean; // default: true 8 ignoredQueries?: string[]; // case-insensitive query keys to drop 9 ignoredPaths?: (string|RegExp)[]; // '/path/*' prefix, '/path/' exact, or RegExp 10 transport?: 'fetch' | 'beacon' | 'img'; // default: 'fetch' 11}
[!IMPORTANT] Constructor throws
Error('[init] {{trackingId}} is missing or incorrect!')if thetrackingIdis not a 17-char string
trackingId{string} - [Required] Website' identifier. To obtaintrackingIdgo to Analytics section and select a domain name;options- {OstrioWebAnalyticsConfig} - [Optional]options.auto- {boolean} - Set tofalseto disable automated page navigation trackingoptions.trackErrors- {boolean} - Set tofalseto disable automated page-level JS errors and exceptions trackingoptions.trackHash- {boolean} - Set tofalseto disable automated tracking of changes in#hashof the page; All reported URLs will have hash omittedoptions.trackQuery- {boolean} - Set tofalseto disable tracking changes in get query?get=query; All reported URLs will have get-query omittedoptions.ignoredQueries- {string[]} - Array of case-insensitive query keys to exclude from analytics trackingoptions.ignoredPaths- {(string|RegExp)[]} - Array of case-sensitive paths and RegExp with URI paths that will be ignored and excluded from web analytics; Use/*to define "beginning" or the path; Use to exclude "service" URLs from tracking like/admin/*; Examples:['/path/starts/with/*', '/exact-path/', /^\/category\/[0-9a-zA-Z]{10}\/?$/]options.transport- {'fetch' | 'beacon' | 'img'} - Set preferred transport; Default:fetch
[!TIP] After initializing
new Analytics()— it's good to go, visitor navigation will be collected and reported in ostr.io analytics. For{auto: false}, additional settings, and custom events - see below.
All Methods
List of all methods and its arguments available on OstrioWebAnalytics instance:
1import Analytics from "ostrio-analytics/source"; 2const analyticsTracker = new Analytics('{{trackingId}}'); 3 4// CHANGE SETTINGS DURING RUNTIME 5analyticsTracker.applySettings(settings: OstrioWebAnalyticsDynamicConfig); 6interface OstrioWebAnalyticsDynamicConfig { 7 trackHash?: boolean; 8 trackQuery?: boolean; 9 transport?: Transport; 10 serviceUrl?: string; 11} 12 13// CHANGE TRANSPORT DURING RUNTIME 14analyticsTracker.setTransport(Transport); // [Transport.Fetch, Transport.Beacon, Transport.Img] 15 16// ADD IGNORED PATH DURING RUNTIME 17analyticsTracker.ignorePath(path: string | RegExp); 18 19// ADD MULTIPLE IGNORED PATHS DURING RUNTIME 20analyticsTracker.ignorePaths(paths: Array<string | RegExp>); 21 22// ADD IGNORED GET-QUERY DURING RUNTIME 23analyticsTracker.ignoreQuery(queryKey: string); 24 25// ADD MULTIPLE IGNORED GET-QUERIES DURING RUNTIME 26analyticsTracker.ignoreQueries(queryKeys: Array<string>); 27 28// ADD HOOK FOR .pushEvent() CALLS 29analyticsTracker.onPushEvent(callback: Function); 30 31// ADD HOOK FOR .track() CALLS 32analyticsTracker.onTrack(callback: Function); 33 34// TRACK CUSTOM EVENT 35analyticsTracker.pushEvent(key: string, value: number | string); 36 37// TRACK PAGEVIEW; USE WITH {auto: false} SETTING 38analyticsTracker.track(); 39 40// STOP AUTO-TRACKING 41analyticsTracker.destroy();
Track Custom Events
Use analyticsTracker.pushEvent(key, value) method to collect and track custom user's events. Custom events are useful for tracking certain activity on your website, like clicks, form submits and others user's behaviors.
key{string} - [Required] The length of the event key must be between 1 and 24 symbols;value{string} - [Required] The length of the event value must be between 1 and 64 symbols.
If the length of key or value is longer than limits, it will be truncated without throwing an exception.
Examples:
1// Various examples on tracking custom user's actions 2analyticsTracker.pushEvent('userAction', 'login'); 3analyticsTracker.pushEvent('userAction', 'logout'); 4analyticsTracker.pushEvent('userAction', 'signup'); 5 6analyticsTracker.pushEvent('click', 'purchase'); 7analyticsTracker.pushEvent('click', 'purchase-left'); 8analyticsTracker.pushEvent('click', 'pricing - more info');
1<script type="text/javascript"> 2 // make analyticsTracker global variable 3 window.analyticsTracker = analyticsTracker; 4</script> 5 6<form> 7 <h2>Buy Now</h2> 8 <select> 9 <option disabled>Select product</option> 10 <option>Blue</option> 11 <option>Red</option> 12 <option>Green</option> 13 </select> 14 <input name="qty" /> 15 <!-- Example on tracking form submit --> 16 <button type="submit" onClick="analyticsTracker.pushEvent('checkout', 'buy-now-form')">Checkout</button> 17</form>
In a similar way using .pushEvent you can detect and track AdBlock usage and Accelerated Mobile Pages (AMP).
Custom Navigation Tracking
Manually dispatch a pageview.
[!TIP] Use
.track()method with{auto: false}to manually and precisely control navigation's events and send tracking info. This method has no arguments.
Examples:
1/* jQuery or any other similar case: */ 2$(document).ready(() => { 3 analyticsTracker.track(); 4}); 5 6/* JS-router definition (pseudo-code!) */ 7router({ 8 '/'() { 9 analyticsTracker.track(); 10 }, 11 '/two'() { 12 analyticsTracker.track(); 13 }, 14 '/three'() { 15 analyticsTracker.track(); 16 } 17}); 18 19/* Although "History.js" and "History API" supported out-of-box, 20you may want to optimize tracking behavior to meet your needs. */ 21History.Adapter.bind(window, 'statechange', () => { 22 analyticsTracker.track(); 23});
Event Callbacks
Use .onPushEvent() to hook into .pushEvent() method. Read how to use this method for deep Google Analytics integration.
Examples:
1analyticsTracker.onPushEvent((key, value) => { 2 console.log({ key, value }); // { key: 'testKey', value: 'testValue' } 3}); 4 5analyticsTracker.pushEvent('testKey', 'testValue');
Tracking Callbacks
Use .onTrack() to hook into .track() method and browser navigation in {auto: true} mode. Read how to use this method for deep Google Analytics integration.
Examples:
1// Callback will be executed on every browser navigation and upon calling `.track()` method 2analyticsTracker.onTrack(() => { 3 console.log('Tracking a session'); // Tracking a session 4});
Destroy Tracker
Call .destroy() to unbind listeners and timers (useful on SPA teardown/HMR).
1analyticsTracker.destroy();
Advanced
Explore advanced settings and its usage
Transports
{ transport: 'beacon' }– usesnavigator.sendBeaconwhen available (best for unload/background sends, but commonly blocked by browsers){ transport: 'fetch' }(default) – usesfetchwith{ mode: 'no-cors', cache: 'no-store' }{ transport: 'img' }– legacy image-pixel transport for top compatibility with various browsers
1const analyticsTracker = new Analytics('{{trackingId}}', { transport: 'img' }); 2 3// OR DURING RUNTIME: 4analyticsTracker.setTransport('beacon');
Ignoring paths
Exclude paths from tracking with exact match, prefix, or RegExp. Use .ignorePath() or .ignorePaths() to add ignored paths during runtime:
1analyticsTracker.ignorePath('/admin/*'); 2analyticsTracker.ignorePath('/payment/status/complete'); 3analyticsTracker.ignorePath(/^\/_next\//i); 4 5// OR ADD ALL AS ARRAY IN ONE CALL 6analyticsTracker.ignorePaths(['/admin/*', '/payment/status/complete']);
Use ignoredPaths as part of the Constructor config object:
1const analyticsTracker = new Analytics('{{trackingId}}', { 2 ignoredPaths: [ 3 '/admin/', // exact match 4 '/api/*', // prefix match 5 /^\/_next\// // RegExp 6 ] 7});
Ignoring queries / search params
[!NOTE] Note: Referral source is tracked via HTTP headers
Remove noisy query keys (case-insensitive) from URL change detection and payload. Use .ignoreQuery() or .ignoreQueries() to add ignored paths during runtime:
1analyticsTracker.ignoreQuery('utm'); 2analyticsTracker.ignoreQuery('ref'); 3 4// OR ADD ALL AS ARRAY IN ONE CALL 5analyticsTracker.ignoreQueries(['gclid', 'fbclid', 'sessionid']);
Use ignoredQueries as part of the Constructor config object:
1const analyticsTracker = new Analytics('{{trackingId}}', { 2 ignoredQueries: ['utm_source', 'utm_medium', 'gclid', 'fbclid', 'sessionid'] 3});
Hash & query tracking controls
Control what constitutes a “new page” for SPAs:
1const analyticsTracker = new Analytics('{{trackingId}}', { 2 trackHash: false, // don't treat #hash changes as navigation (default: true) 3 trackQuery: false // don't treat ?query changes as navigation (default: true) 4}); 5 6// OR UPDATE SETTING DURING RUNTIME: 7analyticsTracker.applySettings({ 8 trackHash: false, 9 trackQuery: false 10});
Examples
Explore various custom usage examples
Google Analytics integration
Using .onTrack() method and .onPushEvent() method we can send tracking-data to Google Analytics upon navigation or event.
In your <head> add Google Analytics as instructed:
1<script async src="https://www.google-analytics.com/analytics.js"></script> 2<script type='text/javascript'> 3 window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date; 4 ga('create', 'UA-XXXXXXXXX-X', 'auto'); 5</script>
1import Analytics from 'ostrio-analytics'; 2const analyticsTracker = new Analytics('{{trackingId}}'); 3 4analyticsTracker.onTrack(() => { 5 // Track navigation with Google Analytics 6 ga('send', { 7 hitType: 'pageview', 8 page: document.location.pathname, 9 location: document.location.href, 10 title: document.title 11 }); 12}); 13 14analyticsTracker.onPushEvent((name, value) => { 15 // Send events to Google Analytics 16 ga('send', { 17 hitType: 'event', 18 eventCategory: name, 19 eventAction: value 20 }); 21});
Google Tag Manager integration
Using .onTrack() method and .onPushEvent() method we can send tracking-data to Google Tag Manager upon navigation or event.
In page's <head> add Google Tag Manager as instructed:
1<script async src="https://www.googletagmanager.com/gtag/js?id=UA-XXXXXXXXX-X"></script> 2<script type='text/javascript'> 3 window.dataLayer = window.dataLayer || []; 4 function gtag(){dataLayer.push(arguments);} 5 gtag('js', new Date()); 6</script>
1import Analytics from 'ostrio-analytics'; 2const analyticsTracker = new Analytics('{{trackingId}}'); 3 4analyticsTracker.onTrack(() => { 5 // Track navigation with Google Analytics 6 gtag('config', 'UA-XXXXXXXXX-X', { 7 page_title: document.title, 8 page_path: document.location.pathname, 9 page_location: document.location.href 10 }); 11}); 12 13analyticsTracker.onPushEvent((name, value) => { 14 // Send events to Google Analytics 15 gtag('event', name, { value }); 16});
Compliance
Opt-out for end-users
[!TIP] Provide a one-click opt-out link in project's legal/settings pages to follow the best privacy experience practices
https://analytics.ostr.io/settings/manage/opt-out/
- Add one-click opt-out link to legal documents and "settings" page
- Click here to check your browser current settings