Architecture
How the Service Worker + Loader architecture works, including data flow, fallback mechanism, and framework-specific integration guides.
🏗️ How It Works
Service Worker (SW)
- Intercepts every
navigaterequest - Extracts UTMs and click IDs from the URL
- Detects traffic source via 60+ platform rules
- Stores data in IndexedDB (30min TTL)
- Injects
digitalDatainto the HTML response
Loader (Client)
- Registers the SW on first load
- Receives
digitalDatafrom injected script - Exposes
TrafficCampaignAPI - Fires
trafficcampaign:readyevent - Fallback: captures params without SW
Data Flow
User clicks ad (utm_source=google&gclid=abc123)
│
▼
┌─────────────────────────────────────────────────┐
│ SERVICE WORKER (intercepts fetch → navigate) │
│ │
│ 1. Extract URL params → sanitize (xss lib) │
│ 2. Detect traffic: source, medium, channel │
│ 3. Detect campaign provider (Google Ads, etc) │
│ 4. Store in IndexedDB (30min TTL) │
│ 5. Inject <script> with digitalData into HTML │
└─────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ LOADER (runs in main thread) │
│ │
│ 1. Read injected digitalData │
│ 2. Expose window.__PRESERVED_DIGITALDATA__ │
│ 3. Expose window.TrafficCampaign API │
│ 4. Fire 'trafficcampaign:ready' event │
└─────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ YOUR APP │
│ │
│ TrafficCampaign.getDigitalData() │
│ TrafficCampaign.sendToGA('G-XXXXXXX') │
└─────────────────────────────────────────────────┘Fallback Mechanism
If the Service Worker is unavailable (first load, unsupported browser, private browsing), the Loader captures URL parameters directly from location.search and provides a basic digitalData object. The data source is indicated in window.__DIGITALDATA_SOURCE__ ("service-worker" or "fallback").
Service Worker Scope: The SW must be served from your domain root (
/service-worker.js) to intercept all navigation requests. If placed in a subdirectory, it will only capture pages under that path.🔧 Framework Guides
Next.js (App Router)
# Step 1: Copy SW cp node_modules/@impressio/sdk/dist/service-worker.js public/service-worker.js // Step 2: Import in layout.js import '@impressio/sdk';
Vite / React
// vite.config.js — Auto-copy SW on build import { defineConfig } from 'vite'; import { copyFileSync } from 'fs'; export default defineConfig({ plugins: [{ name: 'copy-impressio-sw', buildStart() { copyFileSync( 'node_modules/@impressio/sdk/dist/service-worker.js', 'public/service-worker.js' ); } }] });
Google Tag Manager
// Push digitalData to GTM dataLayer window.addEventListener('trafficcampaign:ready', (e) => { window.dataLayer = window.dataLayer || []; window.dataLayer.push({ event: 'impressio_campaign_detected', impressio_source: e.detail.trafficDetail.source, impressio_medium: e.detail.trafficDetail.medium, impressio_channel: e.detail.trafficDetail.channel }); });
SPA Note: In Single Page Applications, the SW only intercepts initial navigations. For soft navigations (client-side routing), use
TrafficCampaign.refresh() to re-query the SW, or rely on the initially captured data.