Skip to main content
Content scripts run on web pages and capture session recordings and events. They communicate with the background script to send data to the Composite API.

Basic Setup

If you’re using a bundler with code splitting (Webpack, Rollup, Vite, etc.), use the /content-script entry point:
// content.js
import composite from '@composite-inc/composite-js/content-script';

(async () => {
  await composite.init({
    apiKey: 'pk_your_api_key',
    transport: 'chrome-extension',
    sessionRecording: true
  });
})();
Using a bundler with code splitting? Import from @composite-inc/composite-js/content-script instead of @composite-inc/composite-js. The /content-script entry point pre-bundles all extensions synchronously, avoiding ChunkLoadError issues caused by dynamic imports in content scripts. See Troubleshooting for details.

Without Code Splitting

If you’re using a bundler configured to inline all code (no code splitting), or using plain JavaScript without a bundler, you can use the standard import:
// content.js (only if NOT using code splitting)
import composite from '@composite-inc/composite-js';

(async () => {
  await composite.init({
    apiKey: 'pk_your_api_key',
    transport: 'chrome-extension',
    sessionRecording: true
  });
})();

With User Identification

Identify users to connect their sessions:
// content.js
import composite from '@composite-inc/composite-js/content-script';

(async () => {
  await composite.init({
    apiKey: 'pk_your_api_key',
    transport: 'chrome-extension',
    sessionRecording: true
  });

  // Identify user if available from storage
  const user = await getUserFromStorage();
  if (user) {
    composite.identify(user.id, {
      email: user.email,
      plan: user.plan
    });
  }
})();

async function getUserFromStorage() {
  return new Promise((resolve) => {
    chrome.storage.local.get(['user'], (result) => {
      resolve(result.user || null);
    });
  });
}

Advanced Configuration

// content.js
import composite from '@composite-inc/composite-js/content-script';

const compositeConfig = {
  apiKey: 'pk_your_api_key',
  transport: 'chrome-extension',
  sessionRecording: true,
  debug: process.env.NODE_ENV === 'development',

  // Custom transport configuration
  transportOptions: {
    flushInterval: 2000,     // Batch events every 2 seconds
    maxBatchSize: 50,        // Max events per batch
    retryLimit: 3,           // Retry failed requests
    timeout: 10000           // Request timeout
  }
};

(async () => {
  await composite.init(compositeConfig);
})();

Storage and Persistence

The SDK automatically uses Chrome’s storage API for persistence:
// User identification persists across sessions
composite.identify('user_123', {
  email: '[email protected]',
  subscription: 'premium'
});

// Reset on logout
document.getElementById('logout')?.addEventListener('click', () => {
  composite.reset();  // Clears user identity
});

What’s Next?