npm package: @sessioniq/client-sdk
Description: SessionIQ Client SDK allows you to record and interact with your users' sessions.
Author: SessionIQ
Latest version: 0.5.3

# SessionIQ Client SDK (`@sessioniq/client-sdk`)

[![npm version](https://badge.fury.io/js/%40sessioniq%2Fclient-sdk.svg)](https://badge.fury.io/js/%40sessioniq%2Fclient-sdk)

## Overview

The SessionIQ Client SDK is a lightweight JavaScript library for recording user sessions in your web application. It captures events, uploads them securely to the SessionIQ backend, facilitates triggering server-side analysis, allows adding textual context notes to specific sessions, and receives real-time updates about analysis progress and AI chat via a Supabase connection.

**Key Features:**

- **Easy Integration:** Simple API to initialize and control recording.
- **Session Recording:** Captures DOM changes, user interactions, console logs, network requests, and more (powered by `@sessioniq/core` internally).
- **Secure Upload:** Transmits recorded data securely to your configured SessionIQ backend using short-lived tokens.
- **Dynamic Loading:** Core recording logic is loaded dynamically only when needed, keeping the initial bundle size small.
- **Server-Side Analysis:** All heavy analysis, including AI processing, happens on the backend, not in the user's browser.
- **Real-time Updates:** Uses Supabase Realtime to receive analysis status updates and AI chat messages.
- **Chat Context Management:** Allows adding simple text notes (e.g., user observations) to a specific session ID via the `addChatContext` method. This context can then be used by the backend AI during chat interactions related to that session.
- **Event-Driven:** Provides hooks to listen for SDK events (initialization, recording status, errors, real-time updates).

## Installation

```bash
# Using npm (or pnpm or yarn)
npm install @sessioniq/client-sdk
```

## Basic Usage

Here's a simple example of how to initialize and use the SDK:

```typescript
import { SessionIQSdk } from "@sessioniq/client-sdk";

// 1. Create an instance
const sdk = new SessionIQSdk();

// 2. Initialize the SDK (asynchronously)
async function initialize() {
  try {
    await sdk.init({
      clientId: "YOUR_CLIENT_ID", // Replace with your actual Client ID
      baseUrl: "https://api.sessioniq.ai/api/v1", // Optional: Replace if self-hosting
      logLevel: "info", // Optional: Set desired log level
      userIdentifier: "user@example.com", // Optional: Identifier for the user (e.g., email)
      // autoStartRecording: true, // Optional: To start recording engine & agent snapshots automatically
    });
    console.log("SessionIQ SDK Initialized!");

    // 3. Add event listeners (optional)
    sdk.addListener("recording:started", (p) =>
      console.log(`Recording started. Checkpoint ID: ${p.checkpointId}`)
    );
    sdk.addListener("recording:stopped", (p) =>
      console.log(
        `Recording stopped. Checkpoint ID: ${p.checkpointId}, Events: ${p.eventCount}`
      )
    );
    sdk.addListener(
      "snapshotGenerated",
      (
        p // NEW EVENT
      ) =>
        console.log(
          `Snapshot for agent ${p.triggeringAgentId} generated with ${p.snapshotEvents.length} events.`
        )
    );
    sdk.addListener("error", (p) =>
      console.error(`SDK Error (${p.context}):`, p.error)
    );
    sdk.addListener("analysis:update", (payload) => {
      console.log("Received analysis update:", payload);
      // Handle analysis status updates (e.g., update UI)
    });
    sdk.addListener("chat:update", (payload) => {
      console.log("Received chat update:", payload);
      // Handle chat messages from AI
    });

    // 4. Subscribe to real-time updates (optional)
    // The listener callback provided here is an alternative to the 'analysis:update' and 'chat:update' events
    // sdk.subscribeToAnalysis((message) => {
    //   console.log("Realtime message:", message);
    // });
  } catch (error) {
    console.error("Failed to initialize SessionIQ SDK:", error);
  }
}

initialize();

// --- Example Usage (call these when needed, e.g., via button clicks) ---

// Start a manual recording checkpoint
// const checkpointId = await sdk.startCheckpoint({ // UPDATED METHOD
//   autoStopAfterMs: 30000, // Optional: Stop this checkpoint after 30 seconds
//   maxEvents: 1000,        // Optional: Stop this checkpoint after 1000 events
//   id: "my-custom-checkpoint-id", // Optional: Specify a custom ID
// });
// console.log("Started checkpoint with ID:", checkpointId);

// Stop the current manual recording checkpoint (automatically uploads events)
// sdk.stopCheckpoint(); // UPDATED METHOD

// Trigger analysis for the current session
// sdk.analyzeSession();

// Trigger analysis for a specific session
// sdk.analyzeSession("some_other_session_id");

// Send a chat message to an agent for the current session
// (Requires recording to be active to get current session ID)
// const currentSession = sdk.getCurrentSessionId();
// if (currentSession) {
//   sdk.sendChatMessage("agent:trace-pilot", "Can you explain this error?", "optional-thread-id-123");
// }

// Add a context note to a specific session
// sdk.addChatContext("some_session_id", { note: "User reported confusion here." });

// Get enabled agents (e.g., to populate a dropdown)
// const agents = sdk.getEnabledAgents();
// console.log("Enabled Agents:", agents);

// Remember to call destroy on cleanup
// sdk.destroy();
```

## Configuration

- `clientId` (Required): Your unique project identifier obtained from the SessionIQ dashboard.
- `baseUrl` (Optional): The base URL of your self-hosted or cloud SessionIQ API endpoint (e.g., `https://api.sessioniq.ai`). Defaults to `https://api.sessioniq.ai/api/v1`.
- `logLevel` (Optional): Sets the minimum log level ('debug', 'info', 'warn', 'error', 'silent'). Defaults to `'info'`.
- `userIdentifier` (Optional): An identifier for the user (e.g., email). This can be used by the backend to associate the session with a known user, potentially influencing chat token generation.
- `autoStartRecording` (Optional): If `true`, the core recording engine and agent snapshotting capabilities are started automatically after successful initialization. Defaults to `false`.

## Real-time Updates

The SDK utilizes a Supabase Realtime channel (configured automatically via the backend) to deliver asynchronous updates about session analysis progress and AI chat interactions. Use the `subscribeToAnalysis(callback)` method to listen for these updates. The callback function will receive a payload object. Check the `event` field within the payload (e.g., `'analysis_status'`, `'chat_updates'`) to determine the type of update and handle the specific `payload` structure accordingly. Listen locally for the `analysis:update` and `chat:update` events emitted by the SDK for easier handling.

## API Reference

- `new SessionIQSdk()`: Creates a new SDK instance.
- `async init(options: SdkInitOptions)`: Initializes the SDK, fetches configuration from the backend, and sets up the Supabase connection. If `options.autoStartRecording` is true, the core recording engine and agent snapshotting capabilities are started. Options include `clientId`, `baseUrl` (optional), `logLevel` (optional), `userIdentifier` (optional), and `autoStartRecording` (optional). Emits `init:success` or `init:error`.
- `async startCheckpoint(options?: { autoStopAfterMs?: number; maxEvents?: number; id?: string; }): Promise<string | void>`: Starts a manual recording checkpoint. Returns a Promise that resolves with the checkpoint ID (or void if an error occurs internally). Emits `recording:started`.
- `stopCheckpoint()`: Stops the currently active manual recording checkpoint and triggers background upload of captured events. Emits `recording:stopped` and potentially `events:upload:*` events.
- `async analyzeSession(sessionId?: string)`: Triggers the backend analysis for the specified session ID (or the current session if none is provided). Returns a confirmation message. Progress delivered via real-time updates (listened to via `subscribeToAnalysis` and emitted locally as `analysis:update`).
- `async sendChatMessage(agentId: string, message: string, threadId?: string)`: Sends a message to the specified agent for the **currently active recording session**. An optional `threadId` can be provided to group messages into a specific conversation thread. Requires an active session (`getCurrentSessionId()` must return an ID). Emits `chat:message:sent`. AI response is delivered via the real-time subscription (listened to via `subscribeToAnalysis` and emitted locally as `chat:update`).
- `async addChatContext(sessionId: string, context: SdkChatContextAddPayload)`: Adds a textual context note (and optional payload) to a **specific session ID** on the backend via an API call. Requires a valid Chat Token (fetched during init). The `context` object should conform to `SdkChatContextAddPayload` (typically `{ note?: string; payload?: any }`). Emits `chat:context:add`.
- `subscribeToAnalysis(callback: (message: { event: string, payload: any }) => void): RealtimeChannel | null`: Subscribes to the Supabase Realtime channel for broadcast events (`analysis_status`, `chat_updates`). Returns the channel instance or null. Use the SDK's `analysis:update` and `chat:update` events for easier handling. Emits `realtime:subscribed` or `realtime:error`.
- `unsubscribeFromAnalysis()`: Unsubscribes from the Supabase Realtime channel. Emits `realtime:unsubscribed`.
- `getCurrentSessionId(): string | null`: Returns the ID of the current active recording session, if any.
- `getEnabledAgents(): EnabledAgent[]`: Returns the list of agents configured and enabled for the project.
- `identifyUser(userId: string, details?: Record<string, any>)`: Associates a user ID and optional details with the current session. Records a custom event internally.
- `recordCustomEvent(name: string, payload?: any)`: Records a custom application event.
- `addListener(eventType: keyof SdkEventMap, listener)`: Adds a listener for local SDK events. See `SdkEventMap` below for the full list.
- `removeListener(eventType: keyof SdkEventMap, listener)`: Removes a listener for local SDK events.
- `destroy()`: Stops recording, unsubscribes from real-time updates, removes all listeners, and cleans up resources. **Important:** Call this when your application or relevant component unmounts to prevent memory leaks, especially in Single Page Applications (SPAs).

## Events (`SdkEventMap`)

Listen to these events using `sdk.addListener()`:

- `init:success`: SDK initialized successfully. Payload: `{ config: SdkConfigResponse }`.
- `init:error`: SDK initialization failed. Payload: `{ error: Error }`.
- `recording:started`: A manual recording checkpoint has started. Payload: `{ checkpointId: string }`.
- `recording:stopped`: A manual recording checkpoint has stopped. Payload: `{ checkpointId: string; eventCount: number }`.
- `snapshotGenerated`: An agent-triggered snapshot has been generated. Payload: `{ triggeringAgentId: string; triggeringEvent?: RRWebEventWithTime; snapshotEvents: RRWebEventWithTime[] }`.
- `checkpointCompleted`: A manual recording checkpoint is completed and its data is available. Payload: `{ checkpointId: string; events: RRWebEventWithTime[]; }`.
- `events:upload:start`: Event upload process initiated. Payload: `{ eventCount: number; uploadType: 'checkpoint' | 'snapshot' }`.
- `events:upload:success`: Events uploaded successfully. Payload: `{ uploadType: 'checkpoint' | 'snapshot' }`.
- `events:upload:error`: Event upload failed. Payload: `{ error: Error; uploadType: 'checkpoint' | 'snapshot'; context?: string }`.
- `realtime:subscribed`: Successfully subscribed to the Supabase channel. Payload: `{ channel: string }`.
- `realtime:error`: Error related to the Supabase channel subscription. Payload: `{ channel: string; status: string; error: Error }`.
- `realtime:unsubscribed`: Successfully unsubscribed from the Supabase channel. Payload: `{ channel: string }`.
- `analysis:update`: Received a real-time status update about analysis progress from the backend via Supabase. Payload structure depends on the specific status update sent by the backend (e.g., `{ status: 'starting' | 'agent_running' | 'agent_completed' | 'analyzed' | 'failed', sessionId: string, agentId?: string, message?: string, reports?: any[], error?: string }`).
- `chat:update`: Received a real-time chat-related update from the backend via Supabase (e.g., AI response, error). Payload structure depends on the specific update sent by the backend (e.g., `{ status: 'completed' | 'error', sessionId: string, agentId: string, threadId?: string, response?: string, error?: string }`).
- `chat:message:sent`: A chat message was successfully submitted to the API via `sendChatMessage`. Payload: `{ agentId: string; message: string; threadId?: string }`.
- `chat:context:add`: A chat context note was successfully submitted to the API via `addChatContext`. Payload: `{ note?: string; payload?: any }`.
- `tokens:refreshed`: SDK tokens have been successfully refreshed. Payload: `{ config: SdkConfigResponse }`.
- `tokens:refresh_error`: An error occurred while trying to refresh SDK tokens. Payload: `{ error: Error }`.
- `error`: A general SDK error occurred. Payload: `{ context: string; error: Error; [key: string]: any }`. Provide context indicates the operation that failed (e.g., 'startRecording', 'init').