MP4, WebM or GIF: how to record a web page scrolling
A scrolling video is a filmstrip: screenshots of one window, each a little further down the page. Scrub this one, then change its length and frame rate.
The page, with the window the video sees.
- Time
- 0.00 s
- Scrolled
- 0 px
- Frame
- 1 of 192
8 of the 192 frames, cut at equal intervals. Choose one to jump to it.
8 s x 24 fps = 192 frames
- The page moves 18.8 px between two frames, 2.6% of the window. 24 frames per second: smooth for a scroll. Fewer frames step, more frames cost bytes.
- It scrolls 450 px a second, 0.63 screens. Slower than 0.75 screens per second: easy to read, but more frames and a larger file.
How many frames does a scrolling video have?
A scrolling video has seconds x frames per second frames, and each one is a full screenshot of the window. The model page in the filmstrip is 1280 x 4320 pixels in a 1280 x 720 window, so it scrolls 3,600 pixels. What the eye judges is how far the page jumps between two frames.
| Length and frame rate | Total frames | Page moves per frame | Screens per second | What it looks like |
|---|---|---|---|---|
| 8 s at 5 fps | Total frames8 x 5 = 40 | Page moves per frame92.3 px | Screens per second0.63 | A slide show: the page jumps an eighth of a screen at a time. |
| 8 s at 15 fps | Total frames8 x 15 = 120 | Page moves per frame30.3 px | Screens per second0.63 | The most a GIF from the API takes. Readable, slightly stepped. |
| 8 s at 24 fps | Total frames8 x 24 = 192 | Page moves per frame18.8 px | Screens per second0.63 | The default frame rate. Smooth for a scroll. |
| 8 s at 30 fps | Total frames8 x 30 = 240 | Page moves per frame15.1 px | Screens per second0.63 | The maximum. A quarter more frames than 24 for a small gain. |
| 4 s at 24 fps | Total frames4 x 24 = 96 | Page moves per frame37.9 px | Screens per second1.25 | Half the length: the same step per frame as 8 s at 12 fps, and too fast to read. |
| 16 s at 24 fps | Total frames16 x 24 = 384 | Page moves per frame9.4 px | Screens per second0.31 | Twice the length: easy to read, and twice the frames to store. |
Page moves per frame = 3,600 / (frames - 1), for a scroll at one even speed. Screens per second = 3,600 / seconds / 720. Higher frame rates give smoother motion and larger files.[2]
MP4, WebM and GIF compared
MP4 and WebM are video containers that store the changes between frames, and GIF is an image format that stores every frame with at most 256 colours. That one difference explains the rest of the table: size, colour, sound and where each file plays.
| MP4 H.264 | WebM VP9 or AV1 | GIF | |
|---|---|---|---|
| What it is[1][4] | MP4A video container. On the web it almost always holds H.264 (AVC) video. | WebMAn open video container. It holds VP8, VP9 or AV1 video. | GIFAn image format (GIF89a) that can hold several frames. |
| Compression[2][3] | MP4Lossy. Stores a full key frame now and then, and only the changes in between. | WebMLossy, with the same key frame and changes method. | GIFLossless LZW, but only after every frame is reduced to a small palette. |
| Colours[3][4] | MP4Full colour. | WebMFull colour. | GIFAt most 256 per frame: each pixel is an 8-bit index into a colour table of 2 to 256 entries. More colours are faked with dithering. |
| Transparency[2][3] | MP4No. | WebMVP9 can carry an alpha channel, but Safari does not play it. | GIFOne palette entry can be fully transparent. A pixel is see-through or it is not. |
| Sound[1] | MP4Yes, usually AAC. | WebMYes: Opus or Vorbis. | GIFNo. |
| Frame timing[4] | MP4Any frame rate. | WebMAny frame rate. | GIFEach frame waits a whole number of hundredths of a second, so 15 frames per second is stored as waits of 7, 6 and 7 hundredths. |
| Looping[4][6] | MP4The player decides: loop on the <video> tag. | WebMThe player decides: loop on the <video> tag. | GIFStored in the file by an application extension. The GIF89a specification itself defines no loop count. |
| Browsers[2][19] | MP4H.264 plays in all versions of Chrome, Edge, Firefox, Opera and Safari. | WebMVP9 plays in all current browsers. Safari has full WebM support from 16.0 on macOS and 17.4 on iOS. AV1 in Safari needs a hardware decoder: an M3 Mac or later, iPhone 15 Pro, iPhone 16 or later. | GIFEverywhere an image is shown. |
| Plays by itself[5] | MP4Only with autoplay, and only when the video is muted or has no sound track. Safari also needs playsinline. | WebMThe same rules as MP4. | GIFAlways. There is no play button, no pause and no way to seek. |
| HTML | MP4<video> | WebM<video> | GIF<img> |
| Use it for[1] | MP4Almost everything: it is the one format every player, phone and editor opens. | WebMWeb pages, as the first <source> with an MP4 behind it. | GIFPlaces that show images but not video: an email, a README. |
Animated WebP. An image format with frames, lossy (built on the VP8 video codec) or lossless, with transparency and looping. It works in current versions of all major browsers; Safari needs version 14 and macOS 11 or later.[3]
APNG. An animated PNG: lossless, full colour with an alpha channel. Supported since Chrome 59, Edge 12, Firefox 3 and Safari 8.[3]
How much bigger is a GIF than an MP4 or a WebM?
In our test, a GIF of a scrolling page at 640 x 360 was 25 times the size of the MP4 and 34 times the size of the WebM made from the same 120 frames. The numbers below are ours, and the recipe is printed so anyone can repeat it.
Our measurement, 11 October 2026
File size in megabytes of one 8 second scroll at 15 frames per second, 120 frames. Shorter is better. 1 MB = 1,000,000 bytes.
- WebM (VP9)
- MP4 (H.264)
- GIF
1280 x 720 pixels
- Wikipedia: Eiffel Tower
- WebM (VP9):
- 0.67 MB
- MP4 (H.264):
- 0.83 MB
- GIF:
- 18.7 MB
- Wikipedia: Web browser
- WebM (VP9):
- 0.65 MB
- MP4 (H.264):
- 0.90 MB
- GIF:
- 16.2 MB
640 x 360 pixels
- Wikipedia: Eiffel Tower
- WebM (VP9):
- 0.25 MB
- MP4 (H.264):
- 0.34 MB
- GIF:
- 8.52 MB
- Wikipedia: Web browser
- WebM (VP9):
- 0.24 MB
- MP4 (H.264):
- 0.32 MB
- GIF:
- 8.20 MB
How it was measured
- Each page was opened in Chromium with Playwright, in a 1280 x 720 window at one image pixel per CSS pixel.
- It was scrolled 36 pixels per frame for 120 frames and each frame was saved as a PNG: 8 seconds at 15 frames per second.
- The same PNG frames were encoded three times with ffmpeg 8.1.2, two threads each, and once more at half the size.
- Wikipedia: Eiffel Tower: https://en.wikipedia.org/wiki/Eiffel_Tower
- Wikipedia: Web browser: https://en.wikipedia.org/wiki/Web_browser
# frames: 120 PNG files, f0000.png to f0119.png, 1280 x 720
ffmpeg -framerate 15 -i f%04d.png -vf format=yuv420p \
-c:v libx264 -preset veryfast -crf 22 -movflags +faststart -an -threads 2 out.mp4
ffmpeg -framerate 15 -i f%04d.png -vf format=yuv420p \
-c:v libvpx-vp9 -b:v 0 -crf 33 -row-mt 1 -an -threads 2 out.webm
ffmpeg -framerate 15 -i f%04d.png -vf palettegen=stats_mode=diff \
-frames:v 1 -update 1 -threads 2 palette.png
ffmpeg -framerate 15 -i f%04d.png -i palette.png \
-lavfi paletteuse=dither=bayer:bayer_scale=5:diff_mode=rectangle -loop 0 -threads 2 out.gif
# the 640 x 360 files: the same, with scale=640:-2:flags=lanczos first in the filterRead it as one test, not a law
Encode an H.264 scroll with one or two threads
-threads changed. With two threads the 1280 x 720 MP4 was 0.83 MB, and with one thread 0.83 MB. With ffmpeg's default on our 10-core machine it was 6.38 MB: 7.7 times the size. The second page went from 0.90 MB to 7.02 MB, and the 640 x 360 files from 0.34 and 0.32 MB to 0.88 and 0.86 MB. The WebM and GIF files did not change by a byte. For a scrolling page, add -threads 2 to an H.264 encode.Which format for which job?
MP4 with H.264 is the safe choice for every destination that plays video, and a GIF is for the places that only show images. The matrix uses what each platform documents about itself. "Not documented" means its own documentation, read on 11 October 2026, does not say.
| Where it goes | MP4 | WebM | GIF | Why |
|---|---|---|---|---|
| Landing page hero | MP4Best | WebMBest | GIFAvoid | Use a muted, looping <video> with a WebM source first and an MP4 source second. The browser plays the first one it understands, at a fraction of the bytes of a GIF.[5][6] |
| Product demo in documentation | MP4Best | WebMWorks | GIFWorks | An MP4 with controls lets the reader pause and scrub. Choose MP4 when you can ship only one file: it is the format available on the widest range of devices and browsers.[1] |
| Pull request or issue on GitHub | MP4Best | WebMWorks | GIFWorks | GitHub accepts .mp4, .mov and .webm attachments in issues, pull requests and comments, and recommends H.264. Limits: 10 MB for a video on a free plan, 100 MB on a paid plan, 10 MB for a GIF.[7] |
| README file | MP4Not documented | WebMNot documented | GIFBest | A GIF committed to the repository is an image, and a README shows images from a relative path. GitHub documents video attachments for issues, pull requests and comments, not for README files.[7][8] |
| Chat message | MP4Not documented | WebMNot documented | GIFNot documented | Slack takes files up to 1 GB, but its upload article does not say which formats play inside a message. Send an MP4 with H.264, the format with the widest support elsewhere, and check it in your own workspace.[13] |
| MP4Not documented | WebMNot documented | GIFBest | Outlook plays animated GIFs in the body of a message by default, and shows only the first frame when animations are turned off. Make the first frame say enough. Keep the file small: it travels with every copy.[12] | |
| Post on X | MP4Best | WebMNot documented | GIFWorks | X recommends H.264 High Profile video at 1280 x 720, 60 frames per second or less. An animated GIF may be 15 MB, 1280 x 1080, 350 frames and 300 million pixels in total (width x height x frames). WebM is not on its list.[9] |
| Slide deck | MP4Best | WebMWorks | GIFWorks | PowerPoint recommends .mp4 with H.264 video and AAC audio. WebM is on its Windows list only. A GIF inserted as a picture plays in the slide show, but not in PowerPoint for the web.[10][11] |
The video tag that replaces a GIF
A muted, looping video behaves like a GIF on a web page and weighs far less. Browsers let a video start by itself when it is muted or has no sound track.[5] The browser tries each source in order and plays the first one it understands.[6]
<video autoplay muted loop playsinline width="1280" height="720" poster="page.jpg">
<source src="page.webm" type="video/webm" />
<source src="page.mp4" type="video/mp4" />
</video>- autoplay
- Starts playing as soon as it can. Browsers allow it without a click only when the video is muted or has no sound track.
- muted
- Silences the sound, which is what lets
autoplaythrough. - loop
- Seeks back to the start when the video reaches the end.
- playsinline
- Plays inside the element instead of full screen. Required for autoplay in Safari.
- poster
- An image shown while the video downloads. Without it nothing is displayed until the first frame is available.
Attribute behaviour from MDN.[5][6] Motion that starts by itself bothers some visitors: add controls, or leave out autoplay when the system asks for reduced motion.
How does scroll recording work?
A scroll recording is made in four stages: open the page, let it settle, capture the window at one scroll position after another, and encode the frames. A screen recorder does the third stage in real time; a rendering tool does it frame by frame.
- 1
Open the page
In a browser window of a fixed size. The window is the frame of the video.
- 2
Let it settle
Wait for fonts and images, and scroll through once so content that loads late is there.
- 3
Scroll and capture
Move the page a set distance, capture the window, repeat: one image per frame.
- 4
Encode
Hand the frames to an encoder such as ffmpeg, which writes the MP4, WebM or GIF.
linear.The settings that matter
- Window size
- Sets the layout the page shows and the pixels of every frame. 1280 x 720 is a common landscape choice; a phone-sized window gives a vertical video of the mobile layout.
- Length
- Together with the height of the page it sets the scroll speed. Three quarters of a screen per second is easy to follow.
- Frame rate
- Sets how far the page jumps between frames. Total frames = seconds x frames per second.
- Easing
- A scroll that starts and stops softly looks deliberate. One even speed suits a loop.
- Rests
- A pause on the first and the last screen gives the viewer time to see where the video starts and ends.
- Lazy content
- Images that load only when they come into view appear late or blank unless the page is scrolled through once before recording.
- Sticky headers
- A header that sticks to the top stays in every frame, because the page really scrolls. Hide it with CSS if it covers too much.
- Animations
- Carousels, counters and videos on the page keep moving while it scrolls, and every moving pixel costs bytes. Stop them if the scroll is the point.
How to record a scrolling page by hand, for free
Every current computer and phone has a free screen recorder, and ffmpeg turns its recording into a GIF, an MP4 or a WebM. Record a selected area so the browser's own bars stay out, and scroll with the keyboard or a steady hand.
macOS[14]
- Press Shift-Command-5.
- Choose "Record Selected Portion" and drag the box over the page.
- Start, scroll the page, then press Command-Control-Esc to stop.
A .mov file on the desktop.
Windows 11[16]
- Press Windows logo key + Shift + R.
- Select the area of the screen to record, then select Start.
- Scroll the page, then select Stop and save.
A video file from Snipping Tool, which can also open it in Clipchamp.
iPhone and iPad[15]
- Swipe down from the top-right corner to open Control Center.
- Tap the Record button and wait for the three-second countdown.
- Scroll the page, then tap the Screen Recording button at the top of the screen and tap Stop.
A video in the Photos app.
Android[17]
- Swipe down twice from the top of the screen.
- Tap Screen record, choose what to record and tap Start.
- Scroll the page, then swipe down and tap the Screen recorder notification.
A video in Photos, under Collections, On this device, Movies.
One ffmpeg command for a good GIF
A good GIF needs a palette chosen for the video. ffmpeg's palettegen filter builds one for the whole stream and paletteuse applies it.[18] We ran this command on our own recording before printing it.
ffmpeg -i recording.mov -vf "fps=15,scale=640:-1:flags=lanczos,split[a][b];[a]palettegen=stats_mode=diff[p];[b][p]paletteuse=dither=bayer:bayer_scale=5:diff_mode=rectangle" -loop 0 page.gifffmpeg -i recording.mov -c:v libx264 -crf 22 -pix_fmt yuv420p -movflags +faststart -an -threads 2 page.mp4
ffmpeg -i recording.mov -c:v libvpx-vp9 -b:v 0 -crf 33 -an page.webm- fps=15
- Keeps 15 frames per second. Halving the frame rate roughly halves the frames to store.
- scale=640:-1:flags=lanczos
- Scales to 640 pixels wide with a sharp resampler. The height follows.
- palettegen=stats_mode=diff
- Builds one palette of up to 256 colours for the whole video, counting only the part of each frame that differs from the one before.
- paletteuse=dither=bayer:bayer_scale=5:diff_mode=rectangle
- Applies the palette with an ordered dither, and redraws only the rectangle that changed in each frame.
- -loop 0
- Loops for ever.
Record a scrolling video with one request
CurlShot records a web page scrolling from top to bottom as mp4, webm or gif from one HTTP request. It plans one scroll position per frame, puts the real page at each position, captures it and encodes the frames with ffmpeg. The page is not filmed in real time, so a busy server makes a video slower to produce, never jerky.
Left alone, the length follows the page: the model page in the filmstrip gives a video of 8.1 seconds and 194 frames. A GIF is recorded at 15 frames per second at most and scaled to 640 pixels wide unless you ask for another width. A video counts as one screenshot against your quota, and takes about twice as long to make as it lasts.
Start with the scrolling video tool, read every video option in the docs, and use async rendering for long videos.
What it does not do
- No sound. Every video is written without an audio track.
- No AV1, animated WebP or APNG output: the three video formats are
mp4,webmandgif. - No typing or clicking while it records. Clicks, scripts and custom CSS run before the recording starts; during it the page only scrolls.
- Nothing longer than 30 seconds, and a plan can set a lower maximum.
- No transparent background, element or clipped-area videos:
omit_background,selector, theclip_*options,image_heightandfull_page=trueare refused with a video format.
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com&format=mp4&video_duration=8&video_fps=24&video_scroll_easing=ease_in_out" \
--output page.mp4A page that fits in the window has nothing to scroll and is recorded standing still.
- formatdefault png
- MP4 is H.264, WebM is VP9, GIF gets a palette built from the whole recording. Values:
mp4,webm,giffor a video. - video_durationdefault none
- Exact length of the video. Left out, the length follows the height of the page at about three quarters of a screen per second. Values: 1 to 30 seconds.
- video_max_durationdefault 30
- Ceiling when the length follows the page. A taller page then scrolls faster. Values: 1 to 30 seconds.
- video_fpsdefault 24 (gif: 15)
- Frames per second. Values: 5 to 30; gif at most 15.
- video_scrolldefault true
- Scroll from top to bottom. With
falsethe first screen is recorded without moving, for 4 seconds unless a length is set. Values:true,false. - video_scroll_backdefault false
- Scroll back to the top at the end, so a loop has no jump. Values:
true,false. - video_scroll_easingdefault ease_in_out
- A soft start and stop with one even speed in between, or one speed throughout. Values:
ease_in_out,linear. - viewport_width, viewport_heightdefault 1280 x 720 for a video
- The window, and so the frame.
viewport_devicesets a phone or tablet instead. Values: one frame holds at most 2,073,600 pixels (1920 x 1080). - image_widthdefault frame width (gif: 640)
- Scales the video down. The height follows. A video is never scaled up. Values: up to the frame width.
- image_qualitydefault 80
- How hard an MP4 or WebM is compressed. 80 means CRF 22 for H.264 and CRF 33 for VP9. Values: 1 to 100.
- full_page_max_heightdefault 20000
- How far down the video scrolls on a very tall page. Values: 100 to 30,000 pixels.
Video format glossary
- Container
- The file format that wraps the video and sound streams: MP4 and WebM are containers. The file extension names the container, not the codec.
- Codec
- The method that compresses and decompresses the video itself: H.264, VP9 and AV1 are codecs. One container can hold different codecs.
- Frame rate
- The number of images shown per second (fps). It sets how smooth motion looks, and higher frame rates give larger files.
- Bitrate
- The amount of data per second of video. File size = bitrate x length. A constant-quality setting such as CRF lets the bitrate follow what the frames need.
- Palette
- The table of colours a GIF frame may use, 2 to 256 entries. Every pixel stores the number of one entry.
- Key frame
- A frame stored whole. The frames after it store only what changed, so a player must start decoding at a key frame.
- Loop
- Playing again from the start when the end is reached. A video loops when its player says so; a GIF carries its loop count in the file.
- Dithering
- Mixing dots of the available colours so that an area looks like a colour the palette does not have.
Questions people ask
How do I make a video of a website scrolling from top to bottom?
Either record your screen while you scroll (Shift-Command-5 on a Mac, Windows logo key + Shift + R on Windows 11) and convert the recording with ffmpeg, or let a tool do the scrolling. With CurlShot you send the address of the page with format=mp4 and get the video back: the page in a 1280 by 720 window, scrolled from the top to the bottom at a steady pace.
Should a website recording be MP4, WebM or GIF?
MP4 with H.264 video unless you have a reason not to: every browser, phone, video editor and slide deck plays it. WebM with VP9 is usually smaller and suits web pages, with an MP4 as the fallback source. A GIF is the largest of the three and has only 256 colours per frame, so keep it for places that show images but not video, such as an email or a README file.
Why is a GIF so much bigger than an MP4?
A GIF compresses each frame on its own with lossless LZW, after reducing it to at most 256 colours. A video codec such as H.264 or VP9 stores a full key frame now and then and only the changes in between, and it is allowed to lose detail. In our measurement of 120 frames at 640 x 360, the GIF was 8.52 MB, the MP4 0.34 MB and the WebM 0.25 MB.
How many frames per second does a scrolling video need?
A scroll looks smooth at 24 frames per second, and 15 is enough for a GIF. What the eye notices is how far the page jumps between two frames: a page that scrolls 3,600 pixels in 8 seconds moves 19 pixels per frame at 24 fps and 92 pixels per frame at 5 fps. More frames per second also means a larger file.
How do I replace a GIF with a video on a web page?
Use a video element with the attributes autoplay, muted, loop and playsinline, and give it a WebM source followed by an MP4 source. Browsers allow autoplay when the video is muted or has no sound track, Safari requires playsinline for it, and the browser plays the first source it understands.
Can I put a video in a GitHub README or pull request?
In an issue, a pull request or a comment, yes: GitHub accepts .mp4, .mov and .webm files there, up to 10 MB on a free plan and 100 MB on a paid plan, and recommends H.264. Its documentation does not describe video attachments for README files. A GIF committed to the repository works in a README, because it is an image.
Does a video from CurlShot have sound, and how long can it be?
No sound: every video is written without an audio track. A video is 1 to 30 seconds long, and a plan can set a lower maximum. Without video_duration the length follows the height of the page, at about three quarters of a screen per second.
Sources
- [1]MDN Web Docs, Media container formats (file types). Checked .
- [2]MDN Web Docs, Web video codec guide. Checked .
- [3]MDN Web Docs, Image file type and format guide. Checked .
- [4]CompuServe, hosted by W3C, Graphics Interchange Format, version 89a. Checked .
- [5]MDN Web Docs, Autoplay guide for media and Web Audio APIs. Checked .
- [6]MDN Web Docs, The video embed element. Checked .
- [7]GitHub Docs, Attaching files. Checked .
- [8]GitHub Docs, About the repository README file. Checked .
- [9]X Developer Platform, Media best practices. Checked .
- [10]Microsoft Support, Video and audio file formats supported in PowerPoint. Checked .
- [11]Microsoft Support, Add an animated GIF to a slide. Checked .
- [12]Microsoft Support, The animated graphic in my e-mail message does not work. Checked .
- [13]Slack Help Center, Add files to Slack. Checked .
- [14]Apple Support, How to record the screen on your Mac. Checked .
- [15]Apple Support, Record the screen on your iPhone or iPad. Checked .
- [16]Microsoft Support, Use Snipping Tool to capture screenshots. Checked .
- [17]Google Android Help, Take a screenshot or record your screen on your Android device. Checked .
- [18]FFmpeg, FFmpeg filters documentation: palettegen and paletteuse. Checked .
- [19]Can I use, WebM video format: browser support. Checked .
Read next
- ComparisonPNG, JPEG, WebP or PDF for website screenshotsA decision flow, a comparison table and our own file-size measurements for choosing PNG, JPEG, WebP or PDF when you save a screenshot of a web page.
- How-toFull-page screenshot on every device and browserExact keys and menu names to screenshot a whole web page in Chrome, Firefox, Edge, Safari, iPhone, iPad and Android, checked against each vendor.
- Cheat sheetSocial preview image sizes: the OG cheat sheetOpen Graph image sizes for Facebook, LinkedIn, WhatsApp, iMessage, Discord, Slack and Google Discover, drawn to scale, with the tags and the fixes.