Dribbble shot video: 20 MB limit and the bitrate budget

Dribbble allows MOV or MP4 video up to 20MB and recommends 1600 px width. What 20MB means in average Mbps by clip length, and which Sume Timeline fields help.

4 min readSume
All posts

A Dribbble shot video must be MOV or MP4 and at most 20MB, and Dribbble recommends a minimum width of 1600 pixels. Twenty megabytes is a total of 160,000,000 bits, so a 30-second clip averages at most 5.33 Mbps for video and audio together. Sume's Timeline has no bitrate field, so the lever you control is length.

What Dribbble accepts

Dribbble's page says it eased its requirements: there is no longer a fixed ratio or height. The page does not define whether MB means 1,000,000 or 1,048,576 bytes, so the table shows both.

Dribbble shot file requirements (read 2026-10-04)
ContentTypesMaximumRecommended
Imagepng, jpg, gif10MBwidth of at least 1600 px
Videomov, mp420MBwidth of at least 1600 px

The bitrate budget

Average total bitrate is the cap in bits divided by the clip length in seconds. Anything above the average will overshoot unless the encoder lowers it elsewhere.

Average bitrate that fits 20MB (computed)
Clip lengthIf MB = 1,000,000 bytesIf MB = 1,048,576 bytes
15 s10.67 Mbps11.18 Mbps
30 s5.33 Mbps5.59 Mbps
60 s2.67 Mbps2.80 Mbps
90 s1.78 Mbps1.86 Mbps
120 s1.33 Mbps1.40 Mbps

What Sume lets you control

Timeline 1.0 takes output width and height as even integers from 256 to 2160, so 1600x900 is a legal frame. It also takes output.fps of 24, 25, 30 or 60. It rejects codec, crf and other encoder keys with a 400, so you cannot set a target bitrate.

The unbilled plan route returns duration, segment count, billable minutes and estimated cost, but no file size. So render, download and measure. Timeline costs $0.10 per output minute rounded up, so a clip under a minute costs $0.10. If the file is over, cut length with video trim, which costs $0.02 per job.

Budget and check script

import asyncio, os

DECIMAL = 20 * 1_000_000
BINARY = 20 * 1024 * 1024

def mbps(seconds, cap):
    return cap * 8 / seconds / 1_000_000

async def main():
    for seconds in (15, 30, 60, 90, 120):
        print(seconds, round(mbps(seconds, DECIMAL), 2), round(mbps(seconds, BINARY), 2))
    path = "shot.mp4"
    if os.path.exists(path):
        size = os.path.getsize(path)
        print(path, size, "ok" if size <= DECIMAL else "over the 20MB reading")

asyncio.run(main())

Before you upload

  • Frame is at least 1600 px wide.
  • File measured with the decimal reading, 20,000,000 bytes, to be safe.
  • Keep a shorter cut ready if the render lands over.

Sources

Related posts

More in Use cases

All Use cases posts

Written by Sume