Host Overrides
Inject layers, plugins, variables, and settings into any video at runtime without modifying the .mp4 file.
Overview
The overrides prop lets a host application deep-merge partial metadata into any MP4E video at runtime. The original .mp4 file is never modified — overrides are applied in memory by the player before the engine processes the metadata.
This keeps videos fully portable. The same video file plays identically on any host, while each host can layer its own branding, analytics, variables, restrictions, and rules on top.
How It Works
When the player loads metadata from the MP4 atom, it applies overrides using a deep-merge algorithm before passing the result to the WASM engine. The merge rules are:
| Data Shape | Merge Behavior |
|---|---|
| Record objects | Deep-merged recursively. Override keys win; base-only keys are preserved. |
| Arrays of { id } objects | Matched by id. If an override item has the same ID as a base item, the two are deep-merged. New IDs are appended to the end. |
| layers (special case) | ID-match merge with cascade: the overlays array within each matched layer is also ID-merged. |
| Plain arrays (no id) | Override replaces entirely. |
| Primitives | Override replaces entirely. |
The following example shows a full merge from base metadata through overrides to the final result:
1// Original metadata (embedded in the .mp4 file)2{3 settings: {4 restrictions: { navigate: true, download: true }5 },6 layers: [7 {8 id: 'layer-1',9 name: 'Products',10 overlays: [11 { id: 'overlay-a', type: 'core:button', config: { text: 'Buy' } }12 ]13 }14 ],15 variables: {16 score: { type: 'number', value: 0 }17 }18}1920// Overrides (provided by host at runtime)21{22 settings: {23 restrictions: { navigate: false }24 },25 layers: [26 {27 id: 'layer-1',28 overlays: [29 { id: 'overlay-a', config: { text: 'Purchase Now' } }30 ]31 },32 {33 id: '__host_brand__',34 name: 'Branding',35 overlays: [{ id: 'logo', type: 'core:image', config: { src: '/logo.png' } }]36 }37 ],38 variables: {39 userName: { type: 'text', value: 'Alice' }40 }41}4243// Result after merge44{45 settings: {46 restrictions: { navigate: false, download: true } // deep-merged: navigate overridden47 },48 layers: [49 {50 id: 'layer-1',51 name: 'Products', // preserved from base52 overlays: [53 { id: 'overlay-a', type: 'core:button', config: { text: 'Purchase Now' } }54 // ^ ID-matched, config overridden55 ]56 },57 {58 id: '__host_brand__', // new layer appended59 name: 'Branding',60 overlays: [{ id: 'logo', type: 'core:image', config: { src: '/logo.png' } }]61 }62 ],63 variables: {64 score: { type: 'number', value: 0 }, // preserved from base65 userName: { type: 'text', value: 'Alice' } // new key added66 }67}Override Structure
The overrides prop mirrors the MP4E metadata structure exactly. Any top-level metadata field can be overridden: layers, plugins, variables, settings, projectSettings, scenes, and more.
1<MP4EPlayer2 src="/video.mp4"3 overrides={{4 layers: [{5 id: '__host_branding__',6 name: 'Host Branding',7 overlays: [{8 id: 'watermark',9 type: 'core:image',10 position: {11 x: 90, y: 5,12 width: 8, height: 8,13 xUnit: '%', yUnit: '%',14 widthUnit: '%', heightUnit: '%'15 },16 config: { src: 'https://myapp.com/logo.png' }17 }]18 }],19 plugins: {20 'host-analytics': {21 id: 'host-analytics',22 type: 'mp4e:analytics',23 source: 'external',24 config: { trackingId: 'UA-XXXXX' }25 }26 },27 variables: {28 hostApiKey: { type: 'text', value: 'sk_live_xxx' },29 userName: { type: 'text', value: 'John' }30 },31 settings: {32 restrictions: { navigate: false, download: false }33 }34 }}35/>Common Use Cases
Branding Watermark
Add a persistent logo overlay to every video on your platform without editing each file.
1// Add a watermark logo to every video2<MP4EPlayer3 src={videoUrl}4 overrides={{5 layers: [{6 id: '__host_watermark__',7 name: 'Watermark',8 overlays: [{9 id: 'logo',10 type: 'core:image',11 position: {12 x: 92, y: 4,13 width: 6, height: 6,14 xUnit: '%', yUnit: '%',15 widthUnit: '%', heightUnit: '%'16 },17 config: {18 src: 'https://myapp.com/assets/logo-white.png',19 opacity: 0.720 }21 }]22 }]23 }}24/>Analytics Service Plugin
Inject a service plugin that tracks viewer interactions and reports them to your analytics backend.
1// Inject an analytics service plugin2<MP4EPlayer3 src={videoUrl}4 overrides={{5 plugins: {6 'host-analytics': {7 id: 'host-analytics',8 type: 'mp4e:analytics',9 source: 'external',10 config: {11 trackingId: 'UA-XXXXX',12 endpoint: 'https://myapp.com/api/analytics'13 }14 }15 }16 }}17/>Override Restrictions
Enforce sequential playback or disable downloads for content that requires it, regardless of what the video creator originally configured.
1// Disable seeking and downloading for paid content2<MP4EPlayer3 src={videoUrl}4 overrides={{5 settings: {6 restrictions: {7 navigate: false, // Disable seeking (sequential viewing only)8 download: false // Remove download option9 }10 }11 }}12/>Inject Host-Specific Variables
Provide runtime variables that plugins can reference via {{variableName}} interpolation. This is how hosts pass user context, API keys, and locale data into videos.
1// Inject host-specific variables that plugins can reference2<MP4EPlayer3 src={videoUrl}4 overrides={{5 variables: {6 userName: { type: 'text', value: currentUser.name },7 userTier: { type: 'text', value: currentUser.tier },8 apiBaseUrl: { type: 'text', value: 'https://myapp.com/api' },9 currency: { type: 'text', value: userLocale.currency }10 }11 }}12/>Host-Controlled Rules
Add event handlers that fire on scene transitions, overlay clicks, or any engine event. The host can wire up its own analytics, navigation, or business logic.
1// Add host-controlled event handlers2<MP4EPlayer3 src={videoUrl}4 overrides={{5 projectSettings: {6 eventRules: {7 'scene:enter': [{8 type: 'pluginAction',9 pluginId: 'host-analytics',10 actionId: 'trackEvent',11 config: { event: 'scene_view' }12 }]13 }14 }15 }}16/>Overrides vs Config
overridesinjects content (additive) — adds layers, plugins, variables, settings into the metadata before the engine processes it.configrestricts behavior (subtractive) — disables actions, sandboxes plugins, gates dangerous operations, and limits what the engine can do at runtime.
Use overrides to put content in. Use config to keep behavior out. They are complementary, not interchangeable.
Host-Injected Layers
Layers added via overrides are appended after the video creator’s layers, so they render on top by default. This makes them ideal for branding, CTAs, and host-controlled UI.
By convention, prefix host layer and overlay IDs with __host__ to avoid collisions with creator-defined IDs. This also makes it easy to identify host-injected content when debugging.
1// Convention: prefix host layer IDs with __host__2<MP4EPlayer3 src={videoUrl}4 overrides={{5 layers: [6 {7 id: '__host_branding__',8 name: 'Host Branding',9 overlays: [{10 id: '__host_logo__',11 type: 'core:image',12 position: { x: 90, y: 5, width: 8, height: 8,13 xUnit: '%', yUnit: '%', widthUnit: '%', heightUnit: '%' },14 config: { src: '/logo.png' }15 }]16 },17 {18 id: '__host_cta__',19 name: 'Host Call-to-Action',20 overlays: [{21 id: '__host_signup_btn__',22 type: 'core:button',23 position: { x: 50, y: 90, width: 20, height: 6,24 xUnit: '%', yUnit: '%', widthUnit: '%', heightUnit: '%' },25 config: { text: 'Sign Up Free' }26 }]27 }28 ]29 }}30/>id as a creator layer, the two will be deep-merged (including their overlays). Use the __host__ prefix to ensure host layers are always separate from creator content.