Docs / Chrome Extension

Chrome extension setup

Chrome extensions cannot load Aizen's hosted tracker script directly. Instead, create a chrome_extension target, mint an events:write key, and send events from your bundled background service worker.

1. Create the target

  • Create a new target in Aizen and choose `Chrome extension`.
  • Add your extension name, timezone, and optional extension ID.
  • Create an `events:write` key from the target settings page.

2. Bundle local extension code

Add your Aizen host to host_permissions and ship the background worker inside the extension package.

{
  "manifest_version": 3,
  "name": "My Extension",
  "version": "1.0.0",
  "permissions": ["storage"],
  "host_permissions": ["https://your-aizen-app.com/*"],
  "background": {
    "service_worker": "background.js",
    "type": "module"
  }
}

3. Send events from the background worker

Use a stable anonymous install ID as client_id. In v1, Aizen uses that ID to keep visitor counts stable for extension traffic.

const API_URL = 'https://your-aizen-app.com/api/event'
const SITE_ID = 'your_site_id'
const WRITE_KEY = 'your_events_write_key'

async function getInstallId() {
  const { aizenInstallId } = await chrome.storage.local.get('aizenInstallId')
  if (aizenInstallId) return aizenInstallId

  const newId = crypto.randomUUID()
  await chrome.storage.local.set({ aizenInstallId: newId })
  return newId
}

export async function track(payload) {
  const clientId = await getInstallId()

  await fetch(API_URL, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${WRITE_KEY}`
    },
    body: JSON.stringify({
      site_id: SITE_ID,
      type: payload.type ?? 'event',
      name: payload.name,
      path: payload.path,
      platform: 'web',
      timestamp: Date.now(),
      client_id: clientId,
      context: payload.context ?? 'background',
      extension_id: chrome.runtime.id,
      props: payload.props
    })
  })
}

4. Track popup or option screens

Treat extension surfaces like screen paths such as /popup,/options, or /sidepanel.

chrome.runtime.sendMessage({
  type: 'track',
  payload: {
    type: 'pageview',
    path: '/popup',
    context: 'popup'
  }
})

Security notes

  • Write keys embedded in an extension are revocable identifiers, not true secrets.
  • Set the extension ID in Aizen once you know it to reject mismatched writes.
  • Use the regular public API docs for `stats:read` keys.