Security

The SDK implements 7 layers of XSS protection using a battle-tested sanitization library, plus GDPR-compliant data handling with automatic TTL expiration.

🛡️ XSS Protection (7 Layers)

All URL parameters and values are sanitized using the xss npm library (js-xss), a battle-tested SAX parser that runs without DOM — fully compatible with Service Workers.

LayerWhat it does
1. HTML strippingRemoves all HTML tags (<script>, <img>, <svg>, etc)
2. Control charsStrips null bytes and ASCII control characters
3. URI scheme blockingBlocks javascript:, data:, vbscript:
4. Event handlersBlocks onerror=, onload=, ontoggle=
5. Prototype pollutionBlocks __proto__, constructor, prototype keys
6. JSON escapeSafe </script>, U+2028, & encoding for inline injection
7. Input limitsMax 500 chars/param, max 50 params (anti-DoS)

🔒 GDPR Compliance

  • Click IDs = PII under GDPR Recital 30 (online identifiers). Handled accordingly.
  • IDB TTL: All stored data expires after 30 minutes of inactivity (storage limitation).
  • No external requests: The SDK never sends data to Impressio servers. All processing is local.
  • Data minimization: Only campaign-related params are captured; debug logs never expose full values.
Zero data exfiltration: The SDK performs 0 network requests. All processing happens in the user's browser — between the Service Worker and the main thread.

🔧 CSP Headers

/* Recommended Content-Security-Policy */
Content-Security-Policy:
  worker-src 'self';          /* Allow SW registration */
  script-src 'self' 'unsafe-inline';  /* For injected digitalData */
unsafe-inline note: The unsafe-inline directive is needed because the SW injects a <script> block with the digitalData object into the HTML response. We use safeJsonForScript() to prevent script context escapes.

🔍 Troubleshooting

SymptomCauseFix
__DIGITALDATA_SOURCE__ = "fallback"SW not registered or first visitVerify /service-worker.js returns 200. Revisit the page.
No UTM params capturedURL has no query paramsExpected behavior for direct traffic.
SW scope too narrowSW not at domain rootMove service-worker.js to /
Private browsing failsSome browsers restrict SW in incognitoFallback mode activates automatically.
diagnose() shows errorsVariousCheck diagnose().swStatus and .idbStatus

Debug Checklist

TrafficCampaign.enableDebug();     // Turn on console logging
const diag = await TrafficCampaign.diagnose();
console.table(diag);               // Full health check
console.log(window.__DIGITALDATA_SOURCE__);  // "service-worker" or "fallback"
Need help? Contact us at dev@getimpress.io or visit the documentation portal for more guides.