Vidtreo
Integraciones

Integración con React

Guía completa para integrar VIDTREO en aplicaciones React con componentes y hooks.

Integración con React

El paquete @vidtreo/recorder-react proporciona un componente React listo para usar y un hook potente para implementaciones personalizadas.

Instalación

npm install @vidtreo/recorder-react

Inicio Rápido

La forma más simple de añadir grabación de video es con el componente VidtreoRecorder:

import { VidtreoRecorder } from '@vidtreo/recorder-react';

function App() {
  return (
    <VidtreoRecorder
      apiKey={import.meta.env.VITE_VIDTREO_API_KEY}
      onUploadComplete={(result) => {
        console.log('Video listo:', result.uploadUrl);
      }}
    />
  );
}

Props del Componente

Requeridos

PropTipoDescripción
apiKeystringTu API key de VIDTREO

Opcionales

PropTipoPor DefectoDescripción
backendUrlstringhttps://core.vidtreo.comURL del endpoint de la API
enableSourceSwitchingbooleantruePermite cambio cámara/pantalla
enableMutebooleantrueMuestra botón de silencio
enablePausebooleantrueMuestra botón pausar/reanudar
enableDeviceChangebooleantruePermite selección de dispositivos
maxRecordingTimenumberundefinedDuración máxima en milisegundos
countdownDurationnumber3000Cuenta regresiva previa en ms
userMetadataobjectundefinedMetadatos personalizados del video
langstring"en"Idioma de la UI (en, es, pt)
textsobjectundefinedTextos personalizados
demobooleanfalseModo demo (sin subida)

Callbacks

CallbackParámetrosDescripción
onRecordingStart()Se dispara al iniciar grabación
onRecordingStop()Se dispara al terminar grabación
onUploadProgress(progress: number)Progreso de subida (0-1)
onUploadComplete(result)Subida completada exitosamente
onUploadError(error: Error)Fallo en la subida
onError(error: Error)Cualquier error ocurrido

Ejemplo Completo

import { VidtreoRecorder } from '@vidtreo/recorder-react';
import { useState } from 'react';

function VideoRecorderPage() {
  const [videoUrl, setVideoUrl] = useState<string | null>(null);
  const [uploadProgress, setUploadProgress] = useState(0);
  const [isRecording, setIsRecording] = useState(false);

  return (
    <div className="container">
      <h1>Graba un Mensaje de Video</h1>

      <VidtreoRecorder
        apiKey={import.meta.env.VITE_VIDTREO_API_KEY}
        enableSourceSwitching={true}
        enableMute={true}
        enablePause={true}
        enableDeviceChange={true}
        maxRecordingTime={120000} // 2 minutos
        countdownDuration={3000}
        lang="es"
        userMetadata={{
          userId: 'user-123',
          sessionId: 'session-456',
        }}
        onRecordingStart={() => {
          setIsRecording(true);
          setVideoUrl(null);
        }}
        onRecordingStop={() => {
          setIsRecording(false);
        }}
        onUploadProgress={(progress) => {
          setUploadProgress(progress);
        }}
        onUploadComplete={(result) => {
          setVideoUrl(result.uploadUrl);
          setUploadProgress(0);
        }}
        onError={(error) => {
          console.error('Error:', error);
        }}
      />

      {uploadProgress > 0 && uploadProgress < 1 && (
        <div className="progress-bar">
          <div style={{ width: `${uploadProgress * 100}%` }} />
          <span>{Math.round(uploadProgress * 100)}%</span>
        </div>
      )}

      {videoUrl && (
        <div className="result">
          <h2>¡Grabación Completa!</h2>
          <video src={videoUrl} controls />
        </div>
      )}
    </div>
  );
}

Usando el Hook

Para control total sobre la UI, usa el hook useVidtreoRecorder:

import { useVidtreoRecorder } from '@vidtreo/recorder-react';
import { useRef, useEffect } from 'react';

function CustomRecorder() {
  const videoRef = useRef<HTMLVideoElement>(null);

  const { state, actions, audioLevel } = useVidtreoRecorder({
    apiKey: import.meta.env.VITE_VIDTREO_API_KEY,
    onUploadComplete: (result) => {
      console.log('URL del Video:', result.uploadUrl);
    },
  });

  // Conectar stream al elemento video
  useEffect(() => {
    if (videoRef.current && state.stream) {
      videoRef.current.srcObject = state.stream;
    }
  }, [state.stream]);

  // Inicializar al montar
  useEffect(() => {
    actions.startPreview();
  }, []);

  return (
    <div className="custom-recorder">
      <video ref={videoRef} autoPlay muted playsInline />

      {/* Indicador de nivel de audio */}
      <div className="audio-meter" style={{ width: `${audioLevel * 100}%` }} />

      {/* Controles de grabación */}
      <div className="controls">
        {state.recordingState === 'idle' && (
          <button onClick={() => actions.startRecording()}>
            Iniciar Grabación
          </button>
        )}

        {state.recordingState === 'countdown' && (
          <div className="countdown">{state.countdown}</div>
        )}

        {state.recordingState === 'recording' && (
          <>
            <span className="timer">{state.timer}</span>

            <button onClick={() => actions.toggleMute()}>
              {state.isMuted ? 'Activar Audio' : 'Silenciar'}
            </button>

            <button onClick={() =>
              state.isPaused ? actions.resumeRecording() : actions.pauseRecording()
            }>
              {state.isPaused ? 'Reanudar' : 'Pausar'}
            </button>

            <button onClick={() => actions.stopRecording()}>
              Detener
            </button>
          </>
        )}
      </div>

      {/* Selección de dispositivos */}
      <div className="devices">
        <select
          value={state.devices.selectedCamera || ''}
          onChange={(e) => actions.changeCamera(e.target.value)}
        >
          {state.devices.cameras.map((camera) => (
            <option key={camera.deviceId} value={camera.deviceId}>
              {camera.label}
            </option>
          ))}
        </select>

        <select
          value={state.devices.selectedMic || ''}
          onChange={(e) => actions.changeMic(e.target.value)}
        >
          {state.devices.microphones.map((mic) => (
            <option key={mic.deviceId} value={mic.deviceId}>
              {mic.label}
            </option>
          ))}
        </select>
      </div>

      {/* Progreso de subida */}
      {state.uploadProgress !== null && (
        <div className="upload-progress">
          Subiendo: {Math.round(state.uploadProgress * 100)}%
        </div>
      )}

      {state.error && (
        <div className="error">{state.error}</div>
      )}
    </div>
  );
}

Valores de Retorno del Hook

Objeto State

interface State {
  recordingState: 'idle' | 'countdown' | 'recording';
  stream: MediaStream | null;
  isMuted: boolean;
  isPaused: boolean;
  error: string | null;
  countdown: number | null;
  timer: string;                    // formato "00:00"
  uploadProgress: number | null;    // 0-1
  transitionMessage: string | null;
  isInitialized: boolean;
  recordedBlob: Blob | null;
  devices: {
    cameras: MediaDeviceInfo[];
    microphones: MediaDeviceInfo[];
    selectedCamera: string | null;
    selectedMic: string | null;
  };
}

Objeto Actions

interface Actions {
  startRecording(sourceType?: 'camera' | 'screen'): Promise<void>;
  stopRecording(): Promise<RecordingStopResult>;
  pauseRecording(): void;
  resumeRecording(): void;
  toggleMute(): void;
  switchSource(sourceType: 'camera' | 'screen'): Promise<void>;
  changeCamera(deviceId: string): Promise<void>;
  changeMic(deviceId: string): Promise<void>;
  startPreview(sourceType?: 'camera' | 'screen'): Promise<void>;
  downloadVideo(): void;
  cleanup(): void;
}

Internacionalización

Idiomas Incorporados

// Inglés (por defecto)
<VidtreoRecorder apiKey="..." lang="en" />

// Español
<VidtreoRecorder apiKey="..." lang="es" />

// Portugués
<VidtreoRecorder apiKey="..." lang="pt" />

Textos Personalizados

Sobrescribe cualquier texto de la UI:

<VidtreoRecorder
  apiKey="..."
  lang="es"
  texts={{
    record: 'Iniciar Captura',
    stop: 'Finalizar Captura',
    pause: 'Esperar',
    resume: 'Continuar',
    mute: 'Silencio',
    unmute: 'Con Sonido',
    switchSource: 'Cambiar Fuente',
    uploading: 'Enviando...',
  }}
/>

Claves de Texto Disponibles

ClavePor Defecto (Español)
initializingCameraInicializando cámara...
grantPermissionsPor favor concede permisos de cámara
switchingDeviceCambiando dispositivo...
recordingStartsInLa grabación comienza en
switchingSourceCambiando fuente...
recREC
settingsConfiguración
recordGrabar
stopDetener
pausePausar
resumeReanudar
muteSilenciar
unmuteActivar Audio
switchSourceCambiar Fuente
cameraCámara
microphoneMicrófono
uploadingSubiendo...

Soporte TypeScript

Todos los tipos están exportados:

import type {
  VidtreoRecorderProps,
  UseVidtreoRecorderConfig,
  UseVidtreoRecorderReturn,
  VidtreoRecorderState,
  VidtreoRecorderActions,
  PartialTranslations,
  TranslationKeys,
} from '@vidtreo/recorder-react';

Compatibilidad con Next.js

Para Next.js con App Router, asegura el renderizado del lado del cliente:

'use client';

import { VidtreoRecorder } from '@vidtreo/recorder-react';

export default function RecorderPage() {
  return (
    <VidtreoRecorder
      apiKey={process.env.NEXT_PUBLIC_VIDTREO_API_KEY!}
      onUploadComplete={(result) => {
        console.log('Video:', result.uploadUrl);
      }}
    />
  );
}

El grabador VIDTREO requiere APIs del navegador y debe renderizarse en el lado del cliente.

Próximos Pasos

En esta página