npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

speech-provider

v0.2.1

Published

A unified interface for browser speech synthesis and Eleven Labs voices

Readme

speech-provider

A unified interface for browser speech synthesis and Eleven Labs voices.

Installation

# Using npm
npm install speech-provider

# Using yarn
yarn add speech-provider

# Using bun
bun add speech-provider

Documentation

Full API documentation is available at https://osteele.github.io/speech-provider/.

Usage

import { getVoiceProvider } from 'speech-provider';

// Use browser voices only
const provider = getVoiceProvider({});

// Use Eleven Labs voices if API key is available
const provider = getVoiceProvider({ elevenLabsApiKey: 'your-api-key' });

// Use Eleven Labs with custom cache duration
const provider = getVoiceProvider({
  elevenLabsApiKey: 'your-api-key',
  cacheMaxAge: 86400 // Cache for 1 day
});

// Use Eleven Labs with volume normalization
const provider = getVoiceProvider({
  elevenLabsApiKey: 'your-api-key',
  normalizeVolume: true // Enable volume normalization
});

// Get voices for a specific language
const voices = await provider.getVoices({ lang: 'en-US', minVoices: 1 });

// Explicitly fall back to unrelated voices when no language match exists
const fallbackVoices = await provider.getVoices({
  lang: 'en-US',
  minVoices: 1,
  fallbackToAnyLanguage: true
});

// Get default voice for a language
const defaultVoice = await provider.getDefaultVoice({ lang: 'en-US' });

// Create and play an utterance
if (defaultVoice) {
  const utterance = defaultVoice.createUtterance('Hello, world!');
  utterance.onstart = () => console.log('Started speaking');
  utterance.onend = () => console.log('Finished speaking');
  utterance.onerror = error => console.error(error);
  await utterance.start();
}

Features

  • Unified interface for both browser speech synthesis and Eleven Labs voices
  • Automatic fallback to browser voices when Eleven Labs API key is not provided
  • Typesafe API with TypeScript support
  • Simple voice selection by language
  • Event listeners for speech start, end, and error events
  • Cancellable Eleven Labs requests and playback
  • Efficient caching of Eleven Labs API responses using the browser's Cache API
  • Configurable cache duration for Eleven Labs responses
  • Audio volume normalization for Eleven Labs voices to ensure consistent volume levels

Used In

This package is used in Mandarin Sentence Practice, a web application for practicing Mandarin Chinese with listening and translation exercises. The app uses this package to provide high-quality text-to-speech for Mandarin sentences, with automatic fallback to browser voices when Eleven Labs is not available.

Examples

The package includes an interactive example in the examples directory that demonstrates both browser and Eleven Labs voice providers. To run it:

  1. View the live demo, or
  2. Open examples/demo.html directly in a browser, or
  3. Run bunx serve examples and open http://localhost:3000/demo.html

The example includes:

  • Session-only API key management for Eleven Labs
  • Provider selection (Browser/Eleven Labs)
  • Language selection with system language detection
  • Voice selection with descriptions
  • Example sentences in multiple languages
  • Text-to-speech controls
  • Volume normalization for Eleven Labs voices

API

getVoiceProvider(options)

Creates a voice provider based on the available API keys. Falls back to browser speech synthesis if no API keys are provided.

function getVoiceProvider(options: {
  elevenLabsApiKey?: string | null;
  cacheMaxAge?: number | null; // Cache duration in seconds (default: 1 hour). Set to null to disable caching.
  normalizeVolume?: boolean; // Enable volume normalization for Eleven Labs voices (default: false)
}): VoiceProvider;

createElevenLabsVoiceProvider(apiKey, options?)

Creates an Eleven Labs voice provider with optional configuration.

function createElevenLabsVoiceProvider(
  apiKey: string,
  baseUrl?: string,
  options?: {
    printVoiceProperties?: boolean;
    cacheMaxAge?: number | null; // Cache duration in seconds (default: 1 hour). Set to null to disable caching.
    normalizeVolume?: boolean; // Enable volume normalization for more consistent audio levels (default: false)
  }
): VoiceProvider;

Caching

The library implements efficient caching for Eleven Labs API responses using the browser's Cache API:

  • Browser voices are cached automatically by the browser's speech synthesis engine
  • Eleven Labs responses are cached using the browser's Cache API with a default duration of 1 hour
  • Cache duration can be configured when creating the provider
  • Cached responses are automatically invalidated after the specified duration
  • Cache keys use SHA-256 fingerprints and do not store raw API keys or utterance text
  • Cache can be disabled by setting cacheMaxAge: null in the provider options
  • The Cache API provides better performance than IndexedDB for network requests

Examples of cache configuration:

// Use default 1-hour cache
const provider = getVoiceProvider({ elevenLabsApiKey: 'your-api-key' });

// Cache for 1 day
const provider = getVoiceProvider({
  elevenLabsApiKey: 'your-api-key',
  cacheMaxAge: 86400 // 24 hours in seconds
});

// Cache for 1 week
const provider = getVoiceProvider({
  elevenLabsApiKey: 'your-api-key',
  cacheMaxAge: 604800 // 7 days in seconds
});

// Disable caching (preferred approach)
const provider = getVoiceProvider({
  elevenLabsApiKey: 'your-api-key',
  cacheMaxAge: null
});

// Alternative way to disable caching
const provider = getVoiceProvider({
  elevenLabsApiKey: 'your-api-key',
  cacheMaxAge: 0
});

Language matching

Language tags are matched using BCP-47 primary languages, so regional variants such as en-US and en-GB can match when an exact regional voice is not available. Unrelated voices are excluded by default. Set fallbackToAnyLanguage: true to request the previous cross-language fallback behavior when fewer than minVoices matches are available.

Volume Normalization

The library includes a volume normalization feature for Eleven Labs voices to ensure consistent audio levels:

  • Automatically normalizes audio volume during playback using the Web Audio API
  • Helps maintain consistent volume levels across different voices and utterances
  • Uses a dynamics compressor to balance loud and quiet sections of audio
  • Can be enabled by setting normalizeVolume: true in the provider options

Examples of volume normalization configuration:

// Enable volume normalization
const provider = getVoiceProvider({
  elevenLabsApiKey: 'your-api-key',
  normalizeVolume: true
});

// Enable volume normalization with custom cache settings
const provider = getVoiceProvider({
  elevenLabsApiKey: 'your-api-key',
  normalizeVolume: true,
  cacheMaxAge: 86400 // 24 hours in seconds
});

// Direct use with ElevenLabsVoiceProvider
const provider = createElevenLabsVoiceProvider('your-api-key', undefined, {
  normalizeVolume: true
});

VoiceProvider Interface

interface VoiceProvider {
  name: string;
  getVoices(options: {
    lang: string;
    minVoices: number;
    fallbackToAnyLanguage?: boolean;
  }): Promise<Voice[]>;
  getDefaultVoice({ lang }: { lang: string }): Promise<Voice | null>;
}

Voice Interface

interface Voice {
  name: string;
  id: string;
  lang: string;
  provider: VoiceProvider;
  description: string | null;
  createUtterance(text: string): Utterance;
}

Utterance Interface

interface Utterance {
  start(): Promise<void>;
  stop(): Promise<void>;
  set onstart(callback: () => void);
  set onend(callback: () => void);
  set onerror(callback: (error: Error) => void);
}

Browser Compatibility

Browser Speech Synthesis

The browser speech synthesis provider (BrowserVoiceProvider) is supported in all modern browsers:

  • Chrome/Edge: Full support (voices load asynchronously)
  • Firefox: Full support
  • Safari: Full support (iOS and macOS)
  • Opera: Full support

Note: Voice availability and quality vary by browser and operating system. Chrome and Edge typically offer the best selection of voices.

ElevenLabs Provider

The ElevenLabs provider (ElevenLabsVoiceProvider) requires:

  • Cache API: For caching API responses (supported in modern browsers)
  • Fetch API: For making API requests (supported in all modern browsers)
  • Audio API: For playing synthesized speech (supported in all modern browsers)

Minimum Requirements

  • Modern browser with ES2022 support
  • Cache API support (for ElevenLabs caching)
  • No Internet Explorer support

Server-Side Rendering (SSR)

The library is designed for client-side use. When used in SSR environments:

  • Browser voice provider gracefully handles the absence of window.speechSynthesis
  • Returns empty arrays when browser APIs are unavailable
  • Safe to import in SSR frameworks (Next.js, Nuxt, etc.) but should only be used client-side

Contributing

Contributions are welcome! Please read the CONTRIBUTING.md guide for details on our code of conduct and the process for submitting pull requests.

Changelog

See CHANGELOG.md for a list of changes and version history.

License

Copyright 2025 by Oliver Steele

MIT