Skip to main content

Data fetching

In Remotion, you may fetch data from an API to use it in your video. On this page, we document recipes and best practices.

Fetching data before the renderv4.0.0

You may use the calculateMetadata prop of the <Composition /> component to alter the props that get passed to your React component.

When to use

The data being fetched using calculateMetadata() must be JSON-serializable. That means it is useful for API responses, but not for assets in binary format.

Usage

Pass a callback function which takes the untransformed props, and return an object with the new props.

src/Root.tsx
tsx
import { Composition } from"remotion";
typeApiResponse= {
title:string;
description:string;
};
typeMyCompProps= {
id:string;
data:ApiResponse|null;
};
constMyComp:React.FC<MyCompProps> = () =>null;
exportconstRoot:React.FC= () => {
return (
<Composition
id="MyComp"
component={MyComp}
durationInFrames={300}
fps={30}
width={1920}
height={1080}
defaultProps={{
id: "1",
data: null,
}}
calculateMetadata={async ({ props }) => {
constdata=awaitfetch(`https://example.com/api/${props.id}`);
constjson=await data.json();
return {
props: {
...props,
data: json,
},
};
}}
/>
);
};

The props being passed to calculateMetadata() are the input props merged together with the default props.
In addition to props, defaultProps can also be read from the same object.

When transforming, the input and the output must be the same TypeScript type. Consider using a nullable type for your data and throw an error inside your component to deal with the null type:

MyComp.tsx
tsx
typeMyCompProps= {
id:string;
data:ApiResponse|null;
};
constMyComp:React.FC<MyCompProps> = ({ data }) => {
if (data ===null) {
thrownewError("Data was not fetched");
}
return <div>{data.title}</div>;
};

TypeScript typing

You may use the CalculateMetadataFunction type from remotion to type your callback function. Pass as the generic value (<>) the type of your props.

src/Root.tsx
tsx
import { CalculateMetadataFunction } from"remotion";
exportconstcalculateMyCompMetadata:CalculateMetadataFunction<
MyCompProps
> = ({ props }) => {
return {
props: {
...props,
data: {
title: "Hello world",
description: "This is a description",
},
},
};
};
exportconstMyComp:React.FC<MyCompProps> = () =>null;

Colocation

Here is an example of how you could define a schema, a component and a fetcher function in the same file:

MyComp.tsx
tsx
import { CalculateMetadataFunction } from"remotion";
import { z } from"zod";
constapiResponse= z.object({ title: z.string(), description: z.string() });
exportconstmyCompSchema= z.object({
id: z.string(),
data: z.nullable(apiResponse),
});
typeProps=z.infer<typeof myCompSchema>;
exportconstcalcMyCompMetadata:CalculateMetadataFunction<Props> =async ({
props,
}) => {
constdata=awaitfetch(`https://example.com/api/${props.id}`);
constjson=await data.json();
return {
props: {
...props,
data: json,
},
};
};
exportconstMyComp:React.FC<Props> = ({ data }) => {
if (data ===null) {
thrownewError("Data was not fetched");
}
return <div>{data.title}</div>;
};
src/Root.tsx
tsx
import React from"react";
import { Composition } from"remotion";
import { MyComp, calcMyCompMetadata, myCompSchema } from"./MyComp";
exportconstRoot= () => {
return (
<Composition
id="MyComp"
component={MyComp}
durationInFrames={300}
fps={30}
width={1920}
height={1080}
defaultProps={{
id: "1",
data: null,
}}
schema={myCompSchema}
calculateMetadata={calcMyCompMetadata}
/>
);
};

By implementing this pattern, The id in the props editor can now be tweaked and Remotion will refetch the data whenever it changes.

Setting the duration based on data

You may set the durationInFrames, fps, width and height by returning those keys in the callback function:

tsx
import { CalculateMetadataFunction } from"remotion";
typeMyCompProps= {
durationInSeconds:number;
};
exportconstcalculateMyCompMetadata:CalculateMetadataFunction<
MyCompProps
> = ({ props }) => {
constfps=30;
constdurationInSeconds= props.durationInSeconds;
return {
durationInFrames: durationInSeconds * fps,
fps,
};
};

Learn more about this feature in the Variable metadata page.

Aborting stale requests

The props in the props editor may rapidly change for example by typing fast.
It is a good practice to cancel requests which are stale using the abortSignal that gets passed to the calculateMetadata() function:

src/MyComp.tsx
tsx
exportconstcalculateMyCompMetadata:CalculateMetadataFunction<
MyCompProps
> =async ({ props, abortSignal }) => {
constdata=awaitfetch(`https://example.com/api/${props.id}`, {
signal: abortSignal,
});
constjson=await data.json();
return {
props: {
...props,
data: json,
},
};
};
exportconstMyComp:React.FC<MyCompProps> = () =>null;

This abortSignal is created by Remotion using the AbortController API.

Debouncing requests

If you are making requests to an expensive API, you might want to only fire a request after the user has stopped typing for a while. You may use the following function for doing so:

src/wait-for-no-input.ts
tsx
import { getRemotionEnvironment } from"remotion";
exportconstwaitForNoInput= (signal:AbortSignal, ms:number) => {
// Don't wait during rendering
if (getRemotionEnvironment().isRendering) {
returnPromise.resolve();
}
if (signal.aborted) {
returnPromise.reject(newError("stale"));
}
returnPromise.race<void>([
newPromise<void>((_, reject) => {
signal.addEventListener("abort", () => {
reject(newError("stale"));
});
}),
newPromise<void>((resolve) => {
setTimeout(() => {
resolve();
}, ms);
}),
]);
};
src/MyComp.tsx
tsx
exportconstcalculateMyCompMetadata:CalculateMetadataFunction<
MyCompProps
> =async ({ props, abortSignal }) => {
awaitwaitForNoInput(abortSignal, 750);
constdata=awaitfetch(`https://example.com/api/${props.id}`, {
signal: abortSignal,
});
constjson=await data.json();
return {
props: {
...props,
data: json,
},
};
};
exportconstMyComp:React.FC<MyCompProps> = () =>null;

Time limit

When Remotion calls the calculateMetadata() function, it wraps it in a delayRender(), which by default times out after 30 seconds.

Fetching data during the render

Using delayRender() and continueRender() you can tell Remotion to wait for asynchronous operations to finish before rendering a frame.

When to use

Use this approach to load assets which are not JSON serializable or if you are using a Remotion version lower than 4.0.

Usage

Call delayRender() as soon as possible, for example when initializing the state inside your component.

tsx
import { useCallback, useEffect, useState } from"react";
import { cancelRender, continueRender, delayRender } from"remotion";
exportconstMyComp= () => {
const [data, setData] =useState(null);
const [handle] =useState(() =>delayRender());
constfetchData=useCallback(async () => {
try {
constresponse=awaitfetch("http://example.com/api");
constjson=await response.json();
setData(json);
continueRender(handle);
} catch (err) {
cancelRender(err);
}
}, [handle]);
useEffect(() => {
fetchData();
}, [fetchData]);
return (
<div>
{data ? (
<div>This video has data from an API! {JSON.stringify(data)}</div>
) :null}
</div>
);
};

Once the data is fetched, you can call continueRender() to tell Remotion to continue rendering the video.
In case the data fetching fails, you can call cancelRender() to cancel the render without waiting for the timeout.

Time limit

You need to clear all handles created by delayRender() within 30 seconds after the page is opened. You may increase the timeout.

Prevent overfetching

During rendering, multiple headless browser tabs are opened to speed up rendering.
In Remotion Lambda, the rendering concurrency may be up to 200x.
This means that if you are fetching data inside your component, the data fetching will be performed many times.

1
Prefer fetching the data before rendering if possible.
2
Ensure you are entitled to a high request rate without running into a rate limit.
3
The data returned by the API must be the same on all threads, otherwise flickering may occur.
4
Make sure to not have frame as a dependency of the useEffect(), directly or indirectly, otherwise data will be fetched every frame leading to slowdown and potentially running into rate limits.

See also

AltStyle によって変換されたページ (->オリジナル) /