> This is a page from the ElevenLabs documentation. For a complete page index, fetch https://elevenlabs.io/docs/llms.txt. For the full documentation in a single file, fetch https://elevenlabs.io/docs/llms-full.txt.

# Streaming en el cliente

> **Note**
>
> **Guía práctica** · Da por hecho que has completado la [guía de inicio rápido de Voz a Texto ](/docs/es/eleven-api/guides/cookbooks/speech-to-text).

## Descripción general

La API de Voz a Texto en Tiempo Real de ElevenLabs te permite transcribir flujos de audio en tiempo real con una latencia ultrabaja mediante el modelo Scribe Realtime v2. Tanto si estás creando asistentes de voz, servicios de transcripción o cualquier aplicación que requiera reconocimiento de voz en directo, esta API basada en WebSocket proporciona transcripciones parciales mientras hablas y transcripciones confirmadas cuando se completan los segmentos de voz.

Scribe v2 Realtime puede implementarse en el lado del cliente para transcribir audio en tiempo real, ya sea a través del micrófono o dividiendo manualmente el audio en fragmentos.

La implementación en el lado del cliente se diferencia de la del lado del servidor en algunos aspectos:

* Requiere un token de un solo uso: es un token temporal que puede utilizarse para conectarse a la API sin exponer tu clave de API.
* El audio del micrófono puede enviarse directamente a la API para transcribirlo, sin necesidad de dividirlo manualmente en fragmentos.

Para transmitir audio desde una URL, consulta la guía de [transmisión en el lado del servidor](/docs/es/eleven-api/guides/how-to/speech-to-text/realtime/server-side-streaming).

## Inicio rápido

> **Note**
>
> Esta guía da por hecho que has [configurado tu clave de API](/docs/es/eleven-api/quickstart). Completa primero la
> guía de inicio rápido si aún no lo has hecho.

#### Instala el SDK

**`React`**

```bash title="React"
npm install @elevenlabs/react @elevenlabs/elevenlabs-js
```

**`JavaScript`**

```bash title="JavaScript"
npm install @elevenlabs/client @elevenlabs/elevenlabs-js
```

#### Crea un token

Para utilizar el SDK del lado del cliente, debes crear un token de un solo uso. Es un token temporal que puede utilizarse para conectarse a la API sin exponer tu clave de API. Puedes hacerlo a través de la API de ElevenLabs en el lado del servidor.

> **Warning**
>
> Nunca expongas tu clave de API en el cliente.

```typescript
// Node.js server
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";

const elevenlabs = new ElevenLabsClient({
  apiKey: process.env.ELEVENLABS_API_KEY,
});

app.get("/scribe-token", yourAuthMiddleware, async (req, res) => {
  const token = await elevenlabs.tokens.singleUse.create("realtime_scribe");

  res.json(token);
});
```

> **Info**
>
> Un token de un solo uso caduca automáticamente después de 15 minutos.

#### Inicia la sesión de transcripción

La transcripción puede realizarse mediante el micrófono o dividiendo manualmente tu propio audio en fragmentos. Tu propio audio puede ser un archivo o un flujo.

> **Info**
>
> Para consultar la lista completa de parámetros y opciones compatibles con la API, consulta la [referencia de la API](/docs/es/api-reference/speech-to-text/v-1-speech-to-text-realtime).

#### Micrófono

**`React`**

```typescript title="React"
import { useScribe } from "@elevenlabs/react";

function MyComponent() {
  const scribe = useScribe({
    modelId: "scribe_v2_realtime",
    onPartialTranscript: (data) => {
      console.log("Partial:", data.text);
    },
    onCommittedTranscript: (data) => {
      console.log("Committed:", data.text);
    },
    onCommittedTranscriptWithTimestamps: (data) => {
      console.log("Committed with timestamps:", data.text);
      console.log("Timestamps:", data.words);
    },
  });

  const handleStart = async () => {
    // Fetch a single use token from the server
    const token = await fetchTokenFromServer();

    await scribe.connect({
      token,
      microphone: {
        echoCancellation: true,
        noiseSuppression: true,
      },
    });
  };

  return (
    <div>
      <button onClick={handleStart} disabled={scribe.isConnected}>
        Start Recording
      </button>
      <button onClick={scribe.disconnect} disabled={!scribe.isConnected}>
        Stop
      </button>

      {scribe.partialTranscript && <p>Live: {scribe.partialTranscript}</p>}

      <div>
        {scribe.committedTranscripts.map((t) => (
          <p key={t.id}>{t.text}</p>
        ))}
      </div>
    </div>
  );
}
```

**`JavaScript`**

```typescript title="JavaScript"
// Client side
import { Scribe, RealtimeEvents } from "@elevenlabs/client";

// Ensure you have authentication headers set up
const response = await fetch("/scribe-token", yourAuthHeaders);
const { token } = await response.json();

const connection = Scribe.connect({
  token,
  modelId: "scribe_v2_realtime",
  includeTimestamps: true,
  microphone: {
    echoCancellation: true,
    noiseSuppression: true,
    autoGainControl: true,
  },
});

// Set up event handlers

// Session started
connection.on(RealtimeEvents.SESSION_STARTED, () => {
  console.log("Session started");
});

// Partial transcripts (interim results), use this in your UI to show the live transcript
connection.on(RealtimeEvents.PARTIAL_TRANSCRIPT, (data) => {
  console.log("Partial:", data.text);
});

// Committed transcripts
connection.on(RealtimeEvents.COMMITTED_TRANSCRIPT, (data) => {
  console.log("Committed:", data.text);
});

// Committed transcripts with word-level timestamps. Only received when includeTimestamps is set to true.
connection.on(RealtimeEvents.COMMITTED_TRANSCRIPT_WITH_TIMESTAMPS, (data) => {
  console.log("Committed:", data.text);
  console.log("Timestamps:", data.words);
});

// Errors - will catch all errors, both server and websocket specific errors
connection.on(RealtimeEvents.ERROR, (error) => {
  console.error("Error:", error);
});

// Connection opened
connection.on(RealtimeEvents.OPEN, () => {
  console.log("Connection opened");
});

// Connection closed
connection.on(RealtimeEvents.CLOSE, () => {
  console.log("Connection closed");
});

// When you are done, close the connection
connection.close();
```

#### División manual del audio en fragmentos

**`React`**

```typescript title="React"
import { useScribe, AudioFormat } from "@elevenlabs/react";

function FileTranscription() {
  const [file, setFile] = useState<File | null>(null);
  const scribe = useScribe({
    modelId: "scribe_v2_realtime",
    audioFormat: AudioFormat.PCM_16000,
    sampleRate: 16000,
  });

  const transcribeFile = async () => {
    if (!file) return;

    // Fetch a single use token from the server
    const token = await fetchToken();
    await scribe.connect({ token });

    // Decode audio file
    const arrayBuffer = await file.arrayBuffer();
    const audioContext = new AudioContext({ sampleRate: 16000 });
    const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);

    // Convert to PCM16
    const channelData = audioBuffer.getChannelData(0);
    const pcmData = new Int16Array(channelData.length);

    for (let i = 0; i < channelData.length; i++) {
      const sample = Math.max(-1, Math.min(1, channelData[i]));
      pcmData[i] = sample < 0 ? sample * 32768 : sample * 32767;
    }

    // Send in chunks
    const chunkSize = 4096;
    for (let offset = 0; offset < pcmData.length; offset += chunkSize) {
      const chunk = pcmData.slice(offset, offset + chunkSize);
      const bytes = new Uint8Array(chunk.buffer);
      const base64 = btoa(String.fromCharCode(...bytes));

      scribe.sendAudio(base64);
      await new Promise((resolve) => setTimeout(resolve, 50));
    }

    // Commit transcription
    scribe.commit();
  };

  return (
    <div>
      <input
        type="file"
        accept="audio/*"
        onChange={(e) => setFile(e.target.files?.[0] || null)}
      />
      <button onClick={transcribeFile} disabled={!file || scribe.isConnected}>
        Transcribe
      </button>

      {scribe.committedTranscripts.map((transcript) => (
        <div key={transcript.id}>{transcript.text}</div>
      ))}
    </div>
  );
}
```

**`JavaScript`**

```typescript title="JavaScript"
import { Scribe, AudioFormat, RealtimeEvents, CommitStrategy } from "@elevenlabs/client";

// Ensure you have authentication headers set up
const response = await fetch("/scribe-token", yourAuthHeaders);
const { token } = await response.json();

const connection = Scribe.connect({
  token,
  modelId: "scribe_v2_realtime",
  includeTimestamps: true,
  audioFormat: AudioFormat.PCM_16000,
  sampleRate: 16000,
  commitStrategy: CommitStrategy.MANUAL,
});

// Set up event handlers
connection.on(RealtimeEvents.SESSION_STARTED, () => {
  console.log("Session started");
  sendAudio();
});

connection.on(RealtimeEvents.PARTIAL_TRANSCRIPT, (data) => {
  console.log("Partial:", data.text);
});

connection.on(RealtimeEvents.COMMITTED_TRANSCRIPT, (data) => {
  console.log("Committed:", data.text);
});

connection.on(RealtimeEvents.ERROR, (error) => {
  console.error("Error:", error);
});

// Committed transcripts with word-level timestamps. Only received when includeTimestamps is set to true.
connection.on(RealtimeEvents.COMMITTED_TRANSCRIPT_WITH_TIMESTAMPS, (data) => {
  console.log("Committed:", data.text);
  console.log("Timestamps:", data.words);

  // Committed transcript received, close the connection
  connection.close();
});

async function sendAudio() {
  // Get file from input element
  const fileInput = document.querySelector('input[type="file"]');
  const audioFile = fileInput.files[0];

  // Read file as ArrayBuffer
  const arrayBuffer = await audioFile.arrayBuffer();
  const audioData = new Uint8Array(arrayBuffer);

  // Convert to base64 and send in chunks
  const chunkSize = 8192; // 8KB chunks
  for (let i = 0; i < audioData.length; i += chunkSize) {
    const chunk = audioData.slice(i, i + chunkSize);
    const base64 = btoa(String.fromCharCode(...chunk));

    // Send audio chunk
    connection.send({ audioBase64: base64 });

    // Optional: Add delay to simulate real-time streaming
    await new Promise((resolve) => setTimeout(resolve, 100));
  }

  // Signal end of audio segment
  connection.commit();
}
```

## Próximos pasos

#### [Transmisión en el lado del servidor](/docs/es/eleven-api/guides/how-to/speech-to-text/realtime/server-side-streaming)

Transcribe flujos de audio en el lado del servidor con la misma API de WebSocket.

#### [Transcripciones y estrategias de confirmación](/docs/es/eleven-api/guides/how-to/speech-to-text/realtime/transcripts-and-commit-strategies)

Controla cuándo se confirman las transcripciones y cómo gestionar los resultados parciales.