Pinch PINCH

Node.js Demo App

This is a minimal working example that demonstrates real-time speech translation in a browser.

https://github.com/pinch-eng/pinch-realtime-demo

Quick Start

1. Clone the repository

git clone https://github.com/pinch-eng/pinch-realtime-demo
cd pinch-realtime-demo

2. Install Dependencies

npm install

3. Add Your API Key

Create a .env file in the project root:

PINCH_API_KEY=your_api_key_here

Don’t have an API key? Login to the Pinch Developer Portal >

4. Run the Demo

npm start

You’ll see:

EXAMPLE OUTPUT
Pinch Real-Time Demo running at http://localhost:3000

5. Try It Out

  1. Open your browser to http://localhost:3000
  2. Click the Connect button
  3. Allow microphone access when prompted
  4. Start speaking and watch the real-time translation appear!

How It Works

The demo has two simple parts:

Backend (server.js)

  • Express server that runs on your computer
  • Proxies requests to the Pinch API (keeps your API key secret)
  • Serves the HTML file to your browser

Frontend (index.html)

  • Single HTML file with embedded JavaScript
  • Connects to the translation service
  • Captures microphone audio and sends it for translation
  • Displays transcripts and plays translated audio

Understanding the Code

Session Creation (Backend)

The backend creates a secure session:

// server.js
app.post("/api/session", async (req, res) => {
  const response = await fetch("https://api.startpinch.com/api/beta1/session", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${PINCH_API_KEY}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      source_language: "en-US",
      target_language: "es-ES",
      voice_type: "clone"
    })
  });
  const data = await response.json();
  res.json(data);
});

Connecting to the Room (Frontend)

// Get credentials from backend
const { url, token } = await fetch("/api/session", {
  method: "POST"
}).then(r => r.json());

// Connect to LiveKit room
const room = new Room();
await room.connect(url, token);

// Start streaming microphone
await room.localParticipant.setMicrophoneEnabled(true);

Receiving Transcripts (Frontend)

The browser listens for transcript messages:

room.on(RoomEvent.DataReceived, (payload) => {
  const message = JSON.parse(new TextDecoder().decode(payload));

  if (message.type === "original_transcript") {
    // Display original text in left panel
    displayOriginal(message.text, message.is_final);
  }
  else if (message.type === "translated_transcript") {
    // Display translation in right panel
    displayTranslated(message.text, message.is_final);
  }
});

Receiving Audio (Frontend)

The browser plays translated audio automatically:

room.on(RoomEvent.TrackSubscribed, (track) => {
  if (track.kind !== Track.Kind.Audio) return;

  // Create audio element
  const audioEl = document.createElement("audio");
  audioEl.autoplay = true;
  audioEl.playsInline = true;

  // Attach translated audio stream
  track.attach(audioEl);
  document.body.appendChild(audioEl);
});

Change Languages

Edit server.js to translate between different languages:

body: JSON.stringify({
  source_language: "en-US",    // Change this
  target_language: "es-ES",    // Change this
  voice_type: "clone"
})

Check Supported languages > for the full list.