Loader

v1.1.0 · 649 LOC · The main-thread orchestrator that registers the Service Worker, provides the TrafficCampaign public API, manages fallback capture, and handles browser quirks — all as an auto-executing IIFE with zero global leaks.

Configuration

Configured via data-* attributes on the script tag:

<script src="node_modules/@impressio/sdk/dist/loader.js"
  data-debug="true"
  data-branding="true"
  data-sw-timeout="5000"
  data-max-retries="2"
></script>
AttributeTypeDefaultDescription
data-debugbooleanfalseEnable console logging ([TrafficCampaign] prefix)
data-brandingbooleantrueShow "NotSet Traffic Campaign Manager" in console
data-sw-timeoutnumber5000Max ms to wait for Service Worker response
data-max-retriesnumber2SW registration retry attempts before fallback

Capability Detection

The loader detects browser capabilities before deciding the loading strategy:

const capabilities = {
  serviceWorker:      'serviceWorker' in navigator,
  navigationPreload:  'navigationPreload' in ServiceWorkerRegistration.prototype,
  indexedDB:          'indexedDB' in window,
  localStorage:       !isPrivate  // Private mode detection
};

Initialization Flow

DOMContentLoaded (or immediate if DOM ready)
│
├─ Guard: already initialized? (__tg_initialized__)
├─ Setup message listener (once, guarded)
├─ Capture parameters immediately (fallback safety net)
│
├─ Register Service Worker
│   ├─ register('/service-worker.js', { scope: '/', updateViaCache: 'none' })
│   ├─ Enable Navigation Preload (if supported)
│   ├─ Wait for activation (10s timeout)
│   └─ Poll for controller (50ms intervals, 3s max)
│
├─ If SW registered + has params:
│   ├─ Ask SW to process current URL via MessageChannel
│   └─ If SW fails → use fallback data
│
└─ If SW failed + has params:
    └─ Use fallback data directly

Registration Resilience

The registration handles multiple failure scenarios gracefully:

Error TypeBehaviorRetries?
Denied / Blocked / SecurityErrorMark swBlocked, stop immediatelyNo
Registration RejectedStop immediatelyNo
404 Not FoundStop (file missing)No
Syntax ErrorStop (file corrupted)No
Transient / NetworkRetry after 1 secondYes (up to maxRetries)

Fallback Mode

When the Service Worker is unavailable (blocked, unsupported, or failed), the loader falls back to localStorage-based parameter capture:

// Captures current URL params immediately (before SW registration)
function captureParametersImmediately() {
  // Sanitize each key/value with sanitizeValue()
  // Store to localStorage as __tg_fallback__
  // Return params object
}

// Fallback digitalData shape:
{
  urlParams: { utm_source: "google", ... },
  referrer: "https://google.com",
  timestamp: 1711234567890,
  _fallback: true                    // ← Marker for fallback mode
}
Note: Fallback mode captures raw UTM parameters but does NOT classify traffic (no channel assignment, no macro resolution). The _fallback: true flag lets consumers detect this degraded mode.

Public API — TrafficCampaign

Exposed on window.TrafficCampaign as the main entry point:

MethodReturnsDescription
getDigitalData()object | nullGet current digitalData
isAvailable()booleanWhether digitalData is available
getTimestamp()number | nullWhen digitalData was captured
getSource()string | null'service-worker', 'service-worker-refresh', or 'fallback'
getParams()objectExtract just UTM params from digitalData
refresh()Promise<object>Re-fetch digitalData from SW IndexedDB
sendToGA(id)booleanSend attribution event to Google Analytics
diagnose()Promise<object>Full diagnostic report (console.table)
enableDebug()objectTurn on debug logging
disableDebug()objectTurn off debug logging
updateConfig(cfg)objectUpdate config + sync to SW
getConfig()objectGet current config copy

Usage Examples

// Wait for data to be ready
window.addEventListener('trafficcampaign:ready', (event) => {
  const data = event.detail;
  console.log(data.trafficDetail.channel);  // "Paid Search"
  console.log(data.trafficDetail.source);   // "google"
});

// Check if available (synchronous)
if (TrafficCampaign.isAvailable()) {
  const utms = TrafficCampaign.getParams();
  // { utm_source, utm_medium, utm_campaign, utm_content, utm_term }
}

// Send to Google Analytics
TrafficCampaign.sendToGA('G-XXXXXXX');

// Refresh from IndexedDB (async)
const freshData = await TrafficCampaign.refresh();

// Diagnose issues
const report = await TrafficCampaign.diagnose();
// Outputs: version, capabilities, browser, errors, SW health, digitalData

Event System

EventWhenDetail
trafficcampaign:readydigitalData available (any source)digitalData object

Error Handling

The loader suppresses its own unhandledrejection errors (blocked SW, denied permissions) via a targeted handler that only catches errors fromservice-worker.js or TrafficCampaign stack traces. Third-party errors pass through unaffected.