Skip to main content

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

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

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)
}
ParameterTypeRequiredDescription
catalogUrlstringYesCatalog API root URL
apiKeystringYesKaltura Session (KS) for authentication
retryConfigRetryConfigNoRetry/backoff settings
logLevelstringNoLog level ('debug', 'info', 'warn', 'error')
timeoutMsnumberNoRequest 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[]>

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[]>

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>

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

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

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

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

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

CatalogListResponse

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

Complete Example

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

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

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>
);
}

Next Steps