Skip to main content
The @react-native-video/drm package provides official DRM (Digital Rights Management) support for React Native Video through the plugin system. It enables playback of protected content using Widevine on Android and FairPlay on iOS/visionOS.

Overview

The DRM plugin integrates seamlessly with React Native Video’s plugin architecture to provide:
  • Widevine DRM for Android via ExoPlayer
  • FairPlay DRM for iOS and visionOS via AVFoundation
  • Simple API - Enable once, configure per-source
  • Nitro Modules - High-performance native integration
  • Automatic registration - No manual native code changes required
DRM is not supported on the iOS Simulator. Always test DRM playback on physical devices.

Installation

1

Install packages

Install the DRM plugin along with required dependencies:
npm install @react-native-video/drm react-native-video react-native-nitro-modules
Or with yarn:
yarn add @react-native-video/drm react-native-video react-native-nitro-modules
2

Install iOS dependencies

For iOS, install CocoaPods dependencies:
npx pod-install
# or
cd ios && pod install
3

Rebuild your app

Rebuild your app to link the native modules:
# iOS
npx react-native run-ios

# Android
npx react-native run-android

Requirements

  • react-native-video >= 7.0.0-alpha.3
  • react-native-nitro-modules >= 0.27.2
  • React Native >= 0.70

Expo Support

The DRM plugin uses Nitro Modules and requires native code compilation. Use a prebuild workflow - pure managed Expo apps are not supported.
# Generate native folders
npx expo prebuild

# Run with custom dev client
npx expo run:ios
npx expo run:android

Quick Start

Enable the plugin once at app startup, then pass DRM configuration to your video sources.
import React from 'react';
import { Platform } from 'react-native';
import { VideoView, useVideoPlayer } from 'react-native-video';
import { enable } from '@react-native-video/drm';

// Enable the DRM plugin at app startup
enable();

export default function DRMPlayer() {
  const player = useVideoPlayer({
    uri: 'https://example.com/protected-stream.m3u8',
    headers: { Authorization: 'Bearer <token>' },
    drm: {
      type: Platform.select({ ios: 'fairplay', default: 'widevine' }),
      licenseUrl: 'https://license.example.com/license',
      
      // iOS-specific (FairPlay)
      certificateUrl: Platform.OS === 'ios' 
        ? 'https://license.example.com/fps.cer' 
        : undefined,
    },
  });

  return <VideoView player={player} style={{ flex: 1 }} />;
}

API Reference

Plugin Methods

Imported from @react-native-video/drm:

enable()

Registers the DRM plugin with React Native Video.
function enable(): void
Usage:
import { enable } from '@react-native-video/drm';

// Call once at app startup (e.g., in App.tsx or index.js)
enable();
Android requires calling enable() before playing DRM content. iOS attempts auto-enable but calling is safe and recommended.

disable()

Unregisters the DRM plugin.
function disable(): void
Usage:
import { disable } from '@react-native-video/drm';

// Cleanup when DRM is no longer needed
disable();

isEnabled

Boolean indicating current plugin registration status.
const isEnabled: boolean
Usage:
import { isEnabled } from '@react-native-video/drm';

if (isEnabled) {
  console.log('DRM plugin is active');
}

DRM Configuration

Pass these options via the drm property in useVideoPlayer() or Video component:

Common Options

PropertyTypeDescription
type'widevine' | 'fairplay' | stringDRM system type. Defaults: Android → widevine, iOS/visionOS → fairplay
licenseUrlstringLicense server URL (required for default flows)

Android-Specific (Widevine)

PropertyTypeDescription
licenseHeadersRecord<string, string>Custom headers for license requests
multiSessionbooleanAllow multiple DRM sessions (default: false)

iOS-Specific (FairPlay)

PropertyTypeDescription
certificateUrlstringFairPlay application certificate URL (required)
contentIdstringContent identifier. Auto-inferred from skd:// URL if not provided
getLicense(payload) => Promise<string>Custom license fetch function (advanced)

Platform-Specific Guides

Android (Widevine)

Widevine DRM is handled through ExoPlayer’s Media3 framework.
1

Enable the plugin

import { enable } from '@react-native-video/drm';
enable();
2

Configure DRM source

const player = useVideoPlayer({
  uri: 'https://example.com/video.mpd', // DASH manifest
  drm: {
    type: 'widevine',
    licenseUrl: 'https://license.server.com/widevine',
    licenseHeaders: {
      'X-Custom-Header': 'value',
      'Authorization': 'Bearer token',
    },
    multiSession: true, // Optional: enable multi-session
  },
});
3

Test on device

Run on a physical device or emulator:
npx react-native run-android
Example: Widevine with Custom Headers
import { enable } from '@react-native-video/drm';
import { useVideoPlayer, VideoView } from 'react-native-video';

enable();

function WidevinePlayer() {
  const player = useVideoPlayer({
    uri: 'https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears.mpd',
    drm: {
      type: 'widevine',
      licenseUrl: 'https://proxy.uat.widevine.com/proxy',
      licenseHeaders: {
        'Content-Type': 'application/octet-stream',
      },
    },
  });
  
  return <VideoView player={player} style={{ flex: 1 }} />;
}

iOS (FairPlay)

FairPlay DRM uses Apple’s AVFoundation framework and requires an application certificate.
FairPlay is not available on the iOS Simulator. Test on a real iPhone, iPad, or Apple Vision Pro.
1

Enable the plugin

import { enable } from '@react-native-video/drm';
enable();
2

Configure FairPlay source

const player = useVideoPlayer({
  uri: 'https://example.com/video.m3u8', // HLS manifest
  headers: {
    Authorization: 'Bearer token', // Used for media AND license requests
  },
  drm: {
    type: 'fairplay',
    certificateUrl: 'https://license.server.com/fairplay.cer',
    licenseUrl: 'https://license.server.com/license',
    contentId: 'content-id-12345', // Optional: auto-inferred from skd://
  },
});
3

Test on device

Run on a physical iOS device:
npx react-native run-ios --device
Example: FairPlay with Default Flow
import { enable } from '@react-native-video/drm';
import { useVideoPlayer, VideoView } from 'react-native-video';

enable();

function FairPlayPlayer() {
  const player = useVideoPlayer({
    uri: 'https://example.com/stream.m3u8',
    headers: {
      'Authorization': 'Bearer eyJhbGc...', // Shared with license server
    },
    drm: {
      type: 'fairplay',
      certificateUrl: 'https://fps.example.com/cert.der',
      licenseUrl: 'https://fps.example.com/license',
      // contentId auto-inferred from skd:// URL in manifest
    },
  });
  
  return <VideoView player={player} style={{ flex: 1 }} />;
}
Example: FairPlay with Custom License Fetch
const player = useVideoPlayer({
  uri: 'https://example.com/stream.m3u8',
  drm: {
    type: 'fairplay',
    certificateUrl: 'https://fps.example.com/cert.der',
    getLicense: async ({ contentId, spc, licenseUrl, keyUrl }) => {
      // Custom license acquisition logic
      const response = await fetch('https://custom-license-server.com/acquire', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/octet-stream',
          'X-Content-Id': contentId,
        },
        body: spc, // Server Playback Context (base64)
      });
      
      const ckc = await response.text(); // Content Key Context (base64)
      return ckc;
    },
  },
});

visionOS (FairPlay)

FairPlay works the same on visionOS as iOS:
import { enable } from '@react-native-video/drm';
import { useVideoPlayer, VideoView } from 'react-native-video';

enable();

function VisionOSPlayer() {
  const player = useVideoPlayer({
    uri: 'https://example.com/spatial-video.m3u8',
    drm: {
      type: 'fairplay',
      certificateUrl: 'https://fps.example.com/cert.der',
      licenseUrl: 'https://fps.example.com/license',
    },
  });
  
  return <VideoView player={player} style={{ flex: 1 }} />;
}

Advanced Usage

Platform-Specific DRM Configuration

import { Platform } from 'react-native';
import { enable } from '@react-native-video/drm';
import { useVideoPlayer } from 'react-native-video';

enable();

function CrossPlatformDRM() {
  const player = useVideoPlayer({
    uri: Platform.select({
      ios: 'https://example.com/video.m3u8',      // HLS for iOS
      android: 'https://example.com/video.mpd',  // DASH for Android
    }),
    drm: Platform.select({
      ios: {
        type: 'fairplay',
        certificateUrl: 'https://fps.example.com/cert.der',
        licenseUrl: 'https://fps.example.com/license',
      },
      android: {
        type: 'widevine',
        licenseUrl: 'https://widevine.example.com/license',
        licenseHeaders: {
          'X-Custom-Data': 'android-specific-value',
        },
      },
    }),
  });
  
  return <VideoView player={player} style={{ flex: 1 }} />;
}

Conditional DRM Enable

import { enable, disable, isEnabled } from '@react-native-video/drm';
import { useEffect } from 'react';

function App() {
  const needsDRM = true; // From your app logic
  
  useEffect(() => {
    if (needsDRM && !isEnabled) {
      enable();
    } else if (!needsDRM && isEnabled) {
      disable();
    }
  }, [needsDRM]);
  
  return <YourApp />;
}

Troubleshooting

Symptoms: Error loading FairPlay certificateSolutions:
  • Verify certificateUrl is accessible and returns valid .cer or .der file
  • Check network connectivity and SSL certificates
  • Ensure the URL uses HTTPS
  • Test the URL in a browser or with curl:
    curl -v https://fps.example.com/cert.der
    
Symptoms: Video loads but playback fails with license errorSolutions:
  • iOS: Check that source.headers includes required authorization. The default flow uses these headers for license requests.
  • Android: Verify licenseHeaders contains all required headers
  • Confirm licenseUrl is correct and accessible
  • Test license server with curl or Postman
  • Check server logs for authentication or format errors
Symptoms: DRM playback fails on simulator but no errors shownSolution: FairPlay is not supported on the iOS Simulator. This is an Apple limitation. Always test DRM on physical devices:
npx react-native run-ios --device "John's iPhone"
Symptoms: Error: “Unsupported DRM type”Solutions:
  • Set drm.type to 'widevine' (Android) or 'fairplay' (iOS)
  • Or omit type to use platform defaults
  • Ensure you’re not trying to use Widevine on iOS or FairPlay on Android
Symptoms: DRM doesn’t work even after calling enable()Solutions:
  • Ensure @react-native-video/drm is installed: npm ls @react-native-video/drm
  • Rebuild the app after installation (don’t just reload)
  • Check that react-native-nitro-modules >= 0.27.2 is installed
  • On iOS, run npx pod-install after installing
  • Clear build caches:
    # iOS
    cd ios && rm -rf build Pods && pod install
    
    # Android
    cd android && ./gradlew clean
    
Symptoms: Multiple DRM videos fail to play simultaneouslySolution: Enable multi-session support:
drm: {
  type: 'widevine',
  licenseUrl: 'https://license.example.com/widevine',
  multiSession: true, // Enable multiple concurrent sessions
}

Implementation Details

The DRM plugin is implemented as a native plugin on both platforms:

Android Implementation

// packages/drm-plugin/android/src/main/java/com/twg/videodrm/DRMPlugin.kt
class DRMPlugin(name: String) : ReactNativeVideoPlugin(name) {
  override fun getDRMManager(source: NativeVideoPlayerSource): DRMManagerSpec? {
    return DRMManager(source)
  }
}
The plugin provides a DRMManager that integrates with ExoPlayer’s MediaDrm API for Widevine license acquisition.

iOS Implementation

// packages/drm-plugin/ios/DRMPlugin.swift
class DRMPlugin: ReactNativeVideoPlugin {
  override func getDRMManager(source: any NativeVideoPlayerSource) -> (any DRMManagerSpec)? {
    #if targetEnvironment(simulator)
      print("[ReactNativeVideoDRM] DRM is not supported on the simulator.")
      return nil
    #else
      return DRMManager(source: source)
    #endif
  }
}
The plugin provides a DRMManager that implements AVContentKeySessionDelegate for FairPlay license handling.

Nitro Modules Bridge

The JavaScript API uses Nitro Modules for high-performance native communication:
// packages/drm-plugin/src/index.tsx
import { NitroModules } from 'react-native-nitro-modules';
import type { PluginManager } from './PluginManager.nitro';

const PluginManager = NitroModules.createHybridObject<PluginManager>('PluginManager');

export function enable() {
  return PluginManager.enable();
}

export function disable() {
  return PluginManager.disable();
}

export const isEnabled: boolean = PluginManager.isEnabled;

Best Practices

Enable Early

Call enable() in your app’s entry point (App.tsx or index.js) before any video playback

Test on Devices

Always test DRM on physical devices - simulators don’t support FairPlay

Secure Credentials

Never hardcode license server credentials. Use secure storage or environment variables

Handle Errors

Implement proper error handling for license acquisition failures

Resources

License

MIT - See LICENSE for details.