Skip to content

Browser ESM build (non-React)

The Browser ESM build is the recommended path for non-React applications. The bundle is self-contained - React, React DOM, and TanStack Query are baked in, so you do not need to load peer-dependency scripts separately. You import it dynamically as an ES module, which means no build step and no <script src> chain.

Prerequisites

RequirementDetails
CDN URLEnvironment-specific - obtain from your Commotion account manager.
App keyOrganization-level app key - obtain from your Commotion account manager.
Modern browserAny browser with dynamic ES module import() support (Chrome 63+, Firefox 67+, Safari 11.1+, Edge 79+).

Minimal example

<div id="copilot-container"></div>
<script type="module">
const COPILOT_CDN_URL = '<YOUR_CDN_URL>'; // env-specific
const APP_KEY = '<YOUR_APP_KEY>';
const { initializeCopilotSDK, CmtnCopilot } = await import(COPILOT_CDN_URL);
initializeCopilotSDK(APP_KEY, { environment: 'production' });
const instance = CmtnCopilot.init({
containerId: 'copilot-container',
mode: 'embed',
userId: 'user-123',
});
</script>

Step-by-step

  1. Obtain credentials.

    Your Commotion account manager provides two values: the env-specific CDN URL and your app key. None of these can be derived from public sources.

  2. Dynamically import the SDK.

    The bundle is published as an ES module. Load it with dynamic import():

    const { initializeCopilotSDK, CmtnCopilot } = await import(COPILOT_CDN_URL);

    No peer-dependency <script> tags are needed - the bundle ships its own React, React DOM, and TanStack Query.

  3. Initialize the SDK once per page.

    initializeCopilotSDK(APP_KEY, { environment: 'production' });

    environment is optional. See Initialization options for valid values.

  4. Mount the Copilot into a container.

    CmtnCopilot.init() is a static class method - it does not require an SDK instance object. Pass an options object with at minimum a containerId and a mode.

    const instance = CmtnCopilot.init({
    containerId: 'copilot-container',
    mode: 'embed',
    });
  5. Tear down when finished.

    Use the instance method, or the static helpers for multi-instance pages:

    instance.destroy(); // unmount this widget
    CmtnCopilot.destroy('copilot-container'); // unmount by container ID
    CmtnCopilot.destroyAll(); // unmount every active widget

Initialization options

initializeCopilotSDK(appKey, options?) is called once per page load. The options object is optional.

OptionTypeDefaultDescription
environmentstring'production'One of 'development', 'staging', 'production'.

CmtnCopilot.init() configuration

FieldTypeRequiredDefaultDescription
containerIdstringYes-DOM element ID where the widget mounts.
modestringYes-embed, preview, link_preview, or widget. See Modes.
userIdstringNoauto-generatedUnique identifier for the current user.
workerIdstringNo''ID of the worker the Copilot interacts with.
agentIdstringNo''ID of the AI agent (requires workerId).
typestringNo'worker''worker' or 'agent'.
versionnumber | nullNonullVersion of the worker / agent (internal use).
shadowDombooleanNotrueRender inside a shadow root to isolate styles.

See the full props reference for prop semantics shared with the React build.

Static and instance methods

const instance = CmtnCopilot.init({ /* config */ });
// Instance methods
instance.destroy(); // unmount this widget
instance.updateConfig({ mode: 'preview' }); // hot-update props on the existing instance
// Static methods (available without an instance)
CmtnCopilot.destroy('copilot-container'); // unmount by container ID
CmtnCopilot.destroyAll(); // unmount every active widget
CmtnCopilot.getActiveInstances(); // returns container IDs of active widgets
MethodKindDescription
instance.destroy()instanceUnmount this widget and clean up event listeners.
instance.updateConfig(partial)instanceHot-update one or more props on an existing instance.
CmtnCopilot.destroy(containerId)staticUnmount the widget bound to containerId.
CmtnCopilot.destroyAll()staticUnmount every active widget on the page.
CmtnCopilot.getActiveInstances()staticReturn the container IDs of all currently active widgets.

Lazy loading pattern

For pages where the Copilot only opens after a user action (for example, a floating chat button), defer the dynamic import() and initializeCopilotSDK() call until first use:

let sdkModule = null;
let sdkInitialized = false;
async function loadSDK() {
if (sdkModule) return sdkModule;
sdkModule = await import(COPILOT_CDN_URL);
return sdkModule;
}
async function ensureSDKInitialized() {
if (sdkInitialized) return;
const { initializeCopilotSDK } = await loadSDK();
initializeCopilotSDK(APP_KEY, { environment: 'production' });
sdkInitialized = true;
}
async function openCopilot() {
await ensureSDKInitialized();
const { CmtnCopilot } = await loadSDK();
return CmtnCopilot.init({
containerId: 'copilot-container',
mode: 'widget',
});
}

When to use Browser ESM

ScenarioUse Browser ESM?
Plain HTML, no build systemYes
jQuery or other non-React frameworksYes
WordPress, Shopify, or CMS-rendered pagesYes
Floating chat button with lazy initializationYes
Modern React 18+ applicationNo - use the React build
Environment without dynamic import() supportNo - use the UMD build