
Imagine speaking in English, and having listeners from all over the world hear you translated into...
Imagine speaking in English, and having listeners from all over the world hear you translated into Spanish, Japanese, or French — in real-time, with low latency, and natural vocal delivery.
In this guide, we’ll build and deploy a Real-Time Multilingual Translation Broadcast web application. We'll leverage Next.js for the frontend, LiveKit Cloud for ultra-low latency WebRTC audio delivery, and the Gemini Live API to translate audio streams on the fly.
Finally, we’ll containerize the entire application and deploy it as a production-ready, auto-scaling service on Google Cloud Run.
Our application runs entirely within a single LiveKit Room to keep signaling fast and simple:
Organizer (Speaking)
│ (Vocal audio via WebRTC)
▼
LiveKit Room
├── TranslationBridge Bot ES (Gemini) ──► Spanish Audio Published
├── TranslationBridge Bot JA (Gemini) ──► Japanese Audio Published
└── TranslationBridge Bot FR (Gemini) ──► French Audio Published
│
▼ (Selected translation stream)
Attendees (Watch Page)
Before we start, make sure you have:
Navigate to the root of the project and install the NPM packages:
npm install
If you want to test the setup locally, you can easily spin up a local LiveKit development server using Docker:
docker run --rm -p 7880:7880 -p 7881:7881 -p 7882:7882/udp \
-e LIVEKIT_KEYS="devkey: secret" \
livekit/livekit:latest \
--dev
Create a .env.local file in the root of the project. This will be used for your local environment:
LIVEKIT_API_KEY=devkey
LIVEKIT_API_SECRET=secret
NEXT_PUBLIC_LIVEKIT_URL=ws://localhost:7880
LIVEKIT_URL=ws://localhost:7880
GEMINI_API_KEY=your-gemini-api-key-here
Launch the Next.js development server:
npm run dev
Open http://localhost:3000 to view the application. Open one tab as the Broadcast (host) and another tab to Watch (attendee) to test translation.
When dealing with real-time WebRTC streams, standard packet delivery operates on a 20ms interval. Delivering audio chunks to the Gemini Live API at 50 Hz (50 times per second) results in high network overhead and CPU cycles.
To optimize performance, we configure LiveKit's native FFI audio stream to capture 100ms chunks instead.
In translation-bridge.ts, we initialize the AudioStream with an AudioStreamOptions object:
const audioStream = new AudioStream(track, {
sampleRate: this.inputSampleRate,
numChannels: this.channels,
frameSizeMs: 100, // Deliver 100ms frames to optimize transmission frequency
});
Next.js's standalone output builds yield highly optimized production bundles containing only the exact files needed for deployment.
The @livekit/rtc-node SDK uses a native compiled WebRTC core. During initialization, this core makes HTTPS requests to verify Cloud settings. Bare-minimum Linux images like node:slim do not ship with SSL certificates, which can cause the secure connection to fail silently. We explicitly install ca-certificates in our multi-stage Dockerfile:
# --- Build stage ---
FROM node:22-slim AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
# --- Production stage ---
FROM node:22-slim AS runner
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*
WORKDIR /app
ENV NODE_ENV=production
ENV PORT=8080
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public
EXPOSE 8080
CMD ["node", "server.js"]
We recommend deploying to Google Cloud Run since the translation bridges are long-running processes (WebSocket connections to Gemini and LiveKit) that require persistent containers and support for long-running requests.
Instead of exposing credentials in env vars, store them in Google Secret Manager:
source <(grep -v '^#' .env.local | sed 's/^/export /')
echo -n "$GEMINI_API_KEY" | gcloud secrets create gemini-api-key --data-file=-
echo -n "$LIVEKIT_API_KEY" | gcloud secrets create livekit-api-key --data-file=-
echo -n "$LIVEKIT_API_SECRET" | gcloud secrets create livekit-api-secret --data-file=-
Grant the Default Compute Engine Service Account access to read these secrets:
PROJECT_NUMBER=$(gcloud projects describe $(gcloud config get-value project) --format="value(projectNumber)")
gcloud secrets add-iam-policy-binding gemini-api-key \
--member="serviceAccount:${PROJECT_NUMBER}[email protected]" \
--role="roles/secretmanager.secretAccessor"
gcloud secrets add-iam-policy-binding livekit-api-key \
--member="serviceAccount:${PROJECT_NUMBER}[email protected]" \
--role="roles/secretmanager.secretAccessor"
gcloud secrets add-iam-policy-binding livekit-api-secret \
--member="serviceAccount:${PROJECT_NUMBER}[email protected]" \
--role="roles/secretmanager.secretAccessor"
Run the deployment command. Note the specific Cloud Run configurations required:
--min-instances 0: Keeps idle costs at $0. An active broadcaster page will dynamically ping the server to keep the instance warm during live events.--max-instances 1: The TranslationSessionManager singleton requires a single instance.--timeout 3600: Allows translation sessions up to 1 hour.--no-cpu-throttling: Keeps CPU allocated between requests to ensure zero audio processing lag (only billed while the instance is active).gcloud run deploy live-translate \
--source . \
--region us-central1 \
--allow-unauthenticated \
--min-instances 0 \
--max-instances 1 \
--timeout 3600 \
--no-cpu-throttling \
--set-secrets "\
GEMINI_API_KEY=gemini-api-key:latest,\
LIVEKIT_API_KEY=livekit-api-key:latest,\
LIVEKIT_API_SECRET=livekit-api-secret:latest" \
--set-env-vars "\
LIVEKIT_URL=wss://your-project.livekit.cloud"
Once your service configuration and secrets are set, you can deploy code updates without repeating or redefining the environment variables:
gcloud run deploy live-translate --source . --region us-central1
Google Cloud Run automatically preserves all environment variables, secrets, scaling limits, and CPU allocations from the previous revision.
You now have a fully functional, production-ready Real-Time Multilingual Translation Broadcast app deployed on Google Cloud Run!
frameSizeMs: 100) to optimize network packet overhead.Happy broadcasting! 🌐🎙️
aiHave you ever tried to read a massive pile of reports and summarize them in under 50 words? It’s...
aieIn his keynote on Wednesday, Benoit Schillings, vice president of Technology at Google DeepMind and...
geminiThis article covers the MCP setup and configuration for using Google Omni Preview and underlying...
ai✨ Overview This article explores how Gemini tokenizes data and demonstrates how to count...
aieYesterday, we kicked off our physical newspaper, The Daily Context, at the AI Engineer World’s Fair...
aieWe (at DEV and MLH) are covering AI Engineer's World Fair by printing a physical newspaper called...
Workflows from the Neura Market marketplace related to this Gemini resource