@xsolla/metrika
v2.16.1
Published
A lightweight integration library for Xsolla Metrics (XMTS) that simplifies user tracking and analytics setup.
Maintainers
Readme
Xsolla Metrika
A lightweight integration library for Xsolla Metrics (XMTS) that simplifies user tracking and analytics setup. Supports SPA and classic sites, works in all modern browsers, and provides full TypeScript support.
Table of Contents
- Features
- Installation
- Usage
- Configuration
- Sending data
- API Reference
- Trackers
- What Data Is Sent
- TypeScript Support
- Migration from v1
- Browser Support
- License
Features
- 📦 Tiny: Minimal bundle size, no heavy dependencies.
- 🧑💻 TypeScript-first: Full type definitions out of the box.
- ⚡ SPA-ready: Tracks navigation in React, Vue, Angular, etc.
- 🖱️ Auto-tracking: Clicks, scrolls, external links, performance, and more.
- 🧬 Device fingerprinting.
- 🌍 Flexible delivery: Works with
sendBeaconandfetch. - 🔌 Custom events: Send any data, integrate with A/B tests, etc.
Installation
Bundles
Xsolla Metrika provides several bundle formats for different use cases:
| Format | File | Best For |
| ------ | -------------------------------------- | -------------------------------------------------------------------------- |
| IIFE | dist/xsolla-metrika.js | Direct <script> inclusion in browsers |
| IIFE | dist/xsolla-metrika.min.js | Minified version for browser usage |
| IIFE | dist/xsolla-metrika.bootstrap.js | Auto-initialization via <script data-*>, available as window.analytics |
| IIFE | dist/xsolla-metrika.bootstrap.min.js | Minified version of the auto-initialization bundle |
| CJS | dist/xsolla-metrika.cjs.cjs | Node.js/CommonJS (require) |
| ESM | dist/xsolla-metrika.esm.js | Modern bundlers and ESM imports (import) |
| Types | dist/xsolla-metrika.d.ts | TypeScript type definitions |
npm / yarn
npm install @xsolla/metrika
# or
yarn add @xsolla/metrikaCDN (jsDelivr / unpkg)
<!-- jsDelivr (IIFE) -->
<script src="https://cdn.jsdelivr.net/npm/@xsolla/metrika@2"></script>
<!-- unpkg (IIFE) -->
<script src="https://unpkg.com/@xsolla/metrika@2"></script>Note: The
@2version range automatically resolves to the latest2.x.xrelease. This is the recommended approach for production — semver guarantees backward compatibility within a major version.
Usage
ESM
import XsollaAnalytics from '@xsolla/metrika';
(async () => {
const analytics = await XsollaAnalytics.init({
id: 'YOUR_COUNTER_ID',
hit: true,
navigation: true,
// ...other options
});
analytics.hit(window.location.href);
analytics.elementClick('my-button');
})();CommonJS
const XsollaAnalytics = require('@xsolla/metrika').default;
XsollaAnalytics.init({ id: 'YOUR_COUNTER_ID', hit: true }).then((analytics) => {
analytics.hit(window.location.href);
});IIFE
<script src="https://cdn.jsdelivr.net/npm/@xsolla/metrika@2"></script>
<script>
window.XsollaAnalytics.init({
id: 'YOUR_COUNTER_ID',
hit: true,
navigation: true,
}).then(function (analytics) {
analytics.hit(window.location.href);
});
</script>IIFE (BOOTSTRAP)
A special bootstrap IIFE bundle: dist/xsolla-metrika.bootstrap.js and its minified version dist/xsolla-metrika.bootstrap.min.js.
This bundle allows you to specify configuration parameters directly via data-attributes on the <script> tag. The analytics instance is then automatically created and becomes available as window.analytics.
<script
src="https://cdn.jsdelivr.net/npm/@xsolla/metrika@2/dist/xsolla-metrika.bootstrap.min.js"
data-id="123456"
data-hit="true"
data-click="true"
data-ext-link="true"
data-site-domains='["example.com","sub.example.com"]'
></script>Note:
- All parameters must be specified in kebab-case format.
- All values that require parsing (such as arrays or objects) must be enclosed in single quotes.
Configuration
Parameters Table
| Name | Type | Default | Description |
| --------------------- | ------------------------------------------- | ---------------------------------- | ------------------------------------------------------------ |
| id | string \| number | required | Counter ID (unique for your project) |
| hit | boolean | true | Track page load (pageview) |
| extLink | boolean | false | Track external links (outside siteDomains) |
| click | boolean | false | Track clicks on elements with data-analytics="true" |
| scroll | boolean | false | Track scroll depth (10%, 50%, 90%) |
| crossDomainTracking | boolean | false | Track transitions to allowed domains (siteDomains) |
| sendLoadMetrics | boolean | false | Send performance metrics (LCP, TTFB, etc.) |
| navigation | boolean | false | Track navigation events (SPA support) |
| siteDomains | string[] | [] | List of internal domains for link tracking (see note below) |
| server | string | 'https://minimetrika.xsolla.com' | Analytics server base URL |
| hitEndpoint | string | 'hit' | Endpoint for pageview events |
| externalId | number | undefined | External user ID (see note below) |
| merchantId | number | undefined | Merchant ID — legacy alias of externalId (see note below) |
| extraValues | Record<string, unknown> | {} | Additional custom parameters |
| abParams | Record<string, unknown> | {} | A/B test parameters |
| useBeacon | boolean | true | Use sendBeacon API for sending data |
| retryOptions | { retries?: number, retryDelay?: number } | { retries: 2, retryDelay: 500 } | Options for retrying failed fetch requests |
| ip | string | undefined | User IP (for override, optional) |
| scrollContainers | ScrollContainerSpec[] | undefined | Track scroll depth inside specific elements (see note below) |
Note:
scrollContainersis a list of{ selector: string; name: string }entries, both fields required. It is independent of thescrollflag — enable either, both, or neither. Example:scrollContainers: [{ selector: '#chat', name: 'chat_messages' }]. A container is only tracked ifcontainer.getRootNode() === document— a scroller inside a shadow tree or an iframe emits nothing; initialise the SDK inside that document instead. See docs/trackers.md for thresholds, multi-match semantics and diagnostics.
Note:
externalIdandmerchantIdare two names for the same thing and both end up in the payload's single rooteidfield. Neither name is ever sent on the wire.merchantIdis the older spelling, kept for installs that still pass it. If you supply both,externalIdwins — including when it is0, which is treated as a real id rather than as "unset". New integrations should pass onlyexternalId.
Note:
siteDomainshas no built-in entries — no Xsolla property (xsolla.site,xsolla.comor any other) is internal unless you list it yourself. The only host added for you iswindow.location.host, the page's own host, which is always treated as internal so a link back to the current page is never reported as external; your entries are added on top of it. Entries match subdomains too, so'example.com'also covers'sub.example.com'. The same list drivesextLink, so a link matching an entry is never reported as an external-link event, while a host you do not list is reported as external — including Xsolla properties. List the hosts you consider your own to opt them into both behaviours at once.
Sending Data
By default, Xsolla Metrika sends all events using sendBeacon for maximum reliability (especially during page unload).
Global setting:
If you want to use regularfetchinstead ofsendBeaconfor manual methods (hit,externalLink,elementClick, etc.), set theuseBeacon: falseparameter during initialization:XsollaAnalytics.init({ id: 'YOUR_COUNTER_ID', useBeacon: false, // ... });Important:
Automatic trackers (such as auto pageview, click, scroll tracking, etc.) always usesendBeaconregardless of the global parameter.Override per event:
In any manual method (hit,externalLink,elementClick, etc.), you can explicitly specify the sending method using theuseBeaconoption:analytics.hit(window.location.href, {}, false); // sends via fetch analytics.hit(window.location.href, {}, true); // sends via sendBeaconRetries with fetch:
IfsendBeaconis not available or fails, or if you explicitly usefetchfor sending, the library will automatically retry the request up to two additional times (total of 3 attempts) in case of network errors or server errors.Customizing retries:
You can control the number of retry attempts and delay between them using theretryOptionsparameter during initialization:XsollaAnalytics.init({ id: 'YOUR_COUNTER_ID', retryOptions: { retries: 5, // Number of retry attempts (default: 2) retryDelay: 1000, // Delay between retries in ms (default: 500) }, });If
retryOptionsis not specified, the default is 2 retries with a 500ms delay.
This allows you to flexibly control how events are sent depending on your needs.
API Reference
Instance Methods
| Method | Arguments | Returns | Description |
| ----------------------- | ---------------------------------------------------------------------------- | --------------------- | ----------------------------------------------- |
| hit | url: string, data?: object, useBeacon?: boolean | Promise<boolean> | Send a pageview event |
| externalLink | url: string, data?: object, useBeacon?: boolean | Promise<boolean> | Track an external link click |
| elementClick | name: string, data?: object, useBeacon?: boolean | Promise<boolean> | Track a named element click |
| formData | name: string, form: object \| FormData, data?: object, useBeacon?: boolean | Promise<boolean> | Track form submission |
| customEvent | name: string, data?: object, useBeacon?: boolean | Promise<boolean> | Send a custom named event |
| sendCustomData | endpoint: string, data: object, useBeacon?: boolean | Promise<boolean> | Send arbitrary data to a custom analytics route |
| payStationUserSession | data: object, useBeacon?: boolean | Promise<boolean> | Track Pay Station user session |
| eventForLCP | useBeacon?: boolean | Promise<boolean> | Send Largest Contentful Paint event |
| setAbParams | abParams: object | void | Update A/B test parameters |
| setExtraValues | extraValues: object | void | Update extra values |
| getClientId | none | string | Get the current client ID |
| getVisitorId | none | string | Get the current visitor ID |
| getFingerprintHash | none | string \| undefined | Get device fingerprint hash |
| getFingerprintData | none | object \| undefined | Get raw device fingerprint data |
| destroy | none | void | Unsubscribe all trackers and clean up resources |
Note: When sending data using any method (
hit,externalLink,elementClick,formData,customEvent, etc.), you can temporarily extend the globalextraValuesorabParamsby passing them in the data object:
analytics.hit(window.location.href, {
exv: { extraKey_1: 'extraValue_1', extraKey_2: 'extraValue_2' },
abParams: { abKey_1: 'abValue_1', abKey_2: 'abValue_2' },
});Values passed this way will be added only to the current event and will not modify the global parameters set during initialization.
Example
analytics.hit(window.location.href);
analytics.externalLink('https://external.com');
analytics.elementClick('my-button');
analytics.formData('signup', { email: '[email protected]' });
analytics.customEvent('my-event', { foo: 1 });
analytics.setAbParams({ experiment: 'A' });
analytics.destroy();List of Event Types
| Type (et) | Symbolic Name | Where Used / How to Enable | Description |
| ------------------------ | ------------------------ | ------------------------------------- | ------------------------------------------------------------ |
| 1 | HIT | PageLoadTracker, NavigationTracker | Page view (pageview), SPA navigation |
| 2 | EXTERNAL_LINK | ExternalLinkTracker, externalLink() | Click on an external link (not from siteDomains) |
| 3 | ELEMENT_CLICK | ClickTracker, elementClick() | Click on element with data-analytics="true" or manual call |
| 4 | FORM_DATA | formData() | Form submission |
| 5 | CUSTOM_EVENT | customEvent() | Custom user event |
| 6 | LCP | PerformanceTracker, eventForLCP() | Largest Contentful Paint metric |
| 10 | SCROLL_TOP | ScrollTracker | Scroll to 10% of the page |
| 11 | SCROLL_MIDDLE | ScrollTracker | Scroll to 50% of the page |
| 12 | SCROLL_BOTTOM | ScrollTracker | Scroll to 90% of the page |
| paystation-user-sessions | paystation-user-sessions | payStationUserSession() | PayStation user session event |
See docs/event-types.md for details.
Trackers
Xsolla Metrika includes several built-in trackers. Enable them via config flags — except
ScrollContainerTracker, which is enabled by passing the scrollContainers option, not a
boolean:
| Tracker | Flag / Option | Description |
| ---------------------- | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| PageLoadTracker | hit | Tracks page load (pageview) |
| ClickTracker | click | Tracks clicks on [data-analytics="true"] elements |
| ExternalLinkTracker | extLink | Tracks clicks on external links |
| ScrollTracker | scroll | Tracks scroll depth (10%, 50%, 90%) |
| CrossDomainTracker | crossDomainTracking | Appends xsollauid and visitorId to links to allowed domains (anchors only, forms are not decorated), cleans URL after extraction |
| PerformanceTracker | sendLoadMetrics | Tracks web-vitals metrics (LCP) |
| NavigationTracker | navigation | Tracks SPA navigation (history API, hashchange) |
| ScrollContainerTracker | scrollContainers (array, not boolean) | Tracks scroll depth (10%, 50%, 90%) inside declared elements, independently of scroll |
See docs/trackers.md for details.
What Data Is Sent
Xsolla Metrika collects and sends only technical and anonymized data required for analytics and improving user experience.
No personal user data is collected or transmitted by default.
Example of the event data structure
{
"et": 1, // Event type (e.g., HIT, CLICK, etc.)
"library_version": "X.Y.Z", // Library version (injected at build time)
"counter_id": "YOUR_COUNTER_ID", // Your project counter ID
"dfp": "fingerprint_hash", // Device fingerprint
"xsollauid": "380884044985925701", // Xsolla user ID
"eid": 123456, // External ID (if there is)
"ident": {
"ntf": 1, // Notifications enabled (1/0)
"net": "4g", // Network type
"t": "Page Title", // Document title
"pc": "UTF-8", // Charset
"la": "en", // Language
"tz": -180, // Timezone offset (minutes)
"wcw": 1920, // Viewport width
"wch": 1080, // Viewport height
"sw": 1920, // Screen width
"sh": 1080, // Screen height
"j": 0, // Java enabled (1/0)
"c": 1, // Cookies enabled (1/0)
"sc": 24, // Color depth
"ifr": 0, // Is in iframe (1/0)
"adb": 0, // AdBlock detected (1/0); background check, the last known result until it settles
"gacid": "123456789.1234567890", // Google Analytics CID (if there is)
"clid": "1733820844784899640", // Client ID
"vid": "1747380405323933016", // Visitor ID,
"cts": 1709571234567, // Client timestamp (ms since epoch)
"plt": 356, // Page load time (ms),
"lcp": 567 // Largest Contentful Paint (ms)
// ...additional cookies (for example: yid, pv, cv, etc.)
},
"user_agent": "...", // User-Agent string
"browser_major": "125", // Browser major version
"browser_name": "Chrome", // Browser name
"title": "Page Title", // Document title
"utm": {
"utm_source": null,
"utm_medium": null,
"utm_campaign": null,
"utm_content": null,
"utm_term": null
},
"openstat": {
"openstat_service": null,
"openstat_campaign": null,
"openstat_ad": null,
"openstat_source": null
},
"url": "https://your.site/page", // Current page URL
"referer": "https://referrer.site/", // Referrer URL
"exv": {}, // Extra values (if there is)
"abParams": {} // A/B test params (if there is)
// ...event-specific fields (for example: value, en, form, metricData, etc.)
}TypeScript Support
- 100% typed API, no need for
@typespackages. - Works out of the box with TypeScript 5.8+.
- See docs/ts-support.md for troubleshooting and tips.
Migration from v1
- Async initialization: use
await XsollaAnalytics.init(...). - Device Fingerprinting has become more reliable.
- Events are sent via
sendBeaconby default, with fallback tofetch. - The method
dfpGethas been renamed togetFingerprintHash. - The method
keyDfpGethas been renamed togetFingerprintData. - Retry logic for failed fetch requests.
- See docs/migration/v1_v2.md for a full migration guide.
Browser Support
- All modern browsers (Chrome, Firefox, Edge, Safari, Opera, Samsung Internet, etc.)
- Chrome 80+, Safari 13.1+, Firefox 74+, Edge 80+, iOS Safari 13.4+, Samsung Internet 13+
- See docs/browser-support.md for the full list.
License
MIT © Xsolla
