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.
| Layer | What it does |
|---|---|
| 1. HTML stripping | Removes all HTML tags (<script>, <img>, <svg>, etc) |
| 2. Control chars | Strips null bytes and ASCII control characters |
| 3. URI scheme blocking | Blocks javascript:, data:, vbscript: |
| 4. Event handlers | Blocks onerror=, onload=, ontoggle= |
| 5. Prototype pollution | Blocks __proto__, constructor, prototype keys |
| 6. JSON escape | Safe </script>, U+2028, & encoding for inline injection |
| 7. Input limits | Max 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
| Symptom | Cause | Fix |
|---|---|---|
__DIGITALDATA_SOURCE__ = "fallback" | SW not registered or first visit | Verify /service-worker.js returns 200. Revisit the page. |
| No UTM params captured | URL has no query params | Expected behavior for direct traffic. |
| SW scope too narrow | SW not at domain root | Move service-worker.js to / |
| Private browsing fails | Some browsers restrict SW in incognito | Fallback mode activates automatically. |
diagnose() shows errors | Various | Check 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.