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 hereInstall the SDK and have your first protected video running in under five minutes.
Requirements
Installation
# npm
npm install @guardvideo/player-sdk
# yarn
yarn add @guardvideo/player-sdk
# pnpm
pnpm add @guardvideo/player-sdkObtain 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
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.
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
GuardVideoPlayer as a global. Pin the CDN URL to a specific semver version in production to avoid unintended breaking changes from @latest.<!-- 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
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.
<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.
<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 3Server-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
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.
<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.
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
403 Forbidden response.Player API
Programmatic control via a forwarded ref on the component, or directly from the hook's return value.
| Method | Returns | Description |
|---|---|---|
| play() | Promise<void> | Start playback. Returns a promise that resolves once playback begins. |
| pause() | void | Pause the video. |
| seek(time) | void | Jump to the specified position in seconds. |
| getCurrentTime() | number | Returns current playback position in seconds. |
| getDuration() | number | Returns total video duration in seconds. |
| getVolume() | number | Returns current volume (0–1). |
| setVolume(vol) | void | Set volume. Value is clamped to 0–1. |
| getQualityLevels() | QualityLevel[] | Returns all available HLS quality levels. |
| getCurrentQuality() | QualityLevel | null | Returns the currently active quality level. |
| setQuality(index) | void | Switch to a quality level by its numeric index. |
| getState() | PlayerState | Returns current state: idle | loading | playing | paused | ended | error. |
| destroy() | void | Tear down the player instance and release all resources. |
Configuration Reference
All props accepted by GuardVideoPlayer and useGuardVideoPlayer.
| Prop | Type | Default | Description |
|---|---|---|---|
| videoId | string | required | The unique ID of the video to load. |
| embedTokenEndpoint | string | required | Backend endpoint that issues signed viewer tokens. |
| apiBaseUrl | string | '' | Base URL for additional SDK API calls. |
| autoplay | boolean | false | Start playback automatically on mount. |
| controls | boolean | true | Show the native video control bar. |
| debug | boolean | false | Enable verbose SDK debug logging. |
| branding | BrandingConfig | GuardVideo defaults | Context-menu branding: name, url, logoUrl, accentColor. |
| contextMenuItems | ContextMenuItem[] | [] | Extra items appended to the branded context menu. |
| security | SecurityConfig | see SecurityConfig | All anti-piracy protection flags and values. |
| hlsConfig | Partial<HlsConfig> | {} | Pass-through config forwarded to the HLS.js instance. |
| viewerName | string | — | Viewer display name forwarded to the embed-token endpoint for forensic watermark personalisation. |
| viewerEmail | string | — | Viewer email forwarded to the embed-token endpoint. Combined with viewerName to build the burn-in fingerprint. |
| forensicWatermark | boolean | false | Request server-side forensic watermark burn-in. Each HLS segment is watermarked on first playback request. |
| onReady | () => void | — | Fires when the player finishes initialising. |
| onError | (err: PlayerError) => void | — | Fires on any unrecoverable player error. |
| onStateChange | (state: PlayerState) => void | — | Fires whenever the player state changes. |
| onQualityChange | (q: QualityLevel) => void | — | Fires when the active HLS quality level changes. |
| onTimeUpdate | (time: number) => void | — | Fires on each timeupdate event. React only. |
| onEnded | () => void | — | Fires 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.
'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.
<!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>