Skip to content

Latest commit

 

History

History

README.md

Swetrix

NPM Package size JSDelivr hits Contributions welcome

Swetrix Tracking Script

Privacy-first, lightweight analytics tracking library for Swetrix. Tracks page views, custom events, errors, feature flags, and A/B experiments — all without cookies or invading user privacy.

Installation

npm / yarn / pnpm

npm install swetrix

CDN

<script src="https://swetrix.org/swetrix.js" defer></script>

Quick Start

ES Modules

import { init, trackViews, trackErrors } from 'swetrix'

init('YOUR_PROJECT_ID')
trackViews()
trackErrors()

CDN / Script Tag

<script src="https://swetrix.org/swetrix.js" defer></script>
<script>
  document.addEventListener('DOMContentLoaded', () => {
    swetrix.init('YOUR_PROJECT_ID')
    swetrix.trackViews()
    swetrix.trackErrors()
  })
</script>

API

init(projectId, options?)

Initialise the library. Must be called before any other method.

init('YOUR_PROJECT_ID', {
  apiURL: 'https://api.swetrix.com/log',
  devMode: false,
  disabled: false,
  respectDNT: false,
  profileId: 'user-123',
  preloadSessionReplay: false,
})
Option Description Default
apiURL API endpoint. Change this if you're self-hosting. 'https://api.swetrix.com/log'
devMode When true, localhost events are sent to the server. false
disabled When true, no data is sent. Useful for dev environments. false
respectDNT When true, disables tracking for users with Do Not Track enabled. false
profileId Profile ID for long-term user tracking (MAU/DAU). undefined
preloadSessionReplay Preload the session replay recorder after init(). Recording only starts after startSessionReplay(). undefined

trackViews(options?)

Automatically tracks page views, including navigation changes in SPAs. Returns a Promise<{ stop() }>.

const { stop } = await trackViews({
  hash: false,
  search: false,
  unique: false,
  heartbeatOnBackground: false,
  callback: undefined,
})

// Stop tracking when needed
stop()
Option Description Default
hash Track hash-based routing (e.g. /#/path). false
search Track search/query-based routing (e.g. /path?query). false
unique Only count unique page views per session. false
heartbeatOnBackground Send heartbeat when the tab is not active. false
callback A function to edit or prevent pageview payloads. Return false to block, true to send as-is, or return a modified payload object. undefined

track(event)

Track custom events (e.g. button clicks, sign-ups).

track({
  ev: 'signup',
  unique: true,
  meta: { plan: 'pro', source: 'landing' },
  profileId: 'user-123',
})
Option Description Default
ev Event name (max 256 chars). required
unique Only count once per session. false
meta Key-value metadata (max 20 keys, 1000 chars total). {}
profileId Optional profile ID. Overrides the global profileId for this event. undefined

trackErrors(options?)

Automatically captures client-side errors. Returns { stop() }.

const { stop } = trackErrors({
  sampleRate: 1,
  callback: undefined,
})
Option Description Default
sampleRate Fraction of errors to send (0 to 1). 1
callback Edit or prevent error payloads. Return false to block. undefined

trackError(payload)

Manually report an error.

trackError({
  name: 'PaymentError',
  message: 'Card declined',
  meta: { gateway: 'stripe' },
})

pageview(options)

Manually track a single page view (useful for custom routing).

pageview({
  payload: { pg: '/checkout', lc: 'en-US' },
  unique: true,
})

Feature Flags

// Get all flags. Results are cached for 5 minutes.
const flags = await getFeatureFlags({ profileId: 'user-123' })

// Force a fresh fetch
const freshFlags = await getFeatureFlags({ profileId: 'user-123' }, true)

// Get a single flag. The third argument is an optional fallback value.
const enabled = await getFeatureFlag('dark-mode', { profileId: 'user-123' })
const enabledWithFallback = await getFeatureFlag('dark-mode', { profileId: 'user-123' }, false)

// Clear the shared feature flag / experiment cache
clearFeatureFlagsCache()

A/B Experiments

// Get all running experiment assignments. Results are cached for 5 minutes.
const experiments = await getExperiments({ profileId: 'user-123' })

// Force a fresh fetch
const freshExperiments = await getExperiments({ profileId: 'user-123' }, true)

// Get a specific experiment variant. The third argument is an optional fallback variant.
const variant = await getExperiment('checkout-redesign-experiment-id', { profileId: 'user-123' })
const variantWithFallback = await getExperiment('checkout-redesign-experiment-id', { profileId: 'user-123' }, 'control')

// Clear the shared feature flag / experiment cache
clearExperimentsCache()

startSessionReplay(options?)

Start recording a session replay. Session replays use total privacy by default, which masks text and inputs and blocks media/canvas capture unless you explicitly choose another mode.

If you use the npm package, rrweb is dynamically imported from your installed dependencies only when the recorder is preloaded or started. If you use the CDN/script-tag build, the standalone replay recorder is loaded with an async script tag.

const replay = await startSessionReplay({
  privacy: 'total',
  maskAllText: true,
  sampleRate: 0.25,
  maxDurationMs: 10 * 60 * 1000,
  idleTimeoutMs: 2 * 60 * 1000,
  maxBytesPerChunk: 512 * 1024,
})

// Stop or flush manually when needed
await replay.flush()
await replay.stop()
Option Description Default
privacy Privacy mode: total, normal, or none. 'total'
maskAllText Mask all non-input text with asterisks. Defaults to true when privacy is total, otherwise false. privacy-based
sampleRate Fraction of sessions to record (0 to 1). 1
maxDurationMs Stop recording after this duration. undefined
idleTimeoutMs Stop recording after this much visitor inactivity. undefined
flushIntervalMs Upload buffered replay events at this interval. 5000
maxEventsPerChunk Upload once this many events are buffered. 100
maxBytesPerChunk Upload once buffered replay events reach this approximate byte size. 524288
maxBytesPerEvent Drop a single replay event if it is larger than this many bytes. 5242880
recordIframes Allow iframe elements to be captured. Iframes are blocked by default to reduce replay size and avoid recording embedded third-party content. false
rrweb Additional rrweb record options. undefined

To mask text while keeping media less restricted than total privacy, combine normal privacy with maskAllText:

await startSessionReplay({
  privacy: 'normal',
  maskAllText: true,
})

By default, Swetrix blocks iframe elements from replay snapshots. If you own the iframe content and need it in the replay, opt in explicitly:

await startSessionReplay({
  privacy: 'normal',
  recordIframes: true,
})

Cross-origin iframe recording also requires rrweb's cross-origin iframe support and should only be enabled for domains you control:

await startSessionReplay({
  recordIframes: true,
  rrweb: {
    recordCrossOriginIframes: true,
  },
})

Session & Profile IDs

const profileId = await getProfileId()
const sessionId = await getSessionId()

These are useful for revenue attribution with payment providers like Paddle.

Self-Hosting

If you're running a self-hosted Swetrix API instance, point the apiURL to your server:

init('YOUR_PROJECT_ID', {
  apiURL: 'https://your-api.example.com/log',
})

Documentation

Full reference and guides are available at docs.swetrix.com.

Contributing

Contributions are welcome — feel free to open an issue or submit a pull request.

License

MIT