---
title: Catalog Service
url: https://docs.kaltura.com/docs/conversational-agents/agentic-avatars-sdk/client-sdk-catalog
---

## Catalog Service

Browse available visuals and voices programmatically using the Catalog Service.

### Overview

The `CatalogService` lets you query the Kaltura Avatar catalog to discover which visuals (avatar appearances) and voices are available for your account. Use it to build dynamic UI for visual/voice selection instead of hardcoding IDs.

> **When to Use**
>
> Use the Catalog Service when you want to:
>
> - Display a list of available avatars for the user to choose from
> - Show voice options with names and descriptions
> - Build a dynamic avatar selection UI with thumbnails

### Setup

```javascript
import { CatalogService } from '@unisphere/models-sdk-js';

const catalog = new CatalogService({
  catalogUrl: 'https://api.avatar.us.kaltura.ai/',
  apiKey: 'your-kaltura-session',
  logLevel: 'debug', // optional
});
```

#### Configuration

```typescript
interface CatalogServiceConfig {
  catalogUrl: string;        // Base URL for the catalog service
  apiKey: string;            // Kaltura Session (KS) for authentication
  retryConfig?: RetryConfig; // Optional retry configuration
  logLevel?: string;         // Optional log level
  timeoutMs?: number;        // Request timeout in ms (default: 10000)
}
```

| Parameter | Type | Required | Description |
|---|---|---|---|
| `catalogUrl` | string | Yes | Catalog API root URL |
| `apiKey` | string | Yes | Kaltura Session (KS) for authentication |
| `retryConfig` | RetryConfig | No | Retry/backoff settings |
| `logLevel` | string | No | Log level (`'debug'`, `'info'`, `'warn'`, `'error'`) |
| `timeoutMs` | number | No | Request timeout in milliseconds (default: 10000) |

> **Security**
>
> The Catalog Service requires a Kaltura Session. For production, call the catalog from your backend and send results to the frontend, or use a limited-privilege KS.

### Methods

#### `listVisuals(pager?, agentScope?)`

Fetch all available visual items (avatar appearances).

**Returns:** `Promise<CatalogItem[]>`

```javascript
const visuals = await catalog.listVisuals();

visuals.forEach((visual) => {
  console.log(visual.itemId);                    // e.g., 'visual-123'
  console.log(visual.attributes.visual?.name);   // e.g., 'Benjamin'
  console.log(visual.imageUrl);                  // thumbnail URL
});
```

---

#### `listVoices(pager?, agentScope?)`

Fetch all available voice items.

**Returns:** `Promise<CatalogItem[]>`

```javascript
const voices = await catalog.listVoices();

voices.forEach((voice) => {
  console.log(voice.itemId);                         // e.g., 'voice-456'
  console.log(voice.attributes.voice?.name);         // e.g., 'Sarah'
  console.log(voice.attributes.voice?.description);  // e.g., 'Warm, friendly tone'
  console.log(voice.attributes.voice?.language);     // e.g., 'en'
});
```

---

#### `listItems(filter?, pager?, agentScope?)`

Fetch catalog items with optional filtering. Use this for advanced queries.

**Returns:** `Promise<CatalogListResponse>`

```javascript
const result = await catalog.listItems(
  { typeEqual: 'Visual', adminTagsIn: ['premium'] },
  { offset: 0, limit: 20 },
);

console.log(result.totalCount);  // total matching items
console.log(result.objects);     // array of CatalogItem
```

### Types

#### `CatalogItem`

```typescript
type CatalogItemType = 'Visual' | 'Voice';

interface CatalogItem {
  type: CatalogItemType;
  itemId: string;
  presetVersion?: number;
  adminTags: string[];
  attributes: CatalogItemAttributes;
  imageUrl?: string;
  agentScope?: string;
  voiceSampleUrl?: string;
  createdBy: string;
  createdAt: string;
  updatedAt: string;
}
```

#### `CatalogItemAttributes`

```typescript
interface CatalogItemAttributes {
  visual?: CatalogVisualAttributes;
  voice?: CatalogVoiceAttributes;
}

type Background = 'Color' | 'Image';
type GenderPresentation = 'Masculine' | 'Feminine';
type SkinTone = 'MediumTan' | 'Light' | 'LightMedium';
type AgeGroup = 'YoungAdult' | 'OlderAdult';
type HairColor = 'Black' | 'Brown' | 'Blonde' | 'Red' | 'Gray';

interface CatalogVisualAttributes {
  background?: Background;
  name?: string;
  genderPresentation?: GenderPresentation;
  skinTone?: SkinTone;
  ageGroup?: AgeGroup;
  hairColor?: HairColor;
  hairStyle?: string[];
  clothing?: string[];
  glasses?: boolean;
}

interface CatalogVoiceAttributes {
  name?: string;
  description?: string;
  language?: string;
}
```

#### `CatalogListFilter`

```typescript
interface CatalogListFilter {
  typeEqual?: CatalogItemType;  // Filter by item type
  itemIdEqual?: string;         // Exact item ID match
  adminTagsIn?: string[];       // Filter by admin tags
  languageEqual?: string;       // Filter voices by language
}
```

#### `CatalogPager`

```typescript
interface CatalogPager {
  offset?: number;  // Starting index (default: 0)
  limit?: number;   // Max items to return (default: 100)
}
```

#### `CatalogListResponse`

```typescript
interface CatalogListResponse {
  objects: CatalogItem[];
  totalCount: number;
}
```

### Complete Example

Build a visual/voice picker that feeds into session creation:

```javascript
import { CatalogService, KalturaAvatarSession } from '@unisphere/models-sdk-js';

const API_KEY = 'your-kaltura-session';
const BASE_URL = 'https://api.avatar.us.kaltura.ai/';

// Step 1: Load catalog
const catalog = new CatalogService({
  catalogUrl: BASE_URL,
  apiKey: API_KEY,
});

const [visuals, voices] = await Promise.all([
  catalog.listVisuals(),
  catalog.listVoices(),
]);

console.log(`Available: ${visuals.length} visuals, ${voices.length} voices`);

// Step 2: Let user pick (or use programmatically)
const selectedVisual = visuals[0];
const selectedVoice = voices[0];

// Step 3: Create session with selected items
const session = new KalturaAvatarSession({
  apiKey: API_KEY,
  baseUrl: BASE_URL,
});

await session.createSession({
  visualId: selectedVisual.itemId,
  voiceId: selectedVoice.itemId,
  videoContainerId: 'avatar-container',
});

await session.sayText('Hello! I am your selected avatar.');
```

#### React Example

```tsx
import { useState, useEffect } from 'react';
import { CatalogService, CatalogItem } from '@unisphere/models-sdk-js';

function AvatarPicker({ apiKey, catalogUrl }: { apiKey: string; catalogUrl: string }) {
  const [visuals, setVisuals] = useState<CatalogItem[]>([]);
  const [voices, setVoices] = useState<CatalogItem[]>([]);

  useEffect(() => {
    const catalog = new CatalogService({ catalogUrl, apiKey });
    Promise.all([catalog.listVisuals(), catalog.listVoices()])
      .then(([v, vo]) => { setVisuals(v); setVoices(vo); });
  }, [apiKey, catalogUrl]);

  return (
    <div>
      <h3>Select Visual</h3>
      {visuals.map((v) => (
        <div key={v.itemId}>
          {v.imageUrl && <img src={v.imageUrl} width={64} height={64} />}
          <span>{v.attributes.visual?.name || v.itemId}</span>
        </div>
      ))}

      <h3>Select Voice</h3>
      {voices.map((v) => (
        <div key={v.itemId}>
          <span>{v.attributes.voice?.name || v.itemId}</span>
          {v.attributes.voice?.description && (
            <small> — {v.attributes.voice.description}</small>
          )}
        </div>
      ))}
    </div>
  );
}
```

### Related

- **[Catalog Service REST API](/docs/conversational-agents/conversational-agents/catalog-service)** — The server-side REST API for the same catalog: create, update, delete, and list catalog items directly via HTTP (Conversational Agents)

### Next Steps

- **[API Reference](./client-sdk-api-reference)** — Complete session method documentation
- **[Basic Usage](./client-sdk-basic-usage)** — Using `visualId` and `voiceId` in sessions
- **[Examples](./examples-simple-client-side)** — Full working examples
