Skip to content

DRM

Widevine (Chrome/Firefox/Edge), FairPlay (Safari/iOS), PlayReady (Edge/Smart TV), and ClearKey (development/testing) support. The plugin detects the browser's key system automatically.

Install

No additional dependencies. Works standalone for encrypted MP4 or alongside HLS/DASH plugins for streaming.

Usage

Encrypted MP4 (standalone)

ts
import { createPlayer } from "@videts/vide";
import { drm } from "@videts/vide/drm";

const player = createPlayer(document.querySelector("video")!);
player.use(drm({
  widevine: {
    licenseUrl: "https://license.example.com/widevine",
  },
  fairplay: {
    licenseUrl: "https://license.example.com/fairplay",
    certificateUrl: "https://certificate.example.com/fairplay.cer",
  },
}));

player.src = "https://example.com/encrypted-video.mp4";

The plugin handles the full EME lifecycle internally — no HLS or DASH plugin required.

With HLS / DASH streaming

ts
import { createPlayer } from "@videts/vide";
import { hls } from "@videts/vide/hls";
import { drm } from "@videts/vide/drm";

const player = createPlayer(document.querySelector("video")!);
player.use(hls());
player.use(drm({
  widevine: {
    licenseUrl: "https://license.example.com/widevine",
  },
}));

player.src = "https://example.com/encrypted-stream.m3u8";

When an HLS or DASH plugin is active, DRM bridges its config via pluginData. Plugin order doesn't matter. The standalone EME handler detects that hls.js/dash.js has set mediaKeys and defers to it automatically.

PlayReady

ts
player.use(drm({
  playready: {
    licenseUrl: "https://license.example.com/playready",
    robustness: "2000",
  },
}));

ClearKey (development)

ts
player.use(drm({
  clearkey: {
    keys: {
      "base64url-key-id": "base64url-key-value",
    },
  },
}));

ClearKey requires no license server — keys are provided directly.

Options

OptionTypeDescription
widevineWidevineConfigWidevine DRM configuration
fairplayFairPlayConfigFairPlay DRM configuration
playreadyPlayReadyConfigPlayReady DRM configuration
clearkeyClearKeyConfigClearKey configuration (no license server)

WidevineConfig

FieldTypeDescription
licenseUrlstringLicense server URL (required)
certificateUrlstringServer certificate URL. Avoids an extra round-trip
headersRecord<string, string>Custom headers for license requests
robustnessstringRobustness level (e.g. "SW_SECURE_CRYPTO", "HW_SECURE_DECODE")
encryptionScheme"cenc" | "cbcs" | "cbcs-1-9"Encryption scheme
retryDrmRetryConfigRetry configuration for license/certificate requests
prepareLicenseRequest(payload: Uint8Array) => Uint8Array | Promise<Uint8Array>Transform license request payload
processLicenseResponse(response: Uint8Array) => Uint8Array | Promise<Uint8Array>Transform license response

FairPlayConfig

FieldTypeDescription
licenseUrlstringLicense server URL (required)
certificateUrlstringFairPlay certificate URL (required)
headersRecord<string, string>Custom headers for license requests
encryptionScheme"cenc" | "cbcs" | "cbcs-1-9"Encryption scheme (FairPlay typically uses "cbcs")
retryDrmRetryConfigRetry configuration for license/certificate requests
transformInitData(initData: Uint8Array, initDataType: string) => Uint8Array | Promise<Uint8Array>Transform init data before generateRequest(). Used for vendor-specific content ID extraction
prepareLicenseRequest(payload: Uint8Array) => Uint8Array | Promise<Uint8Array>Transform license request payload
processLicenseResponse(response: Uint8Array) => Uint8Array | Promise<Uint8Array>Transform license response

PlayReadyConfig

FieldTypeDescription
licenseUrlstringLicense server URL (required)
headersRecord<string, string>Custom headers for license requests
robustnessstringRobustness level (e.g. "150", "2000", "3000")
encryptionScheme"cenc" | "cbcs" | "cbcs-1-9"Encryption scheme
retryDrmRetryConfigRetry configuration for license requests
prepareLicenseRequest(payload: Uint8Array) => Uint8Array | Promise<Uint8Array>Transform license request payload
processLicenseResponse(response: Uint8Array) => Uint8Array | Promise<Uint8Array>Transform license response

ClearKeyConfig

FieldTypeDescription
keysRecord<string, string>Map of key IDs to keys, both as base64url-encoded strings (required)

DrmRetryConfig

FieldTypeDefaultDescription
maxAttemptsnumber1Maximum number of retry attempts
delayMsnumber1000Base delay between retries (ms)
backoffnumber2Exponential backoff multiplier (delayMs × backoff^attempt)

Events

EventPayloadDescription
drm:ready{ keySystem: KeySystem }DRM initialized successfully
drm:keystatus{ keyId: string, status: MediaKeyStatus }Key status changed
ts
player.on("drm:ready", ({ keySystem }) => {
  console.log(`DRM initialized with: ${keySystem}`);
});

player.on("drm:keystatus", ({ keyId, status }) => {
  console.log(`Key ${keyId}: ${status}`);
});

Error handling

DRM errors are emitted as error events with source: "drm" and a numeric code:

CodeConstantDescription
4000ERR_DRM_UNSUPPORTEDNo supported key system found
4001ERR_DRM_DETECTIONKey system detection failed
4002ERR_DRM_LICENSELicense request/exchange failed
4003ERR_DRM_CERTIFICATECertificate fetch failed
4004ERR_DRM_KEY_STATUSKey status error (expired or internal-error)
ts
import { ERR_DRM_UNSUPPORTED } from "@videts/vide/drm";

player.on("error", (e) => {
  if (e.source === "drm") console.error(`DRM error ${e.code}: ${e.message}`);
});

Standalone utilities

detectKeySystem

Detect the first supported key system from a list of candidates. Supports plain strings or objects with robustness/encryption scheme.

ts
import { detectKeySystem } from "@videts/vide/drm";

const keySystem = await detectKeySystem([
  { keySystem: "com.widevine.alpha", robustness: "HW_SECURE_DECODE" },
  { keySystem: "com.apple.fps.1_0" },
  "com.microsoft.playready",
]);

queryDrmSupport

Query support for multiple key systems at once.

ts
import { queryDrmSupport } from "@videts/vide/drm";

const support = await queryDrmSupport([
  "com.widevine.alpha",
  "com.apple.fps.1_0",
  "com.microsoft.playready",
  "org.w3.clearkey",
]);

support.forEach((supported, ks) => {
  console.log(`${ks}: ${supported}`);
});

Notes

  • The plugin uses EME (Encrypted Media Extensions) to detect the browser's supported key system.
  • Standalone EME handles encrypted MP4 directly. When hls.js or dash.js is active, DRM defers to the streaming library.
  • Widevine: Chrome, Firefox, Edge. FairPlay: Safari, iOS Safari. PlayReady: Edge, Smart TVs. ClearKey: all modern browsers.
  • Custom headers are useful for auth tokens on license requests.
  • Server certificates (Widevine optional, FairPlay required) reduce round-trips by avoiding individualization requests.
  • License and certificate requests use exponential backoff when retry is configured.

Common Issues

"No supported key system found" — Error code 4000. Check that your DRM configuration matches the browser. Widevine works on Chrome/Firefox/Edge, FairPlay on Safari, PlayReady on Edge. Use detectKeySystem() to check at runtime.

License request fails — Error code 4002. Verify the license URL, check CORS headers on the license server, and ensure any required auth headers are set via the headers option.

FairPlay certificate error — Error code 4003. FairPlay requires a valid certificateUrl. Unlike Widevine, the certificate is mandatory.

See Troubleshooting for more.