Turn any webpage into an audiobook with the Speechify TTS API
Give the Speechify text-to-speech API a URL and the page comes back as narrated audio. Fetch, extract the article text, chunk on sentence boundaries, synthesize each chunk with POST /v1/audio/speech.
Give the Speechify text-to-speech API a URL and you can hand a listener narrated audio of the article. The pipeline is short: fetch the page, pull out the readable text, split it into chunks, and synthesize each one with POST /v1/audio/speech. Play the chunks back to back and a long read becomes an audiobook. There’s a live demo, and the source is a single Next.js route.
I built the demo against the live API while writing this. It fetched a real Wikipedia article, extracted the text, and returned six chunks of MP3. The examples here are that pipeline.
Four steps, one of them fiddly
The four steps are fetch, extract, chunk, and synthesize. Three are easy; extraction is the one that bites.
Webpage audiobook pipeline
A URL becomes narrated audio in four steps: fetch the page server-side, pull out the readable text, split on sentence boundaries, and call POST /v1/audio/speech once per chunk.
- Step 1FetchServer-side request for the page HTML. Never from the browser — your API key stays server-side and you skip cross-origin restrictions.
GET <url> - Step 2ExtractStrip scripts, styles, and nav. Pull readable text from paragraph and heading tags. The fiddly step — a real readability library beats a hand-rolled one in production.
article text - Step 3ChunkPack whole paragraphs into ~500–800-character segments. Split on sentence boundaries only when a paragraph exceeds the cap.
(?<=[.!?])\s+ - Step 4SynthesizeOne request per chunk. Returns JSON with Base64-encoded audio data — decode it, then play the chunks in order for continuous narrated audio.
POST /v1/audio/speech
Only the synthesize step touches the Speechify API. Fetch, extract, and chunk all run locally — retries and caching stay clean at the chunk boundary.
Fetch is a plain server-side request for the page HTML. Do it on the server, not the browser, so your API key never ships to the client and you avoid cross-origin headaches.
Extract turns that HTML into the words a person actually wants read. This is the hard part, and I’ll be honest about it below.
Chunk is splitting the text so each synthesis request is a sensible size. Split on sentence boundaries, not arbitrary character counts, or the narration stumbles mid-thought.
Synthesize is the easy payoff: each chunk goes to POST /v1/audio/speech and comes back as JSON with Base64-encoded audio — decode audio_data and play the chunks in order.
The text-to-speech API call
Once you have a chunk of clean text, this is the whole of it:
curl -X POST https://api.speechify.ai/v1/audio/speech \
-H "Authorization: Bearer $SPEECHIFY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": "The paragraph of article text to narrate.",
"voice_id": "geffen_32",
"model": "simba-3.2",
"audio_format": "mp3"
}'
Do that per chunk, keep the order, and play them in sequence on the client. The demo caps a long article at the first six chunks so it stays cheap; a real build would page through the rest. The full reference lives in the Speechify TTS API docs.
Chunk on sentence boundaries
The demo packs whole paragraphs into segments of roughly 500 to 800 characters, and only splits a paragraph into sentences (on (?<=[.!?])\s+) when it runs past the cap. That keeps each chunk ending where a human would pause. It’s the same approach that makes long-form narration sound continuous rather than chopped, and the same pattern an earlier post used to narrate an entire ePub with Python and ffmpeg.
Why is extraction so tricky?
Turning arbitrary HTML into just-the-article is a real problem, and a naive extractor gets you most of the way but not all. The demo strips scripts, styles, and nav, then pulls text from paragraph and heading tags. On a clean article that reads well. On a busy page it can pick up menu text, which is exactly what happened on the Wikipedia article I tested. For production, reach for a dedicated readability extractor rather than rolling your own. I left the demo’s version naive on purpose so the code stays dependency-free and easy to read.
Two more things you own in production: fetching arbitrary user-supplied URLs is a server-side request forgery risk, so validate the URL and block private hosts (the demo does a minimal version of this), and long pages need a paging strategy rather than a hard cap.
How do I convert an article URL to speech?
Fetch the page server-side, extract the readable text, chunk it on sentence boundaries, and send each chunk to POST /v1/audio/speech on the Speechify text-to-speech API. Play the returned audio chunks in order, and every step ends up being one HTTP request or a simple loop.
Why fetch and synthesize on the server instead of the browser?
Your Speechify API key stays server-side, and you avoid the cross-origin restrictions the browser puts on fetching other sites. A server route also gives you a single place to validate URLs and add caching. Caching synthesized audio by URL is straightforward server-side too, since you control the response lifecycle and can store results without touching the browser cache.
How should I split a long article for TTS?
On sentence boundaries, packed into segments of a few hundred characters, so each chunk ends at a natural pause. Splitting on raw character counts cuts sentences in half and the narration audibly stumbles. The demo targets 500 to 800 characters per chunk, which balances synthesis latency against natural phrasing.
What’s the hardest part of this?
Extraction. Getting clean article text out of arbitrary HTML is genuinely tricky. A naive strip-the-tags approach works on simple pages but picks up navigation on busy ones, so use a real readability library in production. Readability.js and similar open-source options handle most site layouts reliably and save you from maintaining your own heuristic parser.