Skip to content

Configuration ​

Trackkit can be configured via:

  • Programmatic options (recommended, most flexible)
  • Environment variables (build-time)
  • Runtime injection (e.g. HTML template / CDN)

Runtime and programmatic config always win over build-time env.

Resolution & precedence ​

When resolving a key like PROVIDER, Trackkit looks in this order:

  1. Programmatic options

    Whatever you pass to createAnalytics(opts) / init(opts) is the top source of truth.

  2. Runtime injection

    • window.__TRACKKIT_ENV__, e.g. { PROVIDER: "umami" }
    • <meta name="TRACKKIT_PROVIDER" content="umami">
  3. Build-time env (suffix after TRACKKIT_)

    • TRACKKIT_PROVIDER
    • VITE_TRACKKIT_PROVIDER
    • REACT_APP_TRACKKIT_PROVIDER

Keys in window.__TRACKKIT_ENV__ should be UPPERCASE and match the suffix after TRACKKIT_ (e.g. PROVIDER, SITE, HOST, QUEUE_SIZE).

Common keys (env + runtime injection) ​

These keys can be supplied via:

  • window.__TRACKKIT_ENV__
  • <meta name="TRACKKIT_*">
  • TRACKKIT_* / VITE_TRACKKIT_* / REACT_APP_TRACKKIT_* env variables

They map onto the corresponding TypeScript options on the facade.

KeyTypeDescriptionDefault (effective)
PROVIDERJSONAnalytics provider options (configuration for umami, plausible, ga4, or noop)see Provider defaults
QUEUE_SIZEnumberMax in-memory facade queue size50
DEBUGboolean (true/false/1/0)Verbose debug loggingfalse
AUTO_TRACKbooleanEnable SPA navigation autotrackingtrue
DO_NOT_TRACKbooleanRespect browser’s DNT (set false to ignore)true
TRACK_LOCALHOSTbooleanSend events from localhosttrue (may be overridden by provider metadata)
INCLUDE_HASHbooleanInclude #hash in URLsfalse
DOMAINSstring / JSONAllowed hostnames, e.g. "app.example.com,www.example.com" or ["app.example.com"]allow all
EXCLUDEstring / JSONURL substrings to exclude, e.g. "/admin,/debug" or ["/admin"]none
TRANSPORTstringTransport hint ('auto', 'fetch', 'beacon')'auto'
BATCHINGJSON
CONSENTJSONInitial consent policy (see below)see Consent defaults
CONNECTIONJSON

A few important details:

  • DOMAINS / EXCLUDE are only applied for pageview events (via the PolicyGate).
  • BATCH_SIZE / BATCH_TIMEOUT now back real batching behaviour; they are not reserved knobs.
  • TRACK_LOCALHOST can still be influenced by provider metadata (e.g. a provider that never tracks localhost even if you ask).

Build tool prefixes ​

  • Vite: VITE_TRACKKIT_*
  • Create React App: REACT_APP_TRACKKIT_*
  • Generic/Node: TRACKKIT_*

For Next.js, prefer runtime injection or a custom config loader; the current env reader does not treat NEXT_PUBLIC_* specially.

Runtime injection ​

Inject config at runtime (e.g. in HTML served by your app or via your CDN):

html
<script>
  window.__TRACKKIT_ENV__ = {
    PROVIDER: "umami",
    SITE: "your-site-id",
    HOST: "https://analytics.example.com",
    DEBUG: "true",
    AUTO_TRACK: "true",
    QUEUE_SIZE: "100"
  };
</script>

You can also use meta tags for simple keys:

html
<meta name="TRACKKIT_PROVIDER" content="plausible">
<meta name="TRACKKIT_SITE" content="site-123">
<meta name="TRACKKIT_HOST" content="https://plausible.example.com">

String values like "true" / "false" / "1" / "0" are parsed to booleans where appropriate.

Programmatic config is the “source of truth” and always wins over env/runtime injection.

ts
import { createAnalytics } from 'trackkit';

const analytics = createAnalytics({
  provider: {
    name: 'plausible',
    site: 'site-123',
    host: 'https://plausible.example.com',
  },
  debug: true,
  autoTrack: true,
  queueSize: 50,
});

You can still use the singleton API if you prefer:

ts
import { init } from 'trackkit';

init({
  provider: {
    name: 'umami',
    site: 'abc-123',
    host: 'https://analytics.example.com',
  },
});

Both APIs flow through the same normalisation / validation path.

Unified Identifier (site) Trackkit accepts a generic site field as a provider-agnostic identifier. When used, it is mapped automatically:

  • Umami → website
  • Plausible → site
  • GA4 → measurementId

Provider-specific identifiers (website, measurementId, etc.) can still be supplied directly and will override the generic mapping. This enables painless provider switching without rewriting configuration.

Advanced programmatic options ​

Some options are only expected to be set programmatically (not via env):

  • dispatcher.resilience.retry
  • dispatcher.resilience (adblocker detection, fallback strategy, proxy)
  • dispatcher.connection
  • dispatcher.performance
  • detailed consent configuration

The dispatcher-related options above live under the dispatcher key in AnalyticsOptions, while detailed consent configuration is defined at the top level of AnalyticsOptions. The shapes are defined in TypeScript; use your editor's IntelliSense (or the source files) as the canonical reference.

Retry ​

Controls backoff and retry for network dispatch. Retry options are nested under dispatcher.resilience.retry.

Defaults (from RETRY_DEFAULTS):

ts
retry: {
  maxAttempts: 3,
  initialDelay: 1000,
  maxDelay: 30000,
  multiplier: 2,
  jitter: true,
  retryableStatuses: [408, 429, 500, 502, 503, 504],
}

Override with:

ts
const analytics = createAnalytics({
  // ...
  dispatcher: {
    resilience: {
      retry: {
        maxAttempts: 5,
        initialDelay: 500,
        maxDelay: 60000,
      },
    },
  },
});

Resilience & transports ​

Controls adblocker detection and transport fallback. These options live under dispatcher.resilience.

Defaults (from RESILIENCE_DEFAULTS):

ts
resilience: {
  detectBlockers: false,
  fallbackStrategy: 'proxy', // 'proxy' | 'beacon'
  proxy: undefined,
  retry: { /* see above */ },
}

Example with a first-party proxy:

ts
const analytics = createAnalytics({
  // ...
  dispatcher: {
    resilience: {
      detectBlockers: true,
      fallbackStrategy: 'proxy',
      proxy: {
        proxyUrl: '/api/trackkit-proxy',
        token: process.env.TRACKKIT_PROXY_TOKEN,
        headers: { 'X-Trackkit-Source': 'web' },
      },
    },
  },
});

See docs/guides/resilience-and-transports.md for the full story.

Connection & offline ​

Controls how Trackkit interprets connection health and, if you wire it, how you use offline storage. These options live under dispatcher.connection.

Defaults (from CONNECTION_DEFAULTS):

ts
connection: {
  monitor: false,
  offlineStorage: false,
  syncInterval: 30000, // ms
  slowThreshold: 3000, // ms
  checkInterval: 30000, // ms
}

Example:

ts
const analytics = createAnalytics({
  // ...
  dispatcher: {
    connection: {
      monitor: true,
      offlineStorage: true,
      syncInterval: 15000,
      slowThreshold: 5000,
    },
  },
});

The actual connection state / offline behaviour is driven by ConnectionMonitor and OfflineStore; see docs/guides/connection-and-offline.md.

Performance tracking ​

Controls the lightweight PerformanceTracker. These options live under dispatcher.performance.

Defaults (from PERFORMANCE_DEFAULTS):

ts
performance: {
  enabled: false,
  // other fields may exist; see PerformanceOptions in the source
}

Example:

ts
const analytics = createAnalytics({
  // ...
  dispatcher: {
    performance: {
      enabled: true,
    },
  },
});

When enabled and wired in, basic metrics (init time, average processing time, average network latency) become visible via getDiagnostics(). See docs/guides/performance-tracking.md for details.

The consent system has its own defaults (from CONSENT_DEFAULTS):

ts
consent: {
  initialStatus: 'pending',
  requireExplicit: true,
  allowEssentialOnDenied: false,
  disablePersistence: false,
  storageKey: '__trackkit_consent__',
}

You can override any of these:

ts
const analytics = createAnalytics({
  // ...
  consent: {
    initialStatus: 'denied',
    requireExplicit: true,
    allowEssentialOnDenied: true,
    storageKey: '__myapp_consent__',
  },
});

If you prefer a coarse env-driven approach, you can use a CONSENT JSON env value:

sh
TRACKKIT_CONSENT={"initialStatus":"denied","requireExplicit":true}

Programmatic consent config always wins over env.

Provider-specific notes ​

Umami ​

  • Required: site (or website)
  • Optional: host (TRACKKIT_HOST or host option). Defaults to https://api.umami.is.

Example:

sh
TRACKKIT_PROVIDER=umami
TRACKKIT_SITE=abc-123
TRACKKIT_HOST=https://umami.example.com

Plausible ​

  • Required: site
  • Optional: host. Defaults to https://plausible.io.

Example:

sh
TRACKKIT_PROVIDER=plausible
TRACKKIT_SITE=mydomain.com
TRACKKIT_HOST=https://plausible.example.com

GA4 ​

  • Required: site (or measurementId) inside the provider object.
  • Host defaults to GA's standard endpoints.

Example:

sh
TRACKKIT_PROVIDER=ga4
TRACKKIT_SITE=G-XXXXXXX

Programmatic:

ts
createAnalytics({
  provider: { name: 'ga4', site: 'G-XXXXXXX' },
});

Error handling ​

Trackkit surfaces typed errors via AnalyticsError with codes like:

  • INIT_FAILED
  • PROVIDER_ERROR
  • NETWORK_ERROR
  • QUEUE_OVERFLOW
  • INVALID_CONFIG
  • INVALID_ENVIRONMENT
  • CONSENT_REQUIRED
  • POLICY_BLOCKED
  • READY_TIMEOUT
  • TIMEOUT
  • UNKNOWN

You can supply a custom handler:

ts
import { createAnalytics } from 'trackkit';

const analytics = createAnalytics({
  onError: (error) => {
    // error is an AnalyticsError
    console.error('[analytics]', error.code, error.message, {
      provider: error.provider,
      timestamp: error.timestamp,
    });
    // e.g. forward to Sentry / Datadog here
  },
});

If you don’t provide onError, Trackkit logs deduplicated errors via its internal logger.

Debug mode ​

Enable detailed logs:

ts
createAnalytics({ debug: true });
// or via env
TRACKKIT_DEBUG=true

Debug mode controls:

  • verbose queue / consent / navigation logs,
  • diagnostics output where enabled,
  • provider lifecycle traces.

Use debug: true in development and staging; keep it false in production unless you’re actively investigating an issue.

Released under the MIT License.