Embeddable TTS widget for blogs and websites - as simple as Google Analytics
npm install @supernal/tts-widgetEmbeddable Text-to-Speech widget for blogs and websites. Add voice to your content in seconds - just like Google Analytics.
✅ Simple as gtag - Drop in two scripts and you're done
✅ Zero JavaScript - Works with plain HTML, no bundlers needed
✅ Auto-discovery - Automatically finds and activates TTS elements
✅ Framework agnostic - Works with React, Vue, vanilla HTML, etc.
✅ Smart defaults - Hardcoded to https://www.tts.supernal.ai, just add your API key
``html
That's it! The widget automatically scans for
.supernal-tts-widget elements when the page loads.$3
`tsx
import Script from 'next/script';export default function RootLayout({ children }) {
return (
{children}
);
}
`Then use in your components:
`tsx
export default function BlogPost({ content }) {
return (
{content}
);
}
`Installation (Optional - for npm workflows)
`bash
npm install @supernal/tts-widget
`$3
`javascript
import { SupernalTTS } from '@supernal/tts-widget';
import '@supernal/tts-widget/widget.css';SupernalTTS.init({
apiKey: 'YOUR_API_KEY'
});
`$3
`tsx
import { TTSInitializer } from '@supernal/tts-widget/react';
import '@supernal/tts-widget/widget.css';export default function App() {
return (
<>
apiKey={process.env.NEXT_PUBLIC_TTS_API_KEY}
mode="bundled" // Skip CDN attempt in bundled apps
/>
>
);
}
`Configuration Options
$3
`javascript
window.SupernalTTS.init({
// Required (defaults to https://www.tts.supernal.ai if not provided)
apiKey: 'YOUR_API_KEY', // Optional overrides (these all have smart defaults)
apiUrl: 'https://www.tts.supernal.ai', // Custom API endpoint
provider: 'openai', // TTS provider
voice: 'alloy', // Default voice
speed: 1.0, // Playback speed (0.25-4.0)
clientSideSpeed: true, // Use browser speed (saves $$, recommended!)
showBranding: true, // Show "Powered by Supernal"
devMode: false // Enable debug logging
});
`$3
`html
data-text="Professional narration"
data-voice="nova"
data-provider="openai">
Professional narration
Advanced: Programmatic Control
$3
`javascript
const tts = window.SupernalTTS.getInstance();// Add TTS to any element
tts.addWidget(
document.querySelector('#my-element'),
'Text to speak',
{ voice: 'alloy', provider: 'openai' }
);
`$3
For truly zero-config, use data attributes:
`html
data-supernal-tts-auto-init='{"apiKey":"YOUR_KEY"}'>
`The widget reads the config and initializes automatically!
Version Pinning
`html
`$3
The widget automatically detects API keys from common framework environment variables, eliminating boilerplate:
`javascript
// ✅ Minimal configuration - API key auto-detected
SupernalTTS.init({
apiUrl: window.location.origin
// provider defaults to 'openai'
// apiKey auto-detected from NEXT_PUBLIC_TTS_API_KEY (or similar)
});
`Supported environment variables (checked in order):
-
NEXT_PUBLIC_TTS_API_KEY - Next.js
- VITE_TTS_API_KEY - Vite
- PUBLIC_TTS_API_KEY - SvelteKit, Astro
- REACT_APP_TTS_API_KEY - Create React AppHow it works:
1. Widget checks for these variables at runtime (bundlers expose them client-side)
2. If found, automatically uses the key for API authentication
3. You can still override by explicitly passing
apiKey option
4. Only works in browser (server-side rendering won't auto-detect)Example - Next.js:
`bash
.env.local
NEXT_PUBLIC_TTS_API_KEY=your-api-key-here
``javascript
// No need to pass apiKey - auto-detected!
SupernalTTS.init({
apiUrl: 'https://tts.supernal.ai'
});
`$3
By default (
clientSideSpeed: true), the widget uses the browser's native preservesPitch feature with playbackRate to adjust speed instantly without regenerating audio. This:- ✅ Saves significant costs - no need to generate audio at multiple speeds
- ✅ Instant speed changes - no loading/regeneration delay
- ✅ Maintains pitch quality - uses browser's time-stretching algorithm
- ✅ Works with already-cached audio
Set
clientSideSpeed: false if you need server-side speed generation with provider-specific pitch correction (more expensive but may have slightly different quality characteristics for extreme speed changes).Widget Data Attributes
`html
data-text="Professional voice example"
data-voice="coral"
data-provider="openai">
Professional voice example
Available Voices
$3
- alloy, echo, fable, onyx, nova, shimmer, coral, sage, verse$3
- mock-voice-1, mock-voice-2, mock-voice-3When to Use What?
| Scenario | Recommended Approach | Why |
|----------|---------------------|-----|
| New projects |
import { WidgetLoader } from '.../ loader' | Auto-updates, has fallback |
| Existing code | import { SupernalTTS } from '...' | No changes needed |
| Corporate firewall | import { SupernalTTS } from '...' | Works offline/air-gapped |
| Static HTML blog | Direct CDN @1 | Simple, no build step |
| Need predictability | import { SupernalTTS } from '...' | Manual upgrades only |
| CSP restrictions | import { SupernalTTS } from '...' | No external scripts |Migration from v1.2.x
See MIGRATION.md for detailed upgrade guide.
TL;DR: No breaking changes. Existing code works as-is. New smart loader is opt-in.
`javascript
// Old (v1.2.x - still works exactly the same)
import { SupernalTTS } from '@supernal/tts-widget';
SupernalTTS.init({ ... });// New (v1.3.0 - opt-in for auto-updates)
import { WidgetLoader } from '@supernal/tts-widget/loader';
const widget = await WidgetLoader.load();
widget.init({ ... });
`No action required for existing code! The default export is unchanged.
Documentation
Full documentation: https://tts.supernal.ai
---
Development
This is the SOURCE OF TRUTH for the Supernal TTS widget. All changes should be made here.
$3
`
packages/@supernal/tts-widget/
├── src/
│ ├── widget.ts # TypeScript source (EDIT THIS)
│ └── widget.css # Styles
├── dist/ # Built output (DO NOT EDIT)
│ ├── widget.js # Bundled JavaScript
│ ├── widget.css # Copied styles
│ └── widget.d.ts # TypeScript declarations
├── package.json
└── tsconfig.json
`$3
1. Build the widget:
`bash
npm run build
` This runs:
-
tsc - Compiles TypeScript to JavaScript
- esbuild - Bundles and minifies to a single IIFE file
- cp - Copies CSS to dist2. From monorepo root:
`bash
npm run build:widget
`3. Docs site automatically copies widget on build/start:
`bash
cd docs-site
npm run copy-widget # or npm start / npm run build
`$3
- TypeScript: Proper typing and IDE support
- Dev Mode Cache Clear: Red button in dev mode to clear local cache
- Absolute URLs: Handles both relative and absolute audio URLs
- Branding: Optional Supernal Intelligence badge
- Responsive: Mobile-friendly design
- Dark Mode: Automatic dark mode support
$3
The docs-site imports the widget from this package via:
- Build script:
copy-widget in docs-site/package.json copies built files to static/
- Component: TTSWidget in docs-site/src/components/TTSWidget/ loads from /js/widget.jsDO NOT edit files in
docs-site/static/js/ or docs-site/static/css/ directly!$3
1. Edit
src/widget.ts or src/widget.css
2. Run npm run build (or npm run dev for watch mode)
3. Test in docs-site: cd ../../../docs-site && npm start
4. The widget will be automatically copied and loaded$3
When ready to publish to npm:
`bash
npm version patch|minor|major
npm publish
``