Remotion Player: Embed Interactive Video in Your React App
Remotion Player: Embed Interactive Video in Your React App
One of the most underused features of Remotion is the ability to take a composition you have already built for export and drop it directly into a running React application — with full playback controls, scrubbing, and programmatic control — without rendering it to a video file first. This is what @remotion/player enables.
Whether you are building a marketing site that showcases your video template live, a SaaS dashboard where users preview their generated video before downloading, or an internal tool that lets team members scrub through a data-driven animation, the <Player> component is the right tool for the job.
This guide covers everything you need to know: installation, the full set of props, controlling playback from outside the component, the acknowledgeRemotionLicense requirement, and embedding patterns for Next.js and standard React apps.
Why Use @remotion/player Instead of a <video> Tag?
A rendered .mp4 file embedded via <video> is static. If your video is data-driven — generated from user input, live metrics, or a database — you would need to re-render the file every time the data changes. That takes time and server resources.
@remotion/player renders the composition in the browser using React, the same way the Remotion Studio does. The video is live: change a prop and the animation updates instantly. This makes it ideal for:
- Interactive previews — let users see their customized video before committing to a server render
- Template showcases — embed an animated demo on a landing page without hosting a video file
- Dashboard widgets — show a data visualization animation that stays current with live data
- Educational tools — let learners scrub through an animated explanation
Installation
@remotion/player is a separate package from the core remotion library. Install it alongside your existing Remotion dependencies:
npm install @remotion/player
You do not need to install @remotion/core separately — remotion covers the core hooks and utilities.
Basic Usage
The <Player> component takes your existing Remotion composition component as a prop and renders it inside a controllable player shell.
import { Player } from '@remotion/player';
import { MyComposition } from './MyComposition';
export const VideoPreview: React.FC = () => {
return (
<Player
component={MyComposition}
durationInFrames={150}
fps={30}
compositionWidth={1920}
compositionHeight={1080}
style={{ width: '100%' }}
/>
);
};
This renders an interactive player with play/pause controls and a scrubber. No additional configuration is required for a basic embed.
Core Props
component
Type: React.FC<Props>
The Remotion composition component to render. This is the same component you would pass to <Composition> in your Root.tsx. The component receives inputProps as its React props.
<Player component={TitleCard} ... />
durationInFrames
Type: number
The total length of the animation in frames. This must match (or be less than) the duration of the composition you are rendering.
<Player durationInFrames={90} ... />
// 90 frames at 30fps = 3 seconds
fps
Type: number
Frames per second. This should match the fps your composition was designed for. Mismatching fps in the player versus what useVideoConfig() returns inside the composition will cause animation speed issues.
compositionWidth and compositionHeight
Type: number
The intrinsic width and height of the composition canvas in pixels. These define the aspect ratio and the coordinate space for your composition. They are independent of the rendered size in the browser — use the style prop to control the visual size.
<Player
compositionWidth={1920}
compositionHeight={1080}
style={{ width: '854px' }} // rendered at 854×480 visually
...
/>
inputProps
Type: object (matching your component’s props type)
Props passed directly to the composition component. Use this to inject dynamic data — user names, custom colors, live metrics — into the animation.
<Player
component={SalesCard}
inputProps={{
revenue: 128500,
period: 'Q2 2026',
currency: 'USD',
}}
durationInFrames={120}
fps={30}
compositionWidth={1280}
compositionHeight={720}
/>
Because the player re-renders reactively, you can connect inputProps to React state and the animation will update live as state changes.
style
Type: React.CSSProperties
CSS styles applied to the player’s outer container. Use this to control the visual dimensions without affecting the composition’s internal coordinate system.
controls
Type: boolean (default: false)
When true, renders a play/pause button and a seek bar below the player. Set to false for an auto-playing embed where you do not want visible controls.
<Player controls ... />
autoPlay
Type: boolean (default: false)
Starts playback automatically when the player mounts. Combine with loop for a continuously playing embed.
loop
Type: boolean (default: false)
Loops the playback indefinitely.
clickToPlay
Type: boolean (default: true when controls is false)
When enabled, clicking the player surface toggles play/pause. Set to false for a purely decorative auto-playing embed that should not respond to user interaction.
showVolumeControls
Type: boolean (default: true)
Show or hide the volume control in the player UI. Only relevant when controls is true.
doubleClickToFullscreen
Type: boolean (default: true)
Allows double-clicking the player to enter fullscreen mode.
spaceKeyToPlayOrPause
Type: boolean (default: true)
When true, pressing the space bar toggles play/pause. Set to false if the player is embedded in a page where space has another function (such as scrolling).
initiallyShowControls
Type: boolean | number (default: true)
Controls whether the control bar is visible initially. When passed a number, the controls fade out after that many milliseconds.
Controlling Playback Programmatically with playerRef
The ref prop gives you imperative access to the player’s playback API. This is how you trigger play, pause, seek, and read the current frame from outside the component.
import { Player, PlayerRef } from '@remotion/player';
import { useRef } from 'react';
import { MyComposition } from './MyComposition';
export const ControlledPlayer: React.FC = () => {
const playerRef = useRef<PlayerRef>(null);
const handlePlay = () => playerRef.current?.play();
const handlePause = () => playerRef.current?.pause();
const handleSeekToMiddle = () => {
playerRef.current?.seekTo(75); // seek to frame 75
};
return (
<>
<Player
ref={playerRef}
component={MyComposition}
durationInFrames={150}
fps={30}
compositionWidth={1920}
compositionHeight={1080}
/>
<div>
<button onClick={handlePlay}>Play</button>
<button onClick={handlePause}>Pause</button>
<button onClick={handleSeekToMiddle}>Jump to Middle</button>
</div>
</>
);
};
Available PlayerRef Methods
| Method | Signature | Description |
|---|---|---|
play | () => void | Starts playback |
pause | () => void | Pauses playback |
toggle | () => void | Toggles between play and pause |
seekTo | (frame: number) => void | Seeks to a specific frame |
getCurrentFrame | () => number | Returns the current frame number |
isPlaying | () => boolean | Returns whether the player is currently playing |
getContainerNode | () => HTMLDivElement | null | Returns the player’s DOM node |
mute | () => void | Mutes audio |
unmute | () => void | Unmutes audio |
setVolume | (volume: number) => void | Sets volume (0 to 1) |
getVolume | () => number | Returns current volume |
isMuted | () => boolean | Returns whether muted |
Listening to Player Events
The <Player> component accepts event handler props for reacting to playback state changes:
<Player
ref={playerRef}
component={MyComposition}
durationInFrames={150}
fps={30}
compositionWidth={1920}
compositionHeight={1080}
onPlay={() => console.log('started playing')}
onPause={() => console.log('paused')}
onEnded={() => console.log('reached the end')}
onSeeked={(e) => console.log('seeked to frame', e.detail.frame)}
onFrameUpdate={(e) => console.log('current frame', e.detail.frame)}
/>
onFrameUpdate fires on every frame tick and is useful for syncing external UI (such as a custom progress bar) with the current playback position.
The acknowledgeRemotionLicense Prop
When you use @remotion/player in a commercial application, Remotion requires you to acknowledge the license. If you do not pass this prop, the player will display a watermark or warning in non-development environments.
<Player
component={MyComposition}
durationInFrames={150}
fps={30}
compositionWidth={1920}
compositionHeight={1080}
acknowledgeRemotionLicense
/>
This is a boolean prop — simply including acknowledgeRemotionLicense (without a value) is equivalent to acknowledgeRemotionLicense={true}.
The requirement reflects Remotion’s licensing model: individual developers and open-source projects can use it freely, but companies must purchase a commercial license. Passing this prop confirms you have read and agreed to the terms at remotion.dev/license.
Embedding in Next.js
@remotion/player is a client-side component. In Next.js (both Pages Router and App Router), you must ensure it renders only in the browser.
App Router (Next.js 13+)
Add the "use client" directive to any file that imports <Player>:
'use client';
import { Player } from '@remotion/player';
import { MyComposition } from '@/remotion/MyComposition';
export const VideoEmbed: React.FC = () => {
return (
<Player
component={MyComposition}
durationInFrames={150}
fps={30}
compositionWidth={1920}
compositionHeight={1080}
controls
acknowledgeRemotionLicense
style={{ width: '100%', borderRadius: '12px' }}
/>
);
};
Then import this client component from any Server Component page:
// app/page.tsx (Server Component)
import { VideoEmbed } from '@/components/VideoEmbed';
export default function Home() {
return (
<main>
<h1>Preview Your Video</h1>
<VideoEmbed />
</main>
);
}
Pages Router
Use next/dynamic with ssr: false to prevent server-side rendering of the player:
import dynamic from 'next/dynamic';
const VideoEmbed = dynamic(
() => import('../components/VideoEmbed'),
{ ssr: false }
);
export default function Page() {
return (
<div>
<VideoEmbed />
</div>
);
}
Responsive Sizing
The player’s visual size is controlled entirely by CSS. The compositionWidth and compositionHeight props define the internal canvas; the style prop controls how large it appears in the DOM.
For a fully responsive player that fills its container:
<Player
component={MyComposition}
durationInFrames={150}
fps={30}
compositionWidth={1920}
compositionHeight={1080}
style={{
width: '100%',
aspectRatio: '16 / 9',
}}
controls
acknowledgeRemotionLicense
/>
The player internally scales the composition canvas to fit the container while maintaining the aspect ratio, so your composition’s layout always looks correct regardless of screen size.
Connecting Live Data via inputProps
A common pattern in SaaS tools is to let users fill out a form and instantly preview the resulting video. Here is a minimal example using React state:
'use client';
import { Player } from '@remotion/player';
import { useState } from 'react';
import { PersonalizedCard } from '@/remotion/PersonalizedCard';
export const PersonalizationPreview: React.FC = () => {
const [name, setName] = useState('Your Name');
const [color, setColor] = useState('#3b82f6');
return (
<div>
<input
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Enter your name"
/>
<input
type="color"
value={color}
onChange={(e) => setColor(e.target.value)}
/>
<Player
component={PersonalizedCard}
durationInFrames={90}
fps={30}
compositionWidth={1280}
compositionHeight={720}
inputProps={{ name, accentColor: color }}
controls
autoPlay
loop
acknowledgeRemotionLicense
style={{ width: '100%', marginTop: 16 }}
/>
</div>
);
};
Every keystroke in the name field immediately updates the animation because inputProps is reactive React state. No render job, no waiting.
Common Pitfalls
Forgetting "use client" in App Router
If you import <Player> in a Server Component without marking the file as a client component, Next.js will throw a hydration error. Always add "use client" to the file that contains the player.
Mismatched fps and durationInFrames
If the fps you pass to <Player> does not match what useVideoConfig() returns inside the composition, animations will run at the wrong speed in the player even though they look correct in the Remotion Studio. Always use a single source of truth — define the fps in one place and pass it to both the <Composition> (if you have one) and the <Player>.
Not handling SSR for heavy compositions
Remotion compositions that import large dependencies (e.g. data processing libraries) can increase the server bundle size in Next.js even if the player itself is a client component. Use dynamic imports for the composition component itself if you encounter bundle size issues.
Ignoring the license requirement
In production commercial apps, omitting acknowledgeRemotionLicense results in a watermark. Add the prop early in development so you do not encounter a surprise in production.
FAQ
Q: Does @remotion/player require a separate Remotion Studio installation?
No. @remotion/player is a standalone React component. It does not depend on the Remotion development server or Studio. You only need to install the @remotion/player package and import it.
Q: Can I render multiple players on the same page?
Yes. Each <Player> instance is independent. You can render as many as you need on a single page. Each has its own playback state and ref. Keep in mind that each player runs its own animation loop, so many simultaneously playing players may impact performance on lower-end devices.
Q: Can I use @remotion/player with Vite or other bundlers besides Next.js?
Yes. @remotion/player is a standard React package and works with any bundler that supports React — Vite, Webpack, Parcel, and others. The "use client" directive is only a Next.js App Router concern.
Q: How do I prevent the player from auto-playing on mobile where autoplay is restricted?
Browser autoplay policies block media with audio on mobile. If your composition has audio, set autoPlay={false} and use controls so users can start playback manually. For silent compositions, autoPlay generally works on mobile.
Q: Is there a way to export the frame as an image from the player?
PlayerRef does not expose a direct screenshot method, but you can use the browser’s Canvas API to capture a frame. Alternatively, Remotion’s renderStill() server-side function can generate a single-frame image from a composition.
Q: What happens if I pass a durationInFrames longer than the composition actually runs?
The player will happily play beyond the composition’s natural end — you will just see the final frame frozen. Always match durationInFrames in the player to the composition’s actual duration to avoid this.
Q: Can I use @remotion/player without a <Composition> wrapper in my Root component?
Yes. The <Player> component takes a raw React component directly via its component prop. You do not need a Root.tsx or a <Composition> registration. The player handles all the context setup internally.
Summary
@remotion/player bridges the gap between programmatic video production and interactive web applications. The key points:
- Install
@remotion/playerseparately; it is not included in the baseremotionpackage - The five required props are
component,durationInFrames,fps,compositionWidth, andcompositionHeight - Use
inputPropsto inject dynamic data — the animation updates reactively - Use
playerReffor imperative playback control from outside the component - Always add
acknowledgeRemotionLicensein commercial applications - In Next.js App Router, mark the containing file with
"use client"
Browse production-ready Remotion templates at RenderComp →
Every template in the RenderComp library is built as a properly structured Remotion composition, ready to drop into a <Player> embed. Preview them live on the site, customize the props, and integrate directly into your React application.
Now available
Get 1,000+ Remotion Templates
Pay once — no subscription. Lifetime updates. TypeScript-first.
View pricing →