or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

audio-processing.mdconversational-ai.mdhistory.mdindex.mdprojects-studio.mdstreaming.mdtext-to-speech.mdutilities.mdvoice-management.md
tile.json

projects-studio.mddocs/

Projects & Studio

Overview

The Projects & Studio API provides comprehensive tools for managing complex audio production workflows, including studio projects, chapter management, and Audio Native embeddable players. These features enable professional audiobook creation, long-form content production, and web-based audio experiences.

Core Imports

import { 
  ElevenLabsClient,
  type BodyCreateStudioProjectV1StudioProjectsPost,
  type BodyUpdateStudioProjectV1StudioProjectsPost,
  type BodyUpdateStudioProjectContentV1StudioProjectsProjectIdContentPost,
  type BodyCreatesAudioNativeEnabledProjectV1AudioNativePost,
  type BodyUpdateAudioNativeProjectContentV1AudioNativeProjectIdContentPost,
  type ProjectsAddRequestTargetAudience,
  type ProjectsAddRequestFiction,
  type ProjectsAddRequestSourceType
} from 'elevenlabs';

Studio Projects

Create Studio Project

const client = new ElevenLabsClient();

// Create a basic studio project
const project = await client.studio.projects.create({
  name: "My Audiobook Project",
  default_title_voice_id: "pNInz6obpgDQGcFmaJgB", // Voice for chapter titles
  default_paragraph_voice_id: "21m00Tcm4TlvDq8ikWAM", // Voice for content
  default_model_id: "eleven_multilingual_v2",
  quality_preset: "high", // standard, high, ultra, ultra lossless
  
  // Project metadata
  title: "The Great Adventure",
  author: "John Author",
  description: "An epic adventure story spanning multiple chapters",
  language: "en",
  content_type: "fiction",
  target_audience: "adult",
  genres: ["fantasy", "adventure", "fiction"],
  
  // Processing options
  auto_convert: true, // Automatically convert to audio
  volume_normalization: true, // Apply audiobook normalization
  apply_text_normalization: "auto"
});

console.log('Project created:', project.project_id);
console.log('Project status:', project.state);

Advanced Studio Project Configuration

import * as fs from 'fs';

// Create project from existing content
const advancedProject = await client.studio.projects.create({
  name: "Professional Audiobook Production",
  default_title_voice_id: "narrator_voice_id",
  default_paragraph_voice_id: "character_voice_id", 
  default_model_id: "eleven_multilingual_v2",
  
  // Initialize from document
  from_document: fs.createReadStream('manuscript.txt'),
  // OR from URL
  // from_url: "https://example.com/book-content.html",
  
  // High-quality production settings
  quality_preset: "ultra", // 50% credit increase but highest quality
  
  // Complete metadata
  title: "The Complete Guide to AI",
  author: "Dr. AI Expert", 
  description: "A comprehensive guide to artificial intelligence",
  isbn_number: "978-1234567890",
  original_publication_date: "2024-01-01",
  language: "en",
  content_type: "non-fiction",
  target_audience: "adult",
  genres: ["technology", "education", "reference"],
  mature_content: false,
  fiction: "non-fiction",
  
  // Advanced processing
  auto_convert: false, // Manual control over conversion
  auto_assign_voices: true, // AI voice assignment
  volume_normalization: true,
  apply_text_normalization: "on",
  
  // Pronunciation customization
  pronunciation_dictionary_locators: [
    JSON.stringify({
      pronunciation_dictionary_id: "dict_id_1",
      version_id: "version_1"
    })
  ],
  
  // Webhook notification
  callback_url: "https://your-app.com/webhooks/project-complete"
});

Project Management

// Get all projects
const projects = await client.studio.projects.getAll();

console.log(`Found ${projects.projects.length} projects`);

projects.projects.forEach(project => {
  console.log(`- ${project.name} (${project.project_id})`);
  console.log(`  Status: ${project.state}`);
  console.log(`  Quality: ${project.quality_preset}`);
  console.log(`  Created: ${new Date(project.create_date_unix * 1000).toLocaleDateString()}`);
});

// Get specific project details
const projectDetails = await client.studio.projects.get(project.project_id);

console.log('Project details:', {
  name: projectDetails.name,
  state: projectDetails.state,
  wordCount: projectDetails.word_count,
  chapterCount: projectDetails.chapters?.length,
  totalDuration: projectDetails.duration_seconds,
  progress: projectDetails.conversion_progress_percentage
});

Update Project

// Update project settings
const updatedProject = await client.studio.projects.update(
  project.project_id,
  {
    name: "Updated Project Name",
    title: "Updated Title",
    description: "Updated project description",
    quality_preset: "ultra", // Upgrade quality
    volume_normalization: true,
    
    // Update voice assignments
    default_title_voice_id: "new_narrator_voice_id",
    default_paragraph_voice_id: "new_character_voice_id"
  }
);

Update Project Content

// Replace project content
await client.studio.projects.updateContent(
  project.project_id,
  {
    content: `# Chapter 1: The Beginning
    
    It was a dark and stormy night when our hero first discovered the mysterious artifact.
    The rain pattered against the window as she examined the strange glowing object.
    
    # Chapter 2: The Journey
    
    With determination in her heart, she set off on the journey that would change everything.
    The path ahead was uncertain, but her resolve was unwavering.`,
    
    // Processing options
    auto_convert: true,
    apply_text_normalization: "auto"
  }
);

// OR update from file
await client.studio.projects.updateContent(
  project.project_id,
  {
    from_document: fs.createReadStream('updated_manuscript.txt'),
    auto_convert: true
  }
);

// OR update from URL
await client.studio.projects.updateContent(
  project.project_id,
  {
    from_url: "https://example.com/updated-content.html",
    auto_convert: false // Manual conversion control
  }
);

Chapter Management

List and Manage Chapters

// Get all chapters for a project
const chapters = await client.studio.chapters.getAll(project.project_id);

console.log(`Project has ${chapters.chapters.length} chapters`);

chapters.chapters.forEach((chapter, index) => {
  console.log(`Chapter ${index + 1}: ${chapter.name}`);
  console.log(`  State: ${chapter.state}`);
  console.log(`  Duration: ${chapter.audio_duration_seconds}s`);
  console.log(`  Word count: ${chapter.word_count}`);
});

Create Chapter

// Add a new chapter to the project
const newChapter = await client.studio.chapters.create(
  project.project_id,
  {
    name: "Chapter 5: The Revelation",
    content: `The truth was finally revealed in all its shocking detail.
      Everything they thought they knew was about to change forever.
      
      The ancient prophecy spoke of this moment, but none of them 
      had truly believed it would come to pass in their lifetime.`,
    
    // Chapter-specific voice settings
    voice_id: "dramatic_narrator_voice_id",
    model_id: "eleven_multilingual_v2",
    
    // Position in project
    chapter_index: 4 // Insert at position 5 (0-indexed)
  }
);

console.log('Chapter created:', newChapter.chapter_id);

Update Chapter

// Update chapter content and settings
const updatedChapter = await client.studio.chapters.update(
  project.project_id,
  newChapter.chapter_id,
  {
    name: "Chapter 5: The Great Revelation",
    content: `The truth was finally revealed in all its shocking, magnificent detail.
      Everything they thought they knew was about to change forever and ever.`,
    
    // Update voice for this chapter
    voice_id: "epic_narrator_voice_id",
    
    // Force regeneration
    regenerate_audio: true
  }
);

Chapter Audio Management

// Get chapter audio
const chapterAudio = await client.studio.chapters.getAudio(
  project.project_id,
  newChapter.chapter_id
);

// Save chapter audio
import { pipeline } from 'stream';
import { promisify } from 'util';

const pipelineAsync = promisify(pipeline);
await pipelineAsync(
  chapterAudio,
  fs.createWriteStream(`chapter_${newChapter.chapter_id}.mp3`)
);

// Delete chapter
await client.studio.chapters.delete(project.project_id, newChapter.chapter_id);
console.log('Chapter deleted');

Project Audio Generation

Convert Project to Audio

// Start audio conversion for entire project
await client.studio.projects.convertToAudio(project.project_id, {
  quality_preset: "high",
  volume_normalization: true,
  apply_text_normalization: "auto"
});

console.log('Audio conversion started');

Monitor Conversion Progress

// Monitor project conversion progress
async function monitorProjectConversion(projectId: string) {
  let isComplete = false;
  
  while (!isComplete) {
    const project = await client.studio.projects.get(projectId);
    
    console.log(`Conversion progress: ${project.conversion_progress_percentage}%`);
    console.log(`State: ${project.state}`);
    
    if (project.state === 'converted') {
      console.log('✓ Project conversion completed!');
      isComplete = true;
    } else if (project.state === 'conversion_failed') {
      console.log('✗ Project conversion failed');
      throw new Error('Conversion failed');
    } else {
      // Wait 30 seconds before checking again
      await new Promise(resolve => setTimeout(resolve, 30000));
    }
  }
}

// Usage
await monitorProjectConversion(project.project_id);

Download Project Audio

// Download complete project audio
const projectAudio = await client.studio.projects.getAudio(project.project_id);

await pipelineAsync(
  projectAudio,
  fs.createWriteStream(`${project.name}_complete.mp3`)
);

console.log('Project audio downloaded');

// Download individual chapters
const chapters = await client.studio.chapters.getAll(project.project_id);

for (let i = 0; i < chapters.chapters.length; i++) {
  const chapter = chapters.chapters[i];
  
  if (chapter.state === 'converted') {
    const chapterAudio = await client.studio.chapters.getAudio(
      project.project_id,
      chapter.chapter_id
    );
    
    const filename = `${chapter.name.replace(/\s+/g, '_')}.mp3`;
    await pipelineAsync(chapterAudio, fs.createWriteStream(filename));
    
    console.log(`Downloaded: ${filename}`);
  }
}

Audio Native Projects

Create Audio Native Project

// Create embeddable audio player project
const audioNativeProject = await client.audioNative.create({
  name: "Website Audio Content",
  
  // Content source
  text_content: `Welcome to our website! This audio content will be embedded 
    directly into your web pages, providing an interactive listening experience 
    for your visitors. They can play, pause, and navigate through the content 
    seamlessly.`,
  
  // Voice and model settings
  voice_id: "professional_web_voice_id",
  model_id: "eleven_multilingual_v2",
  
  // Auto-start conversion
  auto_convert: true,
  
  // Embedding options
  auto_play: false, // Don't auto-play on page load
  show_controls: true, // Show player controls
  background_color: "#ffffff",
  text_color: "#000000"
});

console.log('Audio Native project created:', audioNativeProject.project_id);
console.log('Embed code:', audioNativeProject.embed_html);

Advanced Audio Native Configuration

// Create Audio Native project with advanced settings
const advancedAudioNative = await client.audioNative.create({
  name: "Interactive Article Reader",
  
  // Rich content
  text_content: `# Article Title
  
  This is an interactive article that readers can listen to while following along 
  with the text. The audio player will highlight sections as they're spoken.
  
  ## Section 1: Introduction
  
  Here we introduce the main concepts...
  
  ## Section 2: Deep Dive
  
  Now we explore the details...`,
  
  // High-quality voice settings
  voice_id: "article_narrator_voice_id",
  model_id: "eleven_multilingual_v2",
  voice_settings: {
    stability: 0.7,
    similarity_boost: 0.8,
    style: 0.2,
    speed: 0.95 // Slightly slower for article reading
  },
  
  // Advanced player options
  auto_convert: true,
  auto_play: false,
  show_controls: true,
  enable_logging: false, // Privacy mode
  
  // Customization
  background_color: "#f8f9fa",
  text_color: "#212529",
  primary_color: "#007bff",
  
  // Behavior settings
  highlight_current_section: true,
  show_progress_bar: true,
  enable_speed_control: true,
  enable_download: false // Disable download option
});

Update Audio Native Content

// Update Audio Native project content
await client.audioNative.updateContent(
  audioNativeProject.project_id,
  {
    text_content: `# Updated Content
    
    This is the updated version of our audio content with new information 
    and improved sections for better user engagement.
    
    ## New Section: Additional Features
    
    We've added exciting new features based on user feedback...`,
    
    // Update settings
    voice_id: "updated_voice_id",
    auto_convert: true,
    
    // New customization
    background_color: "#f0f0f0",
    show_controls: true,
    enable_speed_control: true
  }
);

console.log('Audio Native content updated');

Project Types and Interfaces

Studio Project Interface

interface BodyCreateStudioProjectV1StudioProjectsPost {
  /** Project name for identification */
  name: string;
  
  /** Default voice for chapter titles */
  default_title_voice_id: string;
  
  /** Default voice for paragraph content */
  default_paragraph_voice_id: string;
  
  /** Model ID for audio generation */
  default_model_id: string;
  
  /** Content source options */
  from_url?: string; // Extract from URL
  from_document?: File | fs.ReadStream | Blob; // Upload document
  
  /** 
   * Output quality preset:
   * - "standard": 128kbps, 44.1kHz
   * - "high": 192kbps, 44.1kHz (+20% credits)
   * - "ultra": 192kbps, 44.1kHz, highest quality (+50% credits) 
   * - "ultra lossless": 705.6kbps, 44.1kHz, lossless (+100% credits)
   */
  quality_preset?: "standard" | "high" | "ultra" | "ultra lossless";
  
  /** Project metadata */
  title?: string;
  author?: string;
  description?: string;
  genres?: string[];
  target_audience?: "children" | "young_adult" | "adult";
  language?: string; // ISO 639-1 code
  content_type?: string;
  original_publication_date?: string; // YYYY-MM-DD or YYYY
  mature_content?: boolean;
  isbn_number?: string;
  fiction?: "fiction" | "non-fiction";
  
  /** Processing options */
  volume_normalization?: boolean;
  apply_text_normalization?: "auto" | "on" | "off" | "apply_english";
  auto_convert?: boolean;
  auto_assign_voices?: boolean;
  
  /** Pronunciation dictionaries */
  pronunciation_dictionary_locators?: string[];
  
  /** Webhook callback URL */
  callback_url?: string;
  
  /** Project source type */
  source_type?: string;
}

Audio Native Interface

interface BodyCreatesAudioNativeEnabledProjectV1AudioNativePost {
  /** Project name */
  name: string;
  
  /** Text content to convert */
  text_content?: string;
  
  /** Voice and model settings */
  voice_id?: string;
  model_id?: string;
  voice_settings?: VoiceSettings;
  
  /** Processing options */
  auto_convert?: boolean;
  enable_logging?: boolean;
  
  /** Player configuration */
  auto_play?: boolean;
  show_controls?: boolean;
  highlight_current_section?: boolean;
  show_progress_bar?: boolean;
  enable_speed_control?: boolean;
  enable_download?: boolean;
  
  /** Visual customization */
  background_color?: string;
  text_color?: string;
  primary_color?: string;
}

Advanced Workflows

Audiobook Production Pipeline

// Complete audiobook production workflow
async function createAudiobook(manuscriptPath: string) {
  console.log('Starting audiobook production...');
  
  // Step 1: Create project
  const project = await client.studio.projects.create({
    name: "Professional Audiobook",
    default_title_voice_id: "narrator_voice_id",
    default_paragraph_voice_id: "character_voice_id",
    default_model_id: "eleven_multilingual_v2",
    from_document: fs.createReadStream(manuscriptPath),
    quality_preset: "ultra",
    
    // Audiobook metadata
    title: "The Great Novel",
    author: "Famous Author",
    isbn_number: "978-1234567890",
    language: "en",
    content_type: "fiction",
    fiction: "fiction",
    
    // Production settings
    auto_convert: false, // Manual control
    volume_normalization: true,
    apply_text_normalization: "auto"
  });
  
  console.log('✓ Project created:', project.project_id);
  
  // Step 2: Wait for project initialization
  let projectReady = false;
  while (!projectReady) {
    const status = await client.studio.projects.get(project.project_id);
    if (status.state === 'ready' || status.state === 'converted') {
      projectReady = true;
    } else {
      await new Promise(resolve => setTimeout(resolve, 10000));
    }
  }
  
  // Step 3: Customize chapters
  const chapters = await client.studio.chapters.getAll(project.project_id);
  
  for (let i = 0; i < chapters.chapters.length; i++) {
    const chapter = chapters.chapters[i];
    
    // Assign different voices based on content
    let voiceId = "narrator_voice_id";
    if (chapter.name.toLowerCase().includes('dialogue')) {
      voiceId = "character_voice_id";
    } else if (chapter.name.toLowerCase().includes('action')) {
      voiceId = "action_narrator_voice_id";
    }
    
    await client.studio.chapters.update(
      project.project_id,
      chapter.chapter_id,
      {
        voice_id: voiceId,
        regenerate_audio: true
      }
    );
    
    console.log(`✓ Configured chapter: ${chapter.name}`);
  }
  
  // Step 4: Start conversion
  await client.studio.projects.convertToAudio(project.project_id, {
    quality_preset: "ultra",
    volume_normalization: true
  });
  
  console.log('✓ Audio conversion started');
  
  // Step 5: Monitor progress
  await monitorProjectConversion(project.project_id);
  
  // Step 6: Download final audiobook
  const projectAudio = await client.studio.projects.getAudio(project.project_id);
  const filename = 'complete_audiobook.mp3';
  
  await pipelineAsync(projectAudio, fs.createWriteStream(filename));
  console.log(`✓ Audiobook saved: ${filename}`);
  
  return project.project_id;
}

Web Content Audio Integration

// Create audio-enabled web content
async function createWebAudioContent(articles: Array<{title: string, content: string}>) {
  const audioProjects = [];
  
  for (const article of articles) {
    const audioProject = await client.audioNative.create({
      name: `Audio: ${article.title}`,
      text_content: `# ${article.title}\n\n${article.content}`,
      voice_id: "web_narrator_voice_id",
      model_id: "eleven_turbo_v2_5", // Faster for web content
      
      // Web-optimized settings
      auto_convert: true,
      auto_play: false,
      show_controls: true,
      enable_speed_control: true,
      highlight_current_section: true,
      
      // Brand colors
      background_color: "#ffffff",
      text_color: "#333333",
      primary_color: "#0066cc"
    });
    
    audioProjects.push({
      title: article.title,
      projectId: audioProject.project_id,
      embedCode: audioProject.embed_html
    });
    
    console.log(`✓ Created audio for: ${article.title}`);
  }
  
  // Generate HTML page with all audio content
  const htmlContent = `
<!DOCTYPE html>
<html>
<head>
  <title>Audio-Enhanced Articles</title>
  <style>
    .article { margin: 2rem 0; padding: 1rem; border: 1px solid #ddd; }
    .audio-player { margin: 1rem 0; }
  </style>
</head>
<body>
  <h1>Audio-Enhanced Content</h1>
  ${audioProjects.map(project => `
    <div class="article">
      <h2>${project.title}</h2>
      <div class="audio-player">
        ${project.embedCode}
      </div>
    </div>
  `).join('')}
</body>
</html>
  `;
  
  fs.writeFileSync('audio_articles.html', htmlContent);
  console.log('✓ HTML page generated: audio_articles.html');
  
  return audioProjects;
}

Project Management Best Practices

Batch Project Operations

// Manage multiple projects efficiently
class ProjectManager {
  private client: ElevenLabsClient;
  private projects: Map<string, any> = new Map();
  
  constructor(client: ElevenLabsClient) {
    this.client = client;
  }
  
  async createBatch(projectConfigs: any[]) {
    const results = [];
    
    for (const config of projectConfigs) {
      try {
        const project = await this.client.studio.projects.create(config);
        this.projects.set(project.project_id, project);
        results.push({ success: true, projectId: project.project_id });
      } catch (error) {
        results.push({ success: false, error: error.message });
      }
    }
    
    return results;
  }
  
  async monitorAllProjects() {
    const statuses = [];
    
    for (const [projectId] of this.projects) {
      try {
        const status = await this.client.studio.projects.get(projectId);
        statuses.push({
          projectId,
          name: status.name,
          state: status.state,
          progress: status.conversion_progress_percentage
        });
      } catch (error) {
        statuses.push({
          projectId,
          error: error.message
        });
      }
    }
    
    return statuses;
  }
  
  async downloadCompletedProjects() {
    const statuses = await this.monitorAllProjects();
    
    for (const status of statuses) {
      if (status.state === 'converted') {
        try {
          const audio = await this.client.studio.projects.getAudio(status.projectId);
          const filename = `${status.name.replace(/\s+/g, '_')}.mp3`;
          
          await pipelineAsync(audio, fs.createWriteStream(filename));
          console.log(`Downloaded: ${filename}`);
        } catch (error) {
          console.error(`Failed to download ${status.projectId}:`, error);
        }
      }
    }
  }
}

Error Handling

import { ElevenLabsError, ElevenLabsTimeoutError } from 'elevenlabs';

try {
  const project = await client.studio.projects.create({
    name: "Test Project",
    default_title_voice_id: "invalid_voice_id",
    default_paragraph_voice_id: "invalid_voice_id",
    default_model_id: "invalid_model_id"
  });
  
} catch (error) {
  if (error instanceof ElevenLabsError) {
    console.error('Project creation error:', error.statusCode);
    
    if (error.statusCode === 400) {
      console.error('Invalid parameters:', error.body);
    } else if (error.statusCode === 402) {
      console.error('Insufficient credits for project creation');
    } else if (error.statusCode === 422) {
      console.error('Validation error:', error.body);
    }
  }
}

// Robust project monitoring
async function robustProjectMonitoring(projectId: string, maxWaitTime = 3600000) { // 1 hour
  const startTime = Date.now();
  
  while (Date.now() - startTime < maxWaitTime) {
    try {
      const project = await client.studio.projects.get(projectId);
      
      if (project.state === 'converted') {
        return project;
      } else if (project.state === 'conversion_failed') {
        throw new Error(`Project conversion failed: ${project.error_message}`);
      }
      
      await new Promise(resolve => setTimeout(resolve, 30000));
      
    } catch (error) {
      console.error('Error checking project status:', error);
      await new Promise(resolve => setTimeout(resolve, 60000)); // Wait longer on error
    }
  }
  
  throw new Error('Project conversion timeout');
}

Best Practices

  1. Project Organization: Use descriptive names and metadata for easy project management
  2. Quality Settings: Choose quality preset based on final use (web vs. professional distribution)
  3. Voice Assignment: Use different voices for titles, narration, and dialogue
  4. Content Structure: Structure content with clear chapters and sections
  5. Monitoring: Always monitor long-running conversions with proper error handling
  6. Resource Management: Delete old projects to manage storage and costs
  7. Batch Operations: Process multiple projects efficiently with batch operations
  8. Audio Native: Optimize for web performance with appropriate voice models
  9. Metadata: Include comprehensive metadata for professional audiobook production
  10. Version Control: Keep track of project versions and content changes