guardvid.comdocs
SDK v1.0 — Stable
@guardvideo/player-sdk

GuardVideo Player SDK

Embed secure, DRM-protected video with enterprise-grade anti-piracy, branded context menus, and a single React component or vanilla JS call.

Getting Started

Start here

Install the SDK and have your first protected video running in under five minutes.

Requirements

Node.js 18+, React 18+ or Next.js 13+ (App Router). Works in all modern browsers. No additional peer dependencies required — HLS.js is bundled.

Installation

bash
# npm
npm install @guardvideo/player-sdk

# yarn
yarn add @guardvideo/player-sdk

# pnpm
pnpm add @guardvideo/player-sdk

Obtain your credentials

After signing up at guardvid.com, generate an API key from your dashboard. Your embedTokenEndpoint is a backend route you control — it exchanges your API key for a short-lived, viewer-specific signed token. Never expose your API key client-side.

React / Next.js

A drop-in component for quick integration, plus a hook for full control over playback and UI.

Component — Basic usage

VideoPage.tsx
import { GuardVideoPlayer } from '@guardvideo/player-sdk';

export default function VideoPage() {
  return (
    <GuardVideoPlayer
      videoId="your-video-id"
      embedTokenEndpoint="https://api.guardvid.com/embed-tokens"
      controls
      autoplay={false}
      onReady={() => console.log('Player ready')}
      onError={(err) => console.error(err)}
    />
  );
}

Hook — Custom controls

Use useGuardVideoPlayer when you need full control over the player UI, quality switching, or want to drive your own playback controls.

CustomPlayer.tsx
import { useGuardVideoPlayer } from '@guardvideo/player-sdk';

export default function CustomPlayer() {
  const {
    videoRef, state, isReady,
    currentTime, duration,
    play, pause, seek,
    setVolume, qualityLevels, setQuality,
  } = useGuardVideoPlayer({
    videoId: 'your-video-id',
    embedTokenEndpoint: 'https://api.guardvid.com/embed-tokens',
    autoplay: false,
    security: {
      enableWatermark: true,
      watermarkText: 'user@example.com',
      disablePiP: true,
      maxPlaybackRate: 2,
    },
  });

  return (
    <div>
      <video ref={videoRef} />
      {isReady && (
        <div className="controls">
          <button onClick={play}>Play</button>
          <button onClick={pause}>Pause</button>
          <span>{currentTime.toFixed(1)}s / {duration.toFixed(1)}s</span>
        </div>
      )}
    </div>
  );
}

Vanilla JS / CDN

Zero build-step integration — one script tag and a single function call is all you need.

Version pinning

The IIFE build exposes GuardVideoPlayer as a global. Pin the CDN URL to a specific semver version in production to avoid unintended breaking changes from @latest.
index.html
<!-- Include the SDK (pin version in production) -->
<script src="https://cdn.guardvid.com/sdk/guardvideo-player.iife.js"></script>

<div id="video-container" style="width:100%;max-width:900px;aspect-ratio:16/9"></div>

<script>
  const player = GuardVideoPlayer.create('video-container', 'your-video-id', {
    embedTokenEndpoint: 'https://api.guardvid.com/embed-tokens',
    controls: true,
    branding: {
      name: 'GuardVideo',
      url: 'https://guardvid.com',
      accentColor: '#44c09b',
    },
    security: {
      enableWatermark: true,
      watermarkText: 'viewer@example.com',
      disablePiP: true,
      blockDevTools: true,
    },
    onReady: () => console.log('Player ready!'),
    onError: (err) => console.error('Error:', err),
  });
</script>

Branded Context Menu

Replace the browser's default right-click menu with a polished, on-brand overlay that deters casual inspection.

Preview

GuardVideov1.0
Report an Issue
Share Video
Visit Website
Secure Video Player

Right-clicking shows your brand instead of the browser's native menu — eliminating quick access to "Inspect Element" and raw video URLs.

Add custom menu items with onClick handlers or external href links. Use separator: true to group related actions.

Set disableRightClick: true in security to block the context menu entirely instead of replacing it.

VideoPage.tsx
<GuardVideoPlayer
  videoId="your-video-id"
  embedTokenEndpoint="https://api.guardvid.com/embed-tokens"
  branding={{
    name: 'MyBrand',
    url: 'https://mybrand.com',
    logoUrl: '/logo.svg',        // optional
    accentColor: '#44c09b',
  }}
  contextMenuItems={[
    {
      label: 'Report an Issue',
      onClick: () => openReportDialog(),
      separator: true,
    },
    {
      label: 'Share Video',
      href: 'https://mybrand.com/share',
    },
  ]}
/>

Security Features

Enterprise-grade anti-piracy protections, all controlled via a single security configuration object.

Watermark Overlay

Semi-transparent text overlay (e.g. user email) that follows the video to deter screen recording and frame-capture.

Branded Right-Click

Replace the browser context menu with your branded overlay — prevents quick access to "Inspect Element" and source URLs.

Text Selection Block

Prevent selecting or copying any text elements rendered over the video.

Drag Prevention

Block dragging the video element into external applications or new browser tabs.

PiP Prevention

Disable Picture-in-Picture mode to prevent content extraction into detached windows.

DevTools Blocking

Intercept F12, Ctrl+Shift+I, and Ctrl+Shift+J to deter casual DevTools inspection.

Playback Rate Cap

Limit maximum playback speed to prevent automated fast-forward content scraping.

Domain Allow-list

Restrict playback to authorised origins — any embed attempt from an unlisted domain is blocked.

VideoPage.tsx
<GuardVideoPlayer
  videoId="your-video-id"
  embedTokenEndpoint="https://api.guardvid.com/embed-tokens"
  security={{
    disableRightClick: false,    // false = branded menu | true = block entirely
    disableSelection: true,
    disableDrag: true,
    enableWatermark: true,
    watermarkText: 'user@example.com',
    disablePiP: true,
    disableScreenCapture: true,
    blockDevTools: true,
    maxPlaybackRate: 2,
    allowedDomains: [
      'https://mybrand.com',
      'https://staging.mybrand.com',
    ],
  }}
/>

Forensic Watermark

Phase 3

Server-side burn-in that embeds a unique viewer fingerprint into every HLS segment at the codec level — survives screen recording and cannot be removed via the DOM.

How it works

When forensicWatermark is true, the backend intercepts each HLS segment request, decrypts the segment on-the-fly, runs ffmpeg drawtext to burn the viewer identity into the video frames, and caches the result. The first request triggers the watermark; subsequent requests are served from cache. No pre-processing queue — playback starts immediately.

On-demand, zero wait

Segments are watermarked the first time they are requested. No background job, no delay before first play.

Per-viewer fingerprint

viewerName + viewerEmail are combined to form a unique identifier burned into the video. Falls back to the token ID.

Cache-backed

Watermarked segments are cached per token + quality and served immediately on repeat views. Expired nightly.

Forensic extraction

Any watermarked segment can be submitted to the extraction endpoint to identify the leaker by reading the embedded gv-wm metadata.

Enabling forensic watermark

Pass viewerName, viewerEmail, and forensicWatermark: true to the player. The SDK forwards these to your embedTokenEndpoint, which passes them to the GuardVideo API. The API then watermarks every segment served to that token.

WatchPage.tsx
<GuardVideoPlayer
  videoId="your-video-id"
  embedTokenEndpoint="https://api.guardvid.com/embed-tokens"
  viewerName={currentUser.name}
  viewerEmail={currentUser.email}
  forensicWatermark={true}
/>

Forensic extraction — identify a leaker

If a leak surfaces, send any watermarked .ts segment to the extraction endpoint. The server reads the gv-wm: metadata comment embedded in the segment and returns the viewer fingerprint.

extract.sh
curl -X POST https://api.guardvid.com/videos/watermark/extract \
  -H "x-api-key: YOUR_API_KEY" \
  -F "segment=@leaked_segment.ts"

# Response:
# { "watermarkText": "John Doe | john@example.com", "tokenId": "abc-123" }

Plan requirement

Forensic watermarking is available on the Pro plan and above. Enabling it on a Free plan token returns a 403 Forbidden response.

Player API

Programmatic control via a forwarded ref on the component, or directly from the hook's return value.

MethodReturnsDescription
play()Promise<void>Start playback. Returns a promise that resolves once playback begins.
pause()voidPause the video.
seek(time)voidJump to the specified position in seconds.
getCurrentTime()numberReturns current playback position in seconds.
getDuration()numberReturns total video duration in seconds.
getVolume()numberReturns current volume (0–1).
setVolume(vol)voidSet volume. Value is clamped to 0–1.
getQualityLevels()QualityLevel[]Returns all available HLS quality levels.
getCurrentQuality()QualityLevel | nullReturns the currently active quality level.
setQuality(index)voidSwitch to a quality level by its numeric index.
getState()PlayerStateReturns current state: idle | loading | playing | paused | ended | error.
destroy()voidTear down the player instance and release all resources.

Configuration Reference

All props accepted by GuardVideoPlayer and useGuardVideoPlayer.

PropTypeDefaultDescription
videoIdstringrequiredThe unique ID of the video to load.
embedTokenEndpointstringrequiredBackend endpoint that issues signed viewer tokens.
apiBaseUrlstring''Base URL for additional SDK API calls.
autoplaybooleanfalseStart playback automatically on mount.
controlsbooleantrueShow the native video control bar.
debugbooleanfalseEnable verbose SDK debug logging.
brandingBrandingConfigGuardVideo defaultsContext-menu branding: name, url, logoUrl, accentColor.
contextMenuItemsContextMenuItem[][]Extra items appended to the branded context menu.
securitySecurityConfigsee SecurityConfigAll anti-piracy protection flags and values.
hlsConfigPartial<HlsConfig>{}Pass-through config forwarded to the HLS.js instance.
viewerNamestringViewer display name forwarded to the embed-token endpoint for forensic watermark personalisation.
viewerEmailstringViewer email forwarded to the embed-token endpoint. Combined with viewerName to build the burn-in fingerprint.
forensicWatermarkbooleanfalseRequest server-side forensic watermark burn-in. Each HLS segment is watermarked on first playback request.
onReady() => voidFires when the player finishes initialising.
onError(err: PlayerError) => voidFires on any unrecoverable player error.
onStateChange(state: PlayerState) => voidFires whenever the player state changes.
onQualityChange(q: QualityLevel) => voidFires when the active HLS quality level changes.
onTimeUpdate(time: number) => voidFires on each timeupdate event. React only.
onEnded() => voidFires when playback reaches the end. React only.

Full Examples

Production-ready, copy-paste examples for common integration setups.

Next.js App Router — Full-featured

Uses a forwarded ref for imperative playback control alongside all major config options.

app/watch/[id]/page.tsx
'use client';

import { useRef } from 'react';
import { GuardVideoPlayer, GuardVideoPlayerRef } from '@guardvideo/player-sdk';

export default function WatchPage({ params }: { params: { id: string } }) {
  const playerRef = useRef<GuardVideoPlayerRef>(null);

  return (
    <div className="max-w-4xl mx-auto p-4">
      <GuardVideoPlayer
        ref={playerRef}
        videoId={params.id}
        embedTokenEndpoint={process.env.NEXT_PUBLIC_API_URL + '/embed-tokens'}
        width="100%"
        height="auto"
        controls
        autoplay={false}
        branding={{
          name: 'MyBrand',
          url: 'https://mybrand.com',
          accentColor: '#6366f1',
        }}
        contextMenuItems={[
          { label: 'Report Issue', onClick: () => alert('Report'), separator: true },
          { label: 'Visit Website', href: 'https://mybrand.com' },
        ]}
        security={{
          disableSelection: true,
          disableDrag: true,
          enableWatermark: true,
          watermarkText: 'user@example.com',
          disablePiP: true,
          blockDevTools: true,
          maxPlaybackRate: 2,
          allowedDomains: ['https://mybrand.com'],
        }}
        onReady={() => console.log('Ready')}
        onError={(err) => console.error(err)}
        onStateChange={(s) => console.log('State:', s)}
      />

      <div className="mt-4 flex gap-2">
        <button onClick={() => playerRef.current?.play()}>Play</button>
        <button onClick={() => playerRef.current?.pause()}>Pause</button>
      </div>
    </div>
  );
}

Vanilla JS — Standalone HTML page

Zero build tools. Drop this file on any static host or CMS.

player.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Video Player</title>
  <style>
    body { margin: 0; background: #000; display: flex; justify-content: center; align-items: center; min-height: 100vh; }
    #player { width: 100%; max-width: 960px; aspect-ratio: 16 / 9; }
  </style>
</head>
<body>
  <div id="player"></div>
  <script src="https://cdn.guardvid.com/sdk/guardvideo-player.iife.js"></script>
  <script>
    const player = GuardVideoPlayer.create('player', 'VIDEO_ID_HERE', {
      embedTokenEndpoint: 'https://api.guardvid.com/embed-tokens',
      controls: true,
      branding: { name: 'GuardVideo', accentColor: '#44c09b' },
      security: {
        enableWatermark: true,
        watermarkText: window.userEmail || 'anonymous',
        disablePiP: true,
        blockDevTools: true,
        maxPlaybackRate: 2,
      },
      onReady() { console.log('Player is ready'); },
      onError(err) { console.error('Player error:', err); },
    });
  </script>
</body>
</html>