Host Config & Security

Configure the permission model, action gating, plugin security, and content restrictions for the MP4E player.

Overview

MP4E uses a three-tier permission model that follows an intersection pattern: each layer can only restrict, never expand, what the previous layer allows. This ensures that no single party (creator, host, or viewer) can override the restrictions of another.

TierSourceControls
1. Creator Restrictionsmetadata.settings.restrictionsAuthor-declared limits embedded in the .mp4e file (e.g., sequential playback, blocked actions). Enforced by the engine even without host config.
2. Host Configconfig React propSandbox actions, disable overlays/layers/plugins/rules, gate actions for approval, plugin security rules.
3. Viewer PreferencessetViewerPreferences() at runtimePrivacy (doNotTrack, doNotShareIdentity, limitStorage) and accessibility (reducedMotion, highContrast). The viewer always has final say.
Three-tier permission model
// Three-tier permission model
// Each layer can only RESTRICT, never expand permissions.

// Tier 1: Creator restrictions (embedded in the .mp4e file)
metadata.settings.restrictions = {
  sequential: true,       // No seeking forward
  actions: { download: false }
};

// Tier 2: Host config (React prop)
<MP4EPlayer
  config={{
    sandbox: { actions: { openUrl: false } },
    gated: ['navigate'],
    disabled: { layers: ['debug-layer'] }
  }}
/>

// Tier 3: Viewer preferences (runtime, from player menu)
engine.setViewerPreferences({
  doNotTrack: true,
  reducedMotion: true
});
Intersection Model
If the creator blocks download and the host blocks openUrl, then both are blocked at runtime. Neither party can re-enable what the other has restricted.

MP4EConfig Reference

The config prop accepts an MP4EConfig object. It is passed to the WASM engine via setConfig() after setMetadata().

Sandbox

Block specific action types globally. Actions not listed are allowed by default.

PropTypeDefaultDescription
sandbox.actionsRecord<string, boolean>-Block or allow specific action types. Keys are action type strings (e.g. "openUrl", "navigate"). Values: true = allowed, false = blocked. Any action type not listed is allowed by default (default-open model). Applies to every execution path, including viewer playback controls — sandboxing "pause" blocks pause regardless of whether a rule, a plugin, or the viewer requested it. A plugin's mp4e.openUrl counts as the "openUrl" action. Independently of this setting, openUrl and navigate open only http:, https:, mailto: and tel: URLs, and relative URLs resolved against the host page; any other URL is refused before it reaches gating.

Disabled Content

Suppress specific creator content by ID. Disabled items are silently removed from the engine's working set.

PropTypeDefaultDescription
disabled.overlaysstring[]-Array of overlay IDs to suppress. Matching overlays will not render.
disabled.pluginsstring[]-Array of plugin IDs (namespace:identifier, e.g. "mp4e:shopping-cart") to suppress. A disabled plugin is never created (no service, controls, or menu instance), overlays whose type is that plugin are not rendered, and its plugin API calls are refused with an error. Takes effect for API calls immediately; overlay filtering applies when metadata loads.
disabled.layersstring[]-Array of layer IDs to suppress. All overlays within matching layers are hidden.
disabled.rulesstring[]-Array of rule IDs to suppress. Matching rules will not be evaluated or executed.
disabled.actionTypesstring[]-Array of action type strings to suppress globally. Any action of a matching type will be silently dropped.

Action Gating

Require host approval before executing certain action types. The engine pauses the action and invokes the onActionGate callback.

PropTypeDefaultDescription
gatedstring[]-Action types that require host approval before execution. When an action of a listed type fires, the engine pauses it and invokes the onActionGate callback. The host must call resolve(true) to allow or resolve(false) to deny.
gateTimeoutMsnumber5000How long (in milliseconds) the engine waits for the host to call resolve() on a gated action before applying the timeout policy.
gateTimeoutPolicy'allow' | 'deny''deny'What happens when the gate timeout expires without a resolve() call. "allow" lets the action proceed; "deny" silently drops it.

Engine Source

A file can carry its own signed engine. The player prefers the embedded engine and falls back to the bundled engine, so playback always works. These options control that choice.

PropTypeDefaultDescription
engineSource'auto' | 'embedded' | 'bundled''auto'Which engine runs when a file carries its own embedded engine. 'auto' prefers the file's embedded engine and falls back to the bundled engine if it is missing or fails verification. 'embedded' forces the file's engine when present (still falling back on failure). 'bundled' always uses the bundled engine and ignores any embedded one.
minEngineVersionstring-Reject an embedded engine below this version. A file whose embedded engine is older falls back to the bundled engine.
revokedEngineVersionsstring[]-Embedded engine versions to reject. A file whose embedded engine matches a listed version falls back to the bundled engine.

The player emits an engine:source event on each resolution so you can see which engine ran:

Observe which engine ran
engine.on('engine:source', ({ source, version, reason }) => {
  // source:  'embedded' | 'bundled'
  // version: the embedded engine's version when source === 'embedded', else null
  // reason:  'preferred' | 'no-embedded-atom' | 'verification-failed' | 'sha256-mismatch'
  //        | 'below-floor' | 'revoked' | 'host-forced-bundled' | 'abi-unsupported'
  //        | 'decompression-failed'
})
Readable source required
Using a file's embedded engine requires a CORS-readable video source — the player must be able to read the file's data. Cross-origin sources without CORS fall back to the bundled engine.

Plugin Security

Control network access, sandbox level, and signer requirements per plugin or group of plugins using wildcard patterns.

PropTypeDefaultDescription
pluginSecurityRecord<string, PluginSecurityRule>-Plugin security rules keyed by wildcard pattern. Patterns match plugin namespace:identifier format. Controls network access, sandbox level, and signer requirements per plugin or group of plugins. If set but no "*" key is provided, the implicit default is "none" (block all). If not set, every plugin runs at the "connected" sandbox level — isolated from the host page, with no same-origin access — with unrestricted network access. Set trustContent to opt in to the "trusted" level.
networkGateTimeoutMsnumber5000How long (in milliseconds) to wait for the host to resolve a network gate request before applying the timeout policy.
networkGateTimeoutPolicy'allow' | 'deny''deny'What happens when the network gate timeout expires. "allow" permits the request; "deny" blocks it.

Trust & Signing

Shortcuts for self-hosted deployments and plugin signature verification.

PropTypeDefaultDescription
trustContentbooleanfalseExplicit opt-in to the "trusted" sandbox level. When true, every plugin receives allow-same-origin (full access to the host page and to other plugins) regardless of other pluginSecurity rules. Plugins are isolated unless you set this. Use only for self-hosted deployments where you control all content.
trustedSignersRecord<string, string | true>-Trusted signers for plugin signature verification. Keys are signer names, values are base64-encoded Ed25519 public keys. The special value true for the key "mp4e" uses the built-in MP4E public key. While you trust at least one signer, a plugin whose signature does not verify (tampered content, or a signer you do not trust) runs at the "contained" level with no network access, whatever rule it matches.

Playback Path

Play only the scenes of one scene group, as a single continuous timeline. See setPlaybackPath on the Player Methods page.

PropTypeDefaultDescription
playbackPathstring-Force a playback path — the scene group id to play. Applied when set or changed (and on every metadata load); removing it from the config clears the path. A config update that keeps the same value leaves a plugin-chosen path in place; set lockPlaybackPath to keep plugins from changing it at all.
lockPlaybackPathbooleanfalseOnly the host can change the playback path. Plugin and rule calls to setPlaybackPath/clearPlaybackPath are refused with error code "playbackPath.locked"; host dispatch still works.

Intelligence

Plugins can read an analysed video's Intelligence — chapters, key moments, things, people, the transcript — with mp4e.getIntelligence() (see Intelligence in the plugin API). What a plugin receives is what its manifest requests, the creator granted and you allow. Set this with the initial config, before plugins load.

PropTypeDefaultDescription
permissions.intelligencestring[]no limitThe Intelligence scopes plugins may read on your site: summary, chapters, moments, questions, things, scenes, people, transcript. An allow-list that only narrows — a plugin still gets a scope only when its manifest requests it and the creator granted it. [] lets no plugin read any. A scope you leave out is reported to the plugin as withheld with reason "host". A value that is not a list lets no plugin read any scope.
Per-plugin grants hold by default
permissions.intelligence applies to every plugin, and the creator's per-plugin grants keep plugins apart because plugins are isolated from the host page and from each other by default. They stop doing so for plugins you raise to the trusted level — with trustContent or a pluginSecurity rule — since trusted plugins can reach each other's windows.
Let plugins read chapters and key moments only
<MP4EPlayer
  src="/video.mp4"
  config={{
    permissions: { intelligence: ['chapters', 'moments'] },
  }}
/>

Action Gating

Action gating lets the host intercept specific action types before they execute. This is useful for confirming navigation, preventing unwanted URL opens, or logging action execution. The flow is:

  1. A rule or plugin triggers a gated action (e.g., openUrl)
  2. The engine pauses execution and invokes onActionGate(action, resolve)
  3. The host inspects the action and calls resolve(true) to allow or resolve(false) to deny
  4. If the host does not respond within gateTimeoutMs, the gateTimeoutPolicy applies
Action gating example
import { MP4EPlayer } from '@mp4e/react';
import '@mp4e/react/styles.css';

function SecurePlayer() {
  return (
    <MP4EPlayer
      src="/video.mp4"
      config={{
        gated: ['openUrl', 'navigate'],
        gateTimeoutMs: 10000,
        gateTimeoutPolicy: 'deny',
      }}
      onActionGate={(action, resolve) => {
        if (action.type === 'openUrl') {
          // Show a confirmation dialog before opening external URLs
          const approved = window.confirm(
            `This video wants to open: ${action.params.url}\nAllow?`
          );
          resolve(approved);
        } else if (action.type === 'navigate') {
          // Always allow in-app navigation
          resolve(true);
        } else {
          // Deny unknown gated actions
          resolve(false);
        }
      }}
    />
  );
}
Timeout Behavior
If the host never calls resolve(), the action is automatically denied (or allowed) after gateTimeoutMs based on the gateTimeoutPolicy. The default policy is "deny" (fail-closed).

Network Gating

When a plugin uses mp4e.fetch() to request a domain not in its allowed list, the onNetworkGate callback fires. This gives the host final say over which external requests plugins can make.

Network gating example
<MP4EPlayer
  src="/video.mp4"
  config={{
    networkGateTimeoutMs: 3000,
    networkGateTimeoutPolicy: 'deny',
  }}
  onNetworkGate={(request, resolve) => {
    // Only allow requests to your own domains
    const allowed = ['api.mysite.com', 'cdn.mysite.com'];
    const url = new URL(request.url);

    console.log(
      `Plugin ${request.pluginId} requesting ${request.method} ${request.url}`
    );

    resolve(allowed.includes(url.hostname));
  }}
/>

The callback receives the requesting plugin's ID, the full URL, and the HTTP method. Call resolve(true) to allow or resolve(false) to block the request. If the host does not respond within networkGateTimeoutMs, the networkGateTimeoutPolicy applies.

Plugin Security Rules

The pluginSecurity config field maps wildcard patterns to security rules. Patterns are matched against the namespace:identifier of each plugin.

PatternMatchesExample
'*'All plugins (global default)Baseline security for every plugin
'mp4e:*'All plugins in the mp4e namespaceOfficial MP4E plugins
'stripe:checkout'Exact plugin matchSpecific plugin elevated access
'!badguy:*'Deny rule (overrides positive matches at equal or lower specificity)Block an entire namespace
Isolated by default
With no pluginSecurity, plugins run at the connected level: isolated from the host page and from each other, with the bridge's storage and fetch available and network access unrestricted. A rule's sandbox picks a different level for the plugins it matches; set trustContent to raise every plugin to trusted.
Implicit Default
If pluginSecurity is set but does not include a '*' key, the implicit default is "none" (all plugins blocked). Always include a '*' entry as your baseline.

PluginSecurityRule Type

PluginSecurityRule
interface PluginSecurityRule {
  /**
   * Network access policy:
   * - 'none': Block all network access
   * - 'manifest': Allow only domains declared in plugin manifest
   * - 'any': Unrestricted (dangerous, explicit opt-in only)
   * - string[]: Explicit domain allowlist (replaces manifest)
   * Applies to mp4e.fetch and, through the plugin frame's Content
   * Security Policy, to the plugin's own requests: fetch, XMLHttpRequest
   * and WebSocket connections, images and form posts may reach only the
   * listed domains (none for 'none'). Under 'none', 'manifest' or a domain
   * list, scripts and styles must be inline in the plugin — external
   * scripts and stylesheets do not load, even from a listed domain.
   */
  network?: 'none' | 'manifest' | 'any' | string[];

  /**
   * Sandbox level controlling iframe capabilities:
   * - 'contained': allow-scripts, allow-forms only (NO same-origin)
   * - 'connected': the default when no pluginSecurity is set (the iframe
   *   is isolated; use mp4e.storage / mp4e.fetch)
   * - 'trusted': + allow-same-origin (full host page access)
   */
  sandbox?: 'contained' | 'connected' | 'trusted';

  /**
   * Required signer name. The rule applies only to a plugin signed by this
   * signer (checked against trustedSigners). An unsigned plugin, a plugin
   * signed by a different trusted signer, or a host with no trustedSigners
   * gets the 'contained' level and no network access instead.
   */
  signer?: string;
}

Full Example

Plugin security configuration
<MP4EPlayer
  src="/video.mp4"
  config={{
    pluginSecurity: {
      // Global default: contained sandbox, no network
      '*': {
        sandbox: 'contained',
        network: 'none',
      },

      // Official MP4E plugins: connected sandbox, manifest-declared domains
      'mp4e:*': {
        sandbox: 'connected',
        network: 'manifest',
        signer: 'mp4e',
      },

      // Stripe plugins: connected sandbox, explicit domain allowlist
      'stripe:*': {
        sandbox: 'connected',
        network: ['js.stripe.com', 'api.stripe.com'],
      },

      // Specific trusted plugin: full access
      'stripe:checkout': {
        sandbox: 'trusted',
        network: 'any',
      },

      // Block a known-bad namespace entirely
      '!badguy:*': {
        sandbox: 'contained',
        network: 'none',
      },
    },
  }}
/>

Content Restrictions

Content restrictions are creator-declared and embedded in metadata.settings.restrictions. They are the first tier of the permission model and are enforced by the engine even when no host config is provided. Think of them like SCORM sequencing rules.

MP4ERestrictions

PropTypeDefaultDescription
actionsRecord<string, boolean>-Action types the creator wants blocked. Same shape as config.sandbox.actions. Blocked actions are silently dropped by the engine.
sequentialbooleanfalseForce linear playback. When true, the viewer cannot seek forward past the furthest-watched point. Similar to SCORM's forwardOnly mode.
Restrictions in metadata
// Creator embeds restrictions in the video metadata
// These are enforced by the engine regardless of host config

{
  "settings": {
    "restrictions": {
      "sequential": true,
      "actions": {
        "download": false,
        "openUrl": false
      }
    }
  }
}
Sequential Playback
When sequential is enabled, the engine tracks the furthest-watched point and prevents seeking beyond it. This is commonly used for e-learning and compliance training videos where linear completion is required.

Security Violations

The onSecurityViolation callback fires when a plugin attempts a blocked network request (CSP violation). Use it for monitoring and alerting.

Security violation handler
<MP4EPlayer
  src="/video.mp4"
  onSecurityViolation={(violation) => {
    console.error(
      `Security violation by plugin ${violation.pluginId}:\n` +
      `  Blocked URI: ${violation.blockedURI}\n` +
      `  Violated directive: ${violation.violatedDirective}`
    );

    // Report to your monitoring service
    analytics.track('security_violation', {
      pluginId: violation.pluginId,
      blockedURI: violation.blockedURI,
      directive: violation.violatedDirective,
    });
  }}
/>
FieldTypeDescription
pluginIdstringThe ID of the plugin that triggered the violation.
blockedURIstringThe URI that was blocked by the Content Security Policy.
violatedDirectivestringThe CSP directive that was violated (e.g., "connect-src", "script-src").

Interactive Tool

Host Config Generator
The MP4E Studio includes an interactive Host Config Generator that lets you visually build your MP4EConfig object. Select action types to sandbox, choose plugins to disable, configure gating policies, and set up plugin security rules -- then copy the generated config directly into your code.

Full Production Example

Putting it all together -- a production-ready player with sandbox rules, action gating, plugin security, and violation monitoring:

Production player with full config
import { MP4EPlayer } from '@mp4e/react';
import '@mp4e/react/styles.css';

function ProductionPlayer({ videoUrl }: { videoUrl: string }) {
  return (
    <MP4EPlayer
      src={videoUrl}
      config={{
        // Block dangerous actions entirely
        sandbox: {
          actions: {
            download: false,
            openUrl: false,
          },
        },

        // Require approval for navigation
        gated: ['navigate', 'goToScene'],
        gateTimeoutMs: 8000,
        gateTimeoutPolicy: 'deny',

        // Disable specific creator content
        disabled: {
          layers: ['debug-layer'],
          actionTypes: ['console'],
        },

        // Plugin security per namespace
        pluginSecurity: {
          '*': { sandbox: 'contained', network: 'none' },
          'mp4e:*': { sandbox: 'connected', network: 'manifest' },
          'stripe:checkout': { sandbox: 'trusted', network: 'any' },
        },

        // Trust official MP4E signatures
        trustedSigners: { mp4e: true },
      }}

      // Gate callbacks
      onActionGate={(action, resolve) => {
        resolve(window.confirm(`Allow action: ${action.type}?`));
      }}
      onNetworkGate={(req, resolve) => {
        const trusted = ['api.mysite.com', 'cdn.mysite.com'];
        resolve(trusted.includes(new URL(req.url).hostname));
      }}
      onSecurityViolation={(v) => {
        console.error('Security violation:', v);
      }}
    />
  );
}