npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

react-webrtc-viewer

v1.0.5

Published

A React component for WebRTC streaming with WHEP protocol support, featuring zoom/pan functionality and customizable UI

Downloads

43

Readme

React WebRTC Viewer

CI npm version npm downloads License: MIT

A React component for WebRTC live streaming with WHEP (WebRTC-HTTP Egress Protocol) support, featuring built-in zoom/pan functionality and customizable UI components.

Installation

npm install react-webrtc-viewer

Dependencies

This package requires the following peer dependencies:

npm install react react-dom video.js whip-whep

Basic Usage

import WhepPlayer from "react-webrtc-viewer";

function App() {
  return (
    <WhepPlayer
      url="https://example.com/live/stream/whep"
      onReady={(player) => console.log("Player ready:", player)}
      onError={(error) => console.error("Stream error:", error)}
    />
  );
}

Features

  • WebRTC WHEP streaming with automatic error handling and reconnection
  • Zoom and Pan functionality for interactive video viewing
  • Customizable UI components for loading, error, and reconnecting states
  • Event callbacks for stream lifecycle management
  • TypeScript support with full type definitions

Props

Basic Props

| Prop | Type | Default | Description | | ----------- | -------- | ------------ | ------------------------- | | url | string | required | WHEP stream URL | | options | object | {} | Video.js player options | | className | string | "" | Additional CSS class name |

Event Callbacks

| Prop | Type | Description | | ---------------------- | ------------------ | ------------------------------ | | onReady | (player) => void | Called when player is ready | | onError | (error) => void | Called on general errors | | onStreamNotFound | (event) => void | Called when stream returns 404 | | onStreamRecovered | (event) => void | Called when stream recovers | | onStreamConnected | (event) => void | Called when stream connects | | onStreamDisconnected | (event) => void | Called when stream disconnects | | onForbidden | (event) => void | Called on 403 errors | | onServerError | (event) => void | Called on 500 errors |

Zoom/Pan Props

| Prop | Type | Default | Description | | --------------- | --------- | ------- | --------------------------------- | | enableZoomPan | boolean | false | Enable zoom and pan functionality | | maxZoom | number | 10 | Maximum zoom level | | zoomStep | number | 0.05 | Zoom step per scroll |

Custom UI Props

| Prop | Type | Description | | -------------------- | ----------------------------------- | ---------------------------------------- | | renderLoading | () => ReactNode | Custom loading spinner component | | renderError | ({ error, onRetry }) => ReactNode | Custom error display component | | renderReconnecting | () => ReactNode | Custom reconnecting display component | | customSpinnerCSS | string | Custom CSS for Video.js internal spinner | | messages | object | Custom messages for internationalization |

Advanced Usage

With Zoom/Pan

<WhepPlayer
  url="https://example.com/live/stream/whep"
  enableZoomPan={true}
  maxZoom={5}
  zoomStep={0.1}
  onReady={(player) => console.log("Player ready")}
/>

With Custom UI Components

<WhepPlayer
  url="https://example.com/live/stream/whep"
  renderLoading={() => <div>Custom loading...</div>}
  renderError={({ error, onRetry }) => (
    <div>
      <h3>Oops! {error}</h3>
      <button onClick={onRetry}>Try Again</button>
    </div>
  )}
  renderReconnecting={() => <div>Reconnecting to stream...</div>}
/>

With Custom Video.js Spinner

Customize the internal Video.js loading spinner:

<WhepPlayer
  url="https://example.com/live/stream/whep"
  customSpinnerCSS={`
    .video-js .vjs-custom-spinner::after {
      border: 6px solid #f3f3f3;
      border-top: 6px solid #ff6b6b;
      width: 60px;
      height: 60px;
      animation: vjs-spin 1s linear infinite;
    }
    
    .video-js .vjs-custom-spinner {
      width: 60px;
      height: 60px;
    }
    
    @keyframes vjs-pulse {
      0% { opacity: 1; }
      50% { opacity: 0.5; }
      100% { opacity: 1; }
    }
    
    /* Add pulsing effect */
    .video-js .vjs-custom-spinner::before {
      content: '📺';
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      font-size: 20px;
      animation: vjs-pulse 1.5s ease-in-out infinite;
    }
  `}
/>

With Internationalization (i18n)

Customize all text messages for different languages:

// English (default)
const englishMessages = {
  loading: "Loading stream...",
  reconnecting: "Reconnecting...",
  streamError: "Stream Error",
  retry: "Retry",
  accessForbidden: "Stream access forbidden (403)",
  serverError: "Server error (500)",
  whepUrlRequired: "WHEP URL is required",
  failedToInitialize: "Failed to initialize WHEP stream",
};

// Spanish
const spanishMessages = {
  loading: "Cargando transmisión...",
  reconnecting: "Reconectando...",
  streamError: "Error de Transmisión",
  retry: "Reintentar",
  accessForbidden: "Acceso a la transmisión prohibido (403)",
  serverError: "Error del servidor (500)",
  whepUrlRequired: "Se requiere URL WHEP",
  failedToInitialize: "Error al inicializar transmisión WHEP",
};

// French
const frenchMessages = {
  loading: "Chargement du flux...",
  reconnecting: "Reconnexion...",
  streamError: "Erreur de Flux",
  retry: "Réessayer",
  accessForbidden: "Accès au flux interdit (403)",
  serverError: "Erreur du serveur (500)",
  whepUrlRequired: "URL WHEP requise",
  failedToInitialize: "Échec de l'initialisation du flux WHEP",
};

function App() {
  return (
    <WhepPlayer
      url="https://example.com/live/stream/whep"
      messages={spanishMessages}
    />
  );
}

Integration with i18n Libraries

import { useTranslation } from "react-i18next";
import WhepPlayer from "react-webrtc-viewer";

function I18nPlayer() {
  const { t } = useTranslation();

  const messages = {
    loading: t("player.loading"),
    reconnecting: t("player.reconnecting"),
    streamError: t("player.streamError"),
    retry: t("player.retry"),
    accessForbidden: t("player.accessForbidden"),
    serverError: t("player.serverError"),
  };

  return (
    <WhepPlayer url="http://localhost/live/stream1/whep" messages={messages} />
  );
}

Dynamic Language Switching

import { useState } from "react";
import WhepPlayer from "react-webrtc-viewer";

const translations = {
  en: {
    loading: "Loading stream...",
    reconnecting: "Reconnecting...",
    streamError: "Stream Error",
    retry: "Retry",
  },
  es: {
    loading: "Cargando transmisión...",
    reconnecting: "Reconectando...",
    streamError: "Error de Transmisión",
    retry: "Reintentar",
  },
  fr: {
    loading: "Chargement du flux...",
    reconnecting: "Reconnexion...",
    streamError: "Erreur de Flux",
    retry: "Réessayer",
  },
};

function MultiLanguagePlayer() {
  const [language, setLanguage] = useState("en");

  return (
    <div>
      <select
        value={language}
        onChange={(e) => setLanguage(e.target.value)}
        style={{ marginBottom: "10px" }}
      >
        <option value="en">English</option>
        <option value="es">Español</option>
        <option value="fr">Français</option>
      </select>

      <WhepPlayer
        url="https://example.com/live/stream/whep"
        messages={translations[language]}
      />
    </div>
  );
}

RTL Language Support

const arabicMessages = {
  loading: "جاري تحميل البث...",
  reconnecting: "إعادة الاتصال...",
  streamError: "خطأ في البث",
  retry: "إعادة المحاولة",
  accessForbidden: "الوصول للبث محظور (403)",
  serverError: "خطأ في الخادم (500)",
};

function ArabicPlayer() {
  return (
    <div dir="rtl">
      <WhepPlayer
        url="http://localhost/live/stream1/whep"
        messages={arabicMessages}
        className="rtl-player"
      />
    </div>
  );
}

Full Event Handling

<WhepPlayer
  url="https://example.com/live/stream/whep"
  onStreamConnected={() => console.log("Stream started")}
  onStreamNotFound={() => console.log("Stream not available")}
  onStreamRecovered={() => console.log("Stream is back online")}
  onStreamDisconnected={() => console.log("Stream disconnected")}
  onForbidden={() => console.log("Access denied")}
  onServerError={() => console.log("Server error")}
/>

Available Message Keys

For internationalization, you can customize the following message keys:

| Key | Default Value | Description | | -------------------- | ---------------------------------- | -------------------------- | | loading | "Loading stream..." | Loading spinner text | | reconnecting | "Reconnecting..." | Reconnecting state text | | streamError | "Stream Error" | Error dialog title | | retry | "Retry" | Retry button text | | accessForbidden | "Stream access forbidden (403)" | 403 error message | | serverError | "Server error (500)" | 500 error message | | whepUrlRequired | "WHEP URL is required" | Missing URL error | | failedToInitialize | "Failed to initialize WHEP stream" | Initialization error | | videoPlayerError | "Video player error" | General player error | | connectionLost | "Connection lost" | Connection failure message |

Default Components

The library exports default components that you can use independently:

import { DefaultLoadingSpinner, DefaultErrorDisplay } from 'react-webrtc-viewer';

// Use the default components in your own layouts
<DefaultLoadingSpinner message="Please wait..." />
<DefaultErrorDisplay
  error="Connection failed"
  onRetry={() => window.location.reload()}
/>

License

MIT