tts Permission — Chrome Extension Reference

8 min read

tts Permission — Chrome Extension Reference

Overview

manifest.json

{ "permissions": ["tts"] }

For engine providers: add "ttsEngine" permission + "tts_engine" manifest key with voice definitions.

Key APIs — chrome.tts

speak(text, options?, callback?)

chrome.tts.speak("Hello!", {
  lang: "en-US", rate: 1.0, pitch: 1.0, volume: 1.0,
  voiceName: "Google US English",
  onEvent: (e) => console.log(e.type, e.charIndex)
});

stop() / pause() / resume()

isSpeaking(callback)

getVoices(callback)

chrome.tts.getVoices((voices) => {
  voices.forEach(v => console.log(v.voiceName, v.lang, v.remote));
});

chrome.ttsEngine (Provider)

Common Patterns

Screen Reader

Language Learning

Accessibility Helper

Voice Selection Best Practices

Using with @theluckystrike/webext-permissions

import { checkPermission, requestPermission, PERMISSION_DESCRIPTIONS } from "@theluckystrike/webext-permissions";

const result = await checkPermission("tts");
console.log(result.description); // "Use text-to-speech"
console.log(result.granted);

PERMISSION_DESCRIPTIONS.tts; // "Use text-to-speech"

// If using optional_permissions
if (!result.granted) {
  const req = await requestPermission("tts");
  if (!req.granted) return;
}

Using with @theluckystrike/webext-messaging

Pattern: popup or content script requests speech from the background:

type Messages = {
  speakText: {
    request: { text: string; lang?: string; rate?: number };
    response: { started: boolean };
  };
  stopSpeaking: {
    request: void;
    response: { stopped: boolean };
  };
  getAvailableVoices: {
    request: void;
    response: Array<{ voiceName: string; lang: string; remote: boolean }>;
  };
};

// background.ts
import { createMessenger } from "@theluckystrike/webext-messaging";
const msg = createMessenger<Messages>();

msg.onMessage({
  speakText: async ({ text, lang, rate }) => {
    chrome.tts.speak(text, {
      lang: lang || "en-US",
      rate: rate || 1.0,
      onEvent: (e) => {
        if (e.type === "error") console.error("TTS error:", e.errorMessage);
      },
    });
    return { started: true };
  },
  stopSpeaking: async () => {
    chrome.tts.stop();
    return { stopped: true };
  },
  getAvailableVoices: async () => {
    const voices = await chrome.tts.getVoices();
    return voices.map(v => ({
      voiceName: v.voiceName || "",
      lang: v.lang || "",
      remote: v.remote || false,
    }));
  },
});

Using with @theluckystrike/webext-storage

Store voice preferences:

import { defineSchema, createStorage } from "@theluckystrike/webext-storage";

const schema = defineSchema({
  preferredVoice: "",
  speechRate: 1.0,
  speechPitch: 1.0,
  speechVolume: 1.0,
  preferLocalVoices: true,
});
const storage = createStorage({ schema });

// Apply user preferences when speaking
async function speakWithPreferences(text: string) {
  const voice = await storage.get("preferredVoice");
  const rate = await storage.get("speechRate");
  const pitch = await storage.get("speechPitch");
  const volume = await storage.get("speechVolume");

  chrome.tts.speak(text, {
    voiceName: voice || undefined,
    rate,
    pitch,
    volume,
  });
}

// Watch for preference changes from options page
storage.watch("speechRate", (newRate) => {
  console.log(`Speech rate changed to ${newRate}`);
});

Practical Example: Read Selection Aloud

// background.ts — context menu + TTS integration
chrome.runtime.onInstalled.addListener(() => {
  chrome.contextMenus.create({
    id: "read-aloud",
    title: 'Read "%s" aloud',
    contexts: ["selection"],
  });
});

chrome.contextMenus.onClicked.addListener(async (info) => {
  if (info.menuItemId === "read-aloud" && info.selectionText) {
    // Stop any current speech first
    chrome.tts.stop();

    const voices = await chrome.tts.getVoices();
    const localVoice = voices.find(v => !v.remote && v.lang?.startsWith("en"));

    chrome.tts.speak(info.selectionText, {
      voiceName: localVoice?.voiceName,
      rate: 1.0,
      enqueue: false,
      onEvent: (event) => {
        if (event.type === "end") {
          console.log("Finished reading selection");
        }
      },
    });
  }
});

Gotchas

Common Errors

Frequently Asked Questions

How do I add text-to-speech to Chrome extension?

Use chrome.tts.speak() to make Chrome read text aloud. You can choose voices, rate, pitch, and listen for events.

Can I use custom voices with the TTS API?

Yes, you can use Chrome’s built-in voices or install extension TTS engines for additional voice options. —

Part of the Chrome Extension Guide by theluckystrike. Built at zovo.one.

No previous article
No next article