ai newsDo., 15. Okt.
EilmeldungMeta and Apple team up to make Muse AI models run better on Macs

Integrating ElevenLabs with Next.js: Step-by-Step Guide

Why Combine ElevenLabs with Next.js? If you’ve ever wanted to add realistic, AI‑generated voice to a web app—whether it’s a podcast generator, an interactive story, or a voice‑enabled chatbot—ElevenLabs is one of the most powerful text‑to‑speech (TTS) engines on the market today. Its neural models

dev.toFreitag 22:41 · 09.10.6 Min. Lesezeit
Bild: dev.to

If you’ve ever wanted to add realistic, AI‑generated voice to a web app—whether it’s a podcast generator, an interactive story, or a voice‑enabled chatbot—ElevenLabs is one of the most powerful text‑to‑speech (TTS) engines on the market today. Its neural models produce natural‑sounding speech, support multiple languages, and even let you clone a voice with a few minutes of audio.

Next.js, with its hybrid rendering capabilities and built‑in API routes, makes it incredibly easy to call external services like ElevenLabs from both the client and the server. In this guide we’ll walk through a full‑stack implementation: a simple UI where users type text, hit “Speak”, and hear the audio streamed back instantly.

Create a.env.local file at the root of your project and add the following:

ELEVENLABS_API_KEY=your-elevenlabs-api-key ELEVENLABS_VOICE_ID=your-default-voice-id # e.g., “EXAVITQu4vr4xnSDxMaL” Enter fullscreen mode Exit fullscreen mode Tip: Keep your API key secret—Next.js automatically exposes only variables prefixed with NEXT_PUBLIC_ to the browser. Since we’ll call ElevenLabs from the server, we don’t need to expose it.

Next.js API routes run on the server, perfect for keeping the API key hidden. Create a new file: pages/api/speak.ts.

import type { NextApiRequest, NextApiResponse } from ' next '; import fetch from ' node-fetch '; export default async function handler ( req: NextApiRequest, res: NextApiResponse ) { if ( req. method!== ' POST ' ) { return res. status ( 405 ). json ({ error: ' Method not allowed ' }); } const { text, voiceId } = req. body; if (! text ) { return res. status ( 400 ). json ({ error: ' Missing text payload ' }); } const voice = voiceId || process. env. ELEVENLABS_VOICE_ID; const apiKey = process. env. ELEVENLABS_API_KEY; try { const response = await fetch ( `https://api.elevenlabs.io/v1/text-to-speech/ ${ voice } `, { method: ' POST ', headers: { ' Content-Type ': ' application/json ', ' xi-api-key ': apiKey!, }, body: JSON. stringify ({ text, voice_settings: { stability: 0.5, similarity_boost: 0.75, }, }), } ); if (! response. ok ) { const err = await response. text (); throw new Error ( `ElevenLabs error: ${ err } ` ); } // The API returns raw audio (mp3) bytes const audioBuffer = await response. arrayBuffer (); // Stream the audio back to the client res. setHeader ( ' Content-Type ', ' audio/mpeg ' ); res. send ( Buffer. from ( audioBuffer )); } catch ( error: any ) { console. error ( error ); res. status ( 500 ). json ({ error: error. message }); } } Enter fullscreen mode Exit fullscreen mode What’s happening?

Create a component at components/VoiceSynthesizer.tsx:

import { useState, useRef } from ' react '; export default function VoiceSynthesizer () { const [ text, setText ] = useState ( '' ); const [ loading, setLoading ] = useState ( false ); const audioRef = useRef < HTMLAudioElement > ( null ); const handleSpeak = async () => { if (! text. trim ()) return; setLoading ( true ); try { const response = await fetch ( ' /api/speak ', { method: ' POST ', headers: { ' Content-Type ': ' application/json ' }, body: JSON. stringify ({ text }), }); if (! response. ok ) throw new Error ( ' Failed to synthesize ' ); const blob = await response. blob (); const url = URL. createObjectURL ( blob ); audioRef. current!. src = url; audioRef. current!. play (); } catch ( err ) { console. error ( err ); alert ( ' Something went wrong – check the console. ' ); } finally { setLoading ( false ); } }; return ( < div style = { { maxWidth: ' 600px ', margin: ' 2rem auto ' } } > < textarea rows = { 4 } placeholder = "Enter the script you want spoken..." value = { text } onChange = { ( e ) => setText ( e. target. value ) } style = { { width: ' 100% ', padding: ' 0.5rem ' } } /> < button onClick = { handleSpeak } disabled = { loading } style = { { marginTop: ' 1rem ', padding: ' 0.75rem 1.5rem ', background: ' #0066ff ', color: ' #fff ', border: ' none ', cursor: loading? ' not-allowed ': ' pointer ', } } > { loading? ' Generating… ': ' Speak ' } </ button > < audio ref = { audioRef } controls style = { { marginTop: ' 1rem ', width: ' 100% ' } } /> </ div > ); } Enter fullscreen mode Exit fullscreen mode Add the component to your homepage ( pages/index.tsx ):

import VoiceSynthesizer from ' @/components/VoiceSynthesizer '; export default function Home () { return ( <> < h1 > 🗣️ Text‑to‑Speech with ElevenLabs + Next.js </ h1 > < VoiceSynthesizer /> </> ); } Enter fullscreen mode Exit fullscreen mode Now, run npm run dev, type a sentence, and hit Speak —you should hear the AI‑generated voice instantly.

ElevenLabs also lets you upload a short audio sample (≈30 seconds) to create a custom voice. Here’s a quick curl example for the cloning endpoint:

curl -X POST "https://api.elevenlabs.io/v1/voices/add" \ -H "xi-api-key: $ELEVENLABS_API_KEY " \ -F "name=MyCustomVoice" \ -F "files=@/path/to/voice_sample.wav" Enter fullscreen mode Exit fullscreen mode The response includes a new voice_id. Store that ID and pass it to the /api/speak route:

await fetch ( ' /api/speak ', { method: ' POST ', headers: { ' Content-Type ': ' application/json ' }, body: JSON. stringify ({ text, voiceId: ' YOUR_CLONED_VOICE_ID ' }) }); Enter fullscreen mode Exit fullscreen mode Now you can let users speak with their voice or any brand‑specific voice you’ve trained.

If you anticipate very long paragraphs, you might want to stream the audio in chunks instead of waiting for the entire MP3. ElevenLabs supports chunked responses via the Accept: audio/mpeg header. Here’s a minimal Node.js streaming example inside the API route:

const response = await fetch ( `https://api.elevenlabs.io/v1/text-to-speech/ ${ voice } `, { method: ' POST ', headers: { ' Content-Type ': ' application/json ', ' xi-api-key ': apiKey!, Accept: ' audio/mpeg ', }, body: JSON. stringify ({ text }) }); res. setHeader ( ' Content-Type ', ' audio/mpeg ' ); response. body?. pipe ( res ); // pipe the streaming body directly Enter fullscreen mode Exit fullscreen mode This keeps memory usage low and lets the browser start playing as soon as the first bytes arrive.

Because the API route contains no server‑side dependencies beyond node-fetch (which is already bundled), you can push the repo to GitHub and connect it to Vercel with one click. Vercel automatically injects your environment variables, so the API key stays secure.

Integrating ElevenLabs with Next.js gives you a production‑ready, server‑secure way to add high‑quality TTS and voice cloning to any web experience. With just a few lines of code you can:

Ready to give your users a voice? Grab your ElevenLabs API key and start building today:

👉 Try ElevenLabs now: https://try.elevenlabs.io/kr07zfuqn1bp

Happy coding, and may your apps speak as smoothly as you type!

Some comments may only be visible to logged-in visitors. Sign in to view all comments.

Quelle: dev.to (dev.to). Original öffnen