VocalStack LogoVocalStack Logo
VOCALSTACK FOR SANITY

Transcripts you can query

A Transcribe button beside the audio in your Sanity Studio documents. The transcript is saved on the document as editable text and timed sentences, so GROQ, your frontend and your search read it like any other field.

SANITY STUDIO 3+ · REACT 18+ · NODE 20+ · FROM $0.20 AN HOUR OF AUDIO
acme.sanity.studio/structure/episode;42
AcmeStructureVision
ContentEpisodesHostsPages
EpisodesEpisode 42: Building in publicEpisode 41: PricingEpisode 40: Hiring
TitleEpisode 42: Building in public
Audio
MP3episode-042.mp346.3 MB · audio/mpeg
Transcript
Transcribing31:06 / 48:20
Stop
00:00Welcome back to the show. Today: shipping early.
00:07The first version was rough, and that was the point.
Publish

Query it with GROQ

The transcript and its timed sentences live on the document, so GROQ and the GraphQL API return them with everything else.

Progress you can see

The field shows how much audio is done and survives a reload. Stop ends a job you no longer want.

Editors stay in charge

The transcript is plain text an editor can correct, with the same history and publishing as the rest of the document.

Key stays on the server

The Studio talks to one route on your own server, which holds the API key. The key never reaches the browser.

SETUP

One plugin, one field, one route

Add the plugin to sanity.config.ts, a vocalstack.transcript field next to the audio in your schema, and the VocalStack route to your frontend (a Next.js route, or any Node or edge server). The route holds the API key, so it never reaches the browser.

01Install the plugin from GitHub and add it to your Studio config.
02Add the VocalStack route to your frontend, with your API key in its environment.
03Add a vocalstack.transcript field next to an audio file field, then click Transcribe.
bash
npm install github:vocalstack/sanity-plugin
typescript
// app/api/vocalstack/[...path]/route.ts
import { createVocalStackHandler } from '@vocalstack/sanity/server'

// The key is read from VOCALSTACK_API_KEY
const handler = createVocalStackHandler({ sanity: { projectId, dataset, token } })
export { handler as GET, handler as OPTIONS, handler as POST }

// sanity.config.ts
import { vocalstack } from '@vocalstack/sanity'

export default defineConfig({
  plugins: [vocalstack({ handlerURL: 'https://www.example.com/api/vocalstack' })],
})

// schemas/episode.ts
defineField({ name: 'audio', type: 'file' }),
defineField({ name: 'transcript', type: 'vocalstack.transcript' }),
OPTIONS

Fits the way you built it

Sensible defaults, and a hook for every place your setup differs.

handlerURL

Where the VocalStack route is mounted on your server. The Studio calls only this address.

audioField

Which file field on the document holds the audio. By default, the first one with an audio file.

spokenLanguage

The language spoken in the audio. Leave it out to detect it automatically.

fileURL

The address VocalStack fetches the audio from. By default, the file's address on Sanity's CDN; return a signed one for private files.

allowedOrigins

Which Studio addresses may call the route.

PRICING

No plugin fee

You pay VocalStack only for the audio you transcribe, on the same rate as the Dashboard and the API. Billed per second, with a minimum of 5 minutes per transcription.

FILES$0.20an hour

Every audio file you transcribe, with speakers, punctuation and timings included.

Frequently Asked Questions

View on GitHubRead the README