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>
| Attribute | Type | Default | Description |
|---|---|---|---|
data-debug | boolean | false | Enable console logging ([TrafficCampaign] prefix) |
data-branding | boolean | true | Show "NotSet Traffic Campaign Manager" in console |
data-sw-timeout | number | 5000 | Max ms to wait for Service Worker response |
data-max-retries | number | 2 | SW 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 directlyRegistration Resilience
The registration handles multiple failure scenarios gracefully:
| Error Type | Behavior | Retries? |
|---|---|---|
| Denied / Blocked / SecurityError | Mark swBlocked, stop immediately | No |
| Registration Rejected | Stop immediately | No |
| 404 Not Found | Stop (file missing) | No |
| Syntax Error | Stop (file corrupted) | No |
| Transient / Network | Retry after 1 second | Yes (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
}_fallback: true flag lets consumers detect this degraded mode.Public API — TrafficCampaign
Exposed on window.TrafficCampaign as the main entry point:
| Method | Returns | Description |
|---|---|---|
getDigitalData() | object | null | Get current digitalData |
isAvailable() | boolean | Whether digitalData is available |
getTimestamp() | number | null | When digitalData was captured |
getSource() | string | null | 'service-worker', 'service-worker-refresh', or 'fallback' |
getParams() | object | Extract just UTM params from digitalData |
refresh() | Promise<object> | Re-fetch digitalData from SW IndexedDB |
sendToGA(id) | boolean | Send attribution event to Google Analytics |
diagnose() | Promise<object> | Full diagnostic report (console.table) |
enableDebug() | object | Turn on debug logging |
disableDebug() | object | Turn off debug logging |
updateConfig(cfg) | object | Update config + sync to SW |
getConfig() | object | Get 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, digitalDataEvent System
| Event | When | Detail |
|---|---|---|
trafficcampaign:ready | digitalData 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.