# Scrolling videos

Record a video of a page scrolling from top to bottom, as MP4, WebM or GIF, and set its length, smoothness and size.

Set `format=mp4` and you get a video of the page in place of an image. It starts at the top and scrolls to the bottom.

```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://en.wikipedia.org/wiki/Eiffel_Tower&format=mp4" \
  --output eiffel.mp4
```

You get `eiffel.mp4`: the article in a 1280 by 720 window, resting on the top for a moment, scrolling down at a steady pace and resting on the last screen. The response has the header `Content-Type: video/mp4`. The video has no sound.

The page really scrolls while it is recorded. A menu that sticks to the top stays there, and content that appears as you scroll appears in the video too.

A video takes longer to make than it lasts: about twice as long, plus the time the page needs to load. For long videos, [render in the background](#long-videos).

## Formats

Three values of [`format`](https://curlshot.com/docs/options.md#format) give a video.

| Format | What you get | Good for |
| --- | --- | --- |
| `mp4` | An H.264 video. Every browser, phone and video editor plays it. | Almost everything. |
| `webm` | A VP9 video. Often a smaller file than MP4. | Web pages. |
| `gif` | An animated image. It needs no player, but the file is much larger. | Emails, chats and READMEs. |

A GIF is recorded at 15 frames per second at most and is scaled down to 640 pixels wide. Set [`image_width`](#size) for another width.

```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&format=gif&video_duration=4" \
  --output example.gif
```

## Length

### video_duration

The length of the video, in seconds.

There is no default. Leave it out and the length follows the page.

The smallest value is `1` and the largest is `30`.

Without it, a taller page gives a longer video: the scroll moves about three quarters of a screen per second, which is easy to follow. With it, the video has exactly that length and the scroll gets faster or slower to fit.

This request gives an 8 second video, however tall the page is:

```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://en.wikipedia.org/wiki/Eiffel_Tower&format=mp4&video_duration=8" \
  --output eiffel-8s.mp4
```

### video_max_duration

The longest the video may get when its length follows the page, in seconds.

The default is `30`. The smallest value is `1` and the largest is `30`.

A page too tall to scroll at the normal pace in this time is scrolled faster, so the video still ends on the bottom of the page. It has no effect when you set `video_duration`.

### How far the video scrolls

The video scrolls to the bottom of the page, or to [`full_page_max_height`](https://curlshot.com/docs/full-page.md#full_page_max_height) on a page taller than that. The default is `20000` pixels. Set a lower value to show only the top part of a long page:

```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://en.wikipedia.org/wiki/Eiffel_Tower&format=mp4&full_page_max_height=4000" \
  --output eiffel-top.mp4
```

Before the recording starts, the page is scrolled through once so images that load late are there. [`full_page_scroll=false`](https://curlshot.com/docs/full-page.md#full_page_scroll) turns that off.

## Scrolling

### video_scroll

Scroll from the top of the page to the bottom while recording.

The default is `true`.

Set it to `false` to record the first screen without moving. That suits a page with an animation you want to show. The video is then 4 seconds long unless you set `video_duration`. A page that fits in the window is recorded the same way.

```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&format=mp4&video_scroll=false&video_duration=5" \
  --output example-still.mp4
```

### video_scroll_back

Scroll back to the top at the end.

The default is `false`.

The video then ends where it started, so it loops without a jump. This is useful for a GIF, which repeats for ever.

### video_scroll_easing

How the scroll moves.

The default is `ease_in_out`.

The allowed values are `ease_in_out` and `linear`. With `ease_in_out` the scroll starts and stops softly and keeps one even speed in between. With `linear` it moves at one speed from the first frame to the last.

## Smoothness

### video_fps

The number of frames per second.

The default is `24`. The smallest value is `5` and the largest is `30`.

More frames give a smoother scroll and a larger file. With `format=gif` the largest value is `15`, and that is also what a GIF gets when you leave the option out.

## Size

A video is as large as the browser window. For a video the window is 1280 by 720 pixels unless you choose another size, with [`viewport_width`](https://curlshot.com/docs/options.md#viewport_width) and [`viewport_height`](https://curlshot.com/docs/options.md#viewport_height) or with a [device](https://curlshot.com/docs/devices.md).

This request records the mobile layout of the page, as a tall phone video:

```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://en.wikipedia.org/wiki/Eiffel_Tower&format=mp4&viewport_device=iphone_15_pro" \
  --output eiffel-phone.mp4
```

Two options you know from images work for videos as well:

- [`image_width`](https://curlshot.com/docs/options.md#image_width) scales the video down to that width. The height follows. A video is never scaled up: a width larger than the recorded frames is refused.
- [`image_quality`](https://curlshot.com/docs/options.md#image_quality) sets how hard an MP4 or WebM is compressed. The default of `80` looks sharp. A lower value gives a smaller file.

One frame can hold at most 2,073,600 pixels, which is 1920 by 1080. The [`device_scale_factor`](https://curlshot.com/docs/options.md#device_scale_factor) counts: a 1280 by 720 window at `device_scale_factor=2` is over the limit and is refused with [`invalid_options`](https://curlshot.com/docs/errors.md#invalid_options). A device preset is different. Its pixel density is lowered until the frames fit, so `viewport_device=iphone_15_pro` gives a sharp 786 by 1704 video.

The sides of an MP4 are always even numbers. An odd side loses one pixel.

## What does not apply to a video

A video always shows the window, scrolling. These options are for still captures, and a request that combines one of them with a video format is refused with [`invalid_options`](https://curlshot.com/docs/errors.md#invalid_options):

- [`full_page=true`](https://curlshot.com/docs/full-page.md). A video already goes through the whole page.
- [`selector`](https://curlshot.com/docs/element.md) and the `clip_*` options.
- [`omit_background`](https://curlshot.com/docs/options.md#omit_background) and [`image_height`](https://curlshot.com/docs/options.md#image_height).

Everything that prepares the page works as usual: [blocking](https://curlshot.com/docs/blocking.md), [dark mode](https://curlshot.com/docs/dark-mode-and-emulation.md), [waiting](https://curlshot.com/docs/waiting.md), [custom CSS and clicks](https://curlshot.com/docs/customize.md), cookies and headers.

## Long videos

A request for a video stays open until the video is done. For a 30 second video that can be well over a minute. Some HTTP clients and proxies give up before that.

To avoid waiting, add [`async=true`](https://curlshot.com/docs/async-and-webhooks.md). The answer comes at once with a job id, and the finished video is sent to your [webhook](https://curlshot.com/docs/async-and-webhooks.md) or fetched with the job.

```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://en.wikipedia.org/wiki/Eiffel_Tower&format=mp4&async=true"
```

## Showing a video on a web page

Do not point a `<video>` tag at a plain request. A player asks for a video in several pieces, and every piece would be a new render.

Add [`cache=true`](https://curlshot.com/docs/caching.md). The first request records the video and every later one gets the stored copy:

```html
<video src="https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&amp;url=https%3A%2F%2Fexample.com&amp;format=mp4&amp;cache=true" autoplay loop muted playsinline></video>
```

On a public page, use a [signed link](https://curlshot.com/docs/signed-links.md) so your access key cannot be reused for other pages. You can also ask for [`response_type=json`](https://curlshot.com/docs/screenshot-url.md) and use the `url` of the stored file.

## Limits of your plan

A video counts as one screenshot against your quota, however long it is. What a plan limits is the length:

- A plan can have a lower maximum than `30` seconds. A larger `video_duration` or `video_max_duration` is lowered to the plan's maximum, and you still get a valid video.
- A plan can leave video capture out. A request for a video then answers `feature_not_available`.

Your own value is `video_max_seconds` in the answer of [`GET /usage`](https://curlshot.com/docs/usage-and-limits.md).

A finished file that is too big answers [`content_too_large`](https://curlshot.com/docs/errors.md#content_too_large). Use a shorter `video_duration`, a smaller `image_width`, a lower `image_quality` or a lower `video_fps`.

## Where to go next

- [Options reference](https://curlshot.com/docs/options.md#video): every video option in one list.
- [Async and webhooks](https://curlshot.com/docs/async-and-webhooks.md): record long videos in the background.
- [Caching](https://curlshot.com/docs/caching.md): record once, serve many times.
- [Devices](https://curlshot.com/docs/devices.md): phone and tablet presets for vertical videos.
- [Full-page screenshots](https://curlshot.com/docs/full-page.md): the whole page as one still image.
