Skip to main content

Combatting autoplay issues

Browsers place restrictions on websites that play audio without user interaction.
Read on how to properly use the Remotion Player so you don't run into a browser policy.

The most strict browser is Mobile Safari.
If your composition plays well there, you should have no problems elsewhere.

Trigger the play from a user event

If you autoplay audio (through an <Audio>, <OffthreadVideo> or <Video> tag) on site load, browsers will block the audio.

The autoPlay prop of the <Player> is therefore discouraged if your video contains any audio.

Display a play button instead or use the controls prop.

Pass the event to the play() or toggle() method

If you don't use the default controls, make sure the call to .play() is initialized from a user gesture, for example a mouse click.
You should get a Javascript event like a MouseEvent from it.
Pass this event to the play() or toggle() function so audio may play automatically.

tsx
import {PlayerRef} from '@remotion/player';
import {useRef} from 'react';
 
export const App: React.FC = () => {
const ref = useRef<PlayerRef>(null);
 
return (
<button
onClickCapture={(e) => {
const {current} = ref;
// Pass the event to .play() or .toggle()
current?.play(e);
}}
>
Play
</button>
);
};
tsx
import {PlayerRef} from '@remotion/player';
import {useRef} from 'react';
 
export const App: React.FC = () => {
const ref = useRef<PlayerRef>(null);
 
return (
<button
onClickCapture={(e) => {
const {current} = ref;
// Pass the event to .play() or .toggle()
current?.play(e);
}}
>
Play
</button>
);
};
note

Prefer the onClickCapture event instead of the onClick event to make the event propagation work properly in Safari.

Media that enters the video after the start

Media that contains audio and that plays without user interaction requires special attention.
Consider the following scenario:

tsx
export const MyComp = () => {
return (
<AbsoluteFill>
<Audio src={staticFile('audio.mp3')} />
<Sequence from={120}>
<Audio src={staticFile('audio2.mp3')} />
</Sequence>
<Sequence from={120}>
<OffthreadVideo src={staticFile('video.mp4')} />
</Sequence>
</AbsoluteFill>
);
};
tsx
export const MyComp = () => {
return (
<AbsoluteFill>
<Audio src={staticFile('audio.mp3')} />
<Sequence from={120}>
<Audio src={staticFile('audio2.mp3')} />
</Sequence>
<Sequence from={120}>
<OffthreadVideo src={staticFile('video.mp4')} />
</Sequence>
</AbsoluteFill>
);
};

There are three different cases here:

An <Audio> tag that plays immediately. ✅ This is fine because we have user interaction.

An <Audio> tag that plays after 120 frames. ⚠️ May be subject to browser autoplay policies, but there is a workaround → Using the numberOfSharedAudioTags prop

A <OffthreadVideo> tag that plays after 120 frames. ⛔ May be subject to browser autoplay policies, which might restrict the video from playing with audio → Dealing with an autoplay failure

Using the numberOfSharedAudioTags prop

By default, Remotion will mount 5 auxiliary <audio> tags that will "warm" up with the first user interaction.
If an <Audio> tag is played after the first user interaction, it will be mounted into one of the auxiliary tags and will be allowed to play.

If you have more than 5 <Audio> tags that play at the same time, you can increase the number of auxiliary tags by passing the numberOfSharedAudioTags prop to the <Player>, because otherwise an error will be thrown.

Dealing with an autoplay failurev4.0.187

If the browser blocks a video from being autoplayed due to it having sound and not being started from a user interaction:

By default: The video will be muted, and played without audio. A console message will be printed.

Custom behavior: You may handle an autoplay failure using the onAutoPlayError prop of <OffthreadVideo> and <Video>:

tsx
import {OffthreadVideo, staticFile} from 'remotion';
import type {PlayerRef} from '@remotion/player';
 
export const MyComp: React.FC<{
playerRef: React.RefObject<PlayerRef>;
}> = ({playerRef}) => {
return (
<OffthreadVideo
src={staticFile('video.mp4')}
onAutoPlayError={() => {
playerRef.current?.pause();
}}
/>
);
};
tsx
import {OffthreadVideo, staticFile} from 'remotion';
import type {PlayerRef} from '@remotion/player';
 
export const MyComp: React.FC<{
playerRef: React.RefObject<PlayerRef>;
}> = ({playerRef}) => {
return (
<OffthreadVideo
src={staticFile('video.mp4')}
onAutoPlayError={() => {
playerRef.current?.pause();
}}
/>
);
};

In this example, the Player is simply paused.
If the user presses Play again, the video may then start playing with audio again due to it being started with user interaction.

You may show a poster with a hint - for example "Tap to resume".

When will a browser restrict autoplay?

It is not entirely deterministic.

After playing a video with user gesture, Safari will allow more media to be played for some amount of time.
However, the WebKit code shows that it is also dependent on battery saver mode or thermal pressure on the device.

Therefore, it is better to attempt to play the video with audio and handle the failure gracefully.