Electron
Set up Human Behavior in an Electron desktop app.
Quickstart
Human Behavior runs inside Electron's renderer process — the same window that loads your HTML and JS. rrweb (the session recorder) needs a DOM, so the SDK cannot be initialized from the main process.
Renderer only. Don't require('humanbehavior-js') from main.js. Load it from your HTML (CDN or bundled) or from a renderer-side script file.
Step 1: Installation
Either install as a dependency and bundle it with your renderer, or drop the CDN bundle into your HTML.
npm install humanbehavior-js<script src="https://unpkg.com/humanbehavior-js@latest"></script>Step 2: Allow the ingestion endpoint in your CSP
Electron applies the Content-Security-Policy on every renderer. Human Behavior sends HTTP POSTs to https://ingest.humanbehavior.co (or your reverse proxy), so that origin must appear in connect-src. Without this, every request fails silently with Refused to connect.
const { app, BrowserWindow, session } = require('electron');
app.whenReady().then(() => {
session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
callback({
responseHeaders: {
...details.responseHeaders,
'Content-Security-Policy': [
"default-src 'self'; " +
"script-src 'self' 'unsafe-inline' https://unpkg.com; " +
"connect-src 'self' https://ingest.humanbehavior.co; " +
"img-src 'self' data: blob:; " +
"style-src 'self' 'unsafe-inline';"
],
},
});
});
const win = new BrowserWindow({
width: 1200,
height: 800,
webPreferences: { contextIsolation: true },
});
win.loadFile('renderer/index.html');
});If you're using a reverse proxy on your own domain, replace https://ingest.humanbehavior.co with that domain. If you run Human Behavior locally for development, add http://localhost:8000 (or your port) to connect-src.
Step 3: Initialize the tracker in the renderer
Bundled (npm)
import { HumanBehaviorTracker } from 'humanbehavior-js';
const tracker = HumanBehaviorTracker.init('your-api-key');CDN bundle
The UMD bundle exposes both window.HumanBehaviorTracker and a window.humanbehavior.init(apiKey, options) helper. The init signature is init(apiKey, options?) — any custom ingestionUrl goes inside options:
<script src="https://unpkg.com/humanbehavior-js@latest"></script>
<script>
const tracker = window.humanbehavior.init('your-api-key', {
ingestionUrl: 'https://ingest.humanbehavior.co',
});
</script>Known gotcha: passing logLevel: 'debug' in the options object currently throws TypeError: this.configureLogging is not a function inside the UMD bundle. If you need verbose logs, call window.HumanBehaviorTracker.configureLogging({ level: 'debug' }) before init() instead.
Step 4: Custom events and identify
Once initialized, use the instance returned by init():
tracker.customEvent('feature_opened', { feature: 'export' });
tracker.identifyUser({
userId: user.id,
userProperties: {
email: user.email,
name: user.name,
},
});That's it! Clicks, page views, console errors, and rage clicks are captured automatically across all renderer windows that initialize the SDK.
Multiple windows
Each BrowserWindow is a separate JS context, so each window that loads your renderer code gets its own tracker instance — same endUserId cookie when they share a session, distinct sessionIds per window. If a window doesn't load the SDK, its interactions simply aren't tracked.
Automating tests against your renderer
If you drive your Electron app from Playwright, Puppeteer, or Claude's browser tools, launch Electron with remote debugging enabled so the test harness can attach to the renderer:
electron . --remote-debugging-port=9222 --remote-allow-origins=*Then connect to http://localhost:9222 over the Chrome DevTools Protocol.
Troubleshooting
- Requests show as
blockedin DevTools → Network. Your CSP is missingconnect-srcfor the ingestion host. Addhttps://ingest.humanbehavior.co(or your proxy domain). TypeError: this.configureLogging is not a function. You passedlogLevelin the UMD init. CallHumanBehaviorTracker.configureLogging({ level: 'debug' })beforeinit()instead.- Nothing shows up in the dashboard. Confirm you're calling
initfrom the renderer, not the main process.typeof window === 'undefined'in the code path means you're in main. window.humanbehavior is undefined. The CDN script tag didn't load — check for aRefused to loadCSP error forscript-srcand addhttps://unpkg.com(or whatever host you pulled the bundle from).