R RenderComp
remotion player react nextjs tutorial

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

MethodSignatureDescription
play() => voidStarts playback
pause() => voidPauses playback
toggle() => voidToggles between play and pause
seekTo(frame: number) => voidSeeks to a specific frame
getCurrentFrame() => numberReturns the current frame number
isPlaying() => booleanReturns whether the player is currently playing
getContainerNode() => HTMLDivElement | nullReturns the player’s DOM node
mute() => voidMutes audio
unmute() => voidUnmutes audio
setVolume(volume: number) => voidSets volume (0 to 1)
getVolume() => numberReturns current volume
isMuted() => booleanReturns 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:

  1. Install @remotion/player separately; it is not included in the base remotion package
  2. The five required props are component, durationInFrames, fps, compositionWidth, and compositionHeight
  3. Use inputProps to inject dynamic data — the animation updates reactively
  4. Use playerRef for imperative playback control from outside the component
  5. Always add acknowledgeRemotionLicense in commercial applications
  6. 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 →