Pre-flight check for Shorts and TikTok ad files: an ffprobe script

A 30-line Python script reads a rendered MP4 with ffprobe and flags it if it is not vertical, over 3 minutes, under 540x960, over 500 MB or under 516 kbps.

4 min readSume
All posts

After a Sume render finishes, check the file before you upload it. The script below uses ffprobe to read width, height, duration, size and bit rate, and flags the limits from YouTube's Shorts page (up to 3 minutes, vertical) and TikTok's ad page (540x960 minimum for 9:16, 500 MB, 516 kbps). It exits 1 if anything fails, so you can run it in a job step.

The script

It needs ffprobe on the PATH and a local file, for example one you downloaded from /v1/videos/{job_id}/content. There is no async code, so no event loop is involved.

import json
import subprocess
import sys
def check(path):
    raw = subprocess.run(
        ["ffprobe", "-v", "error", "-print_format", "json",
         "-show_format", "-show_streams", path],
        check=True, capture_output=True, text=True).stdout
    data = json.loads(raw)
    v = next(s for s in data["streams"] if s["codec_type"] == "video")
    f = data["format"]
    w, h = int(v["width"]), int(v["height"])
    secs, size, bps = float(f["duration"]), int(f["size"]), int(f["bit_rate"])
    bad = []
    if h <= w:
        bad.append("not vertical")
    if secs > 180:
        bad.append("over 3 minutes (Shorts)")
    if abs(w * 16 - h * 9) <= 16 and (w < 540 or h < 960):
        bad.append("under 540x960 (TikTok 9:16)")
    if size > 500_000_000:
        bad.append("over 500 MB (TikTok)")
    if bps < 516_000:
        bad.append("under 516 kbps (TikTok)")
    return bad

if __name__ == "__main__":
    problems = check(sys.argv[1])
    print("\n".join(problems) or "ok")
    sys.exit(1 if problems else 0)

What each check maps to

Checks in the script and the platform page they come from (read 2026-10-06)
CheckLimitSource
Verticalheight greater than widthYouTube Shorts page
Length180 seconds or lessYouTube Shorts page
9:16 size540x960 minimumTikTok ad page
File size500 MB or less (script uses 500,000,000 bytes)TikTok ad page
Bit rate516 kbps or moreTikTok ad page

Wiring it into a pipeline

Run the script as the last step before upload and treat a non-zero exit as a blocking failure. In a batch, run it on every file, not a sample, since a single odd clip, such as one with a very low bit rate, is the typical failure. Collect the messages into a report so a reviewer can see which clip failed and why.

Keep the limits in one place. When a page changes, you edit one number and re-run, rather than hunting through steps. A small config file with the five values and their source URLs and read dates does the job and makes the next audit faster.

Do not make the script block on things the pages do not state. It is tempting to add rules from third-party guides, but a rule you cannot trace to a platform page produces false failures, and you will end up ignoring the tool. Add a check when a real upload fails and you have learned the reason.

Where it is too strict or too loose

The size check is a decimal-megabyte reading of the page's 500 MB; the page does not say which it means. The 9:16 test allows a few pixels of rounding, so a 1080x1920 file passes the size minimum and a 270x480 file fails. The script applies the TikTok minimum only to 9:16 files, and it checks nothing for Spark Ads, whose row on the page lists no size. It does not read the codec because neither page names one. If you reach a rejection the script did not catch, the platform's upload message is the source of truth, and you should add the rule here.

Run it after the last step of your pipeline. The order of steps for a vertical Short puts captions last, so check after the captions render.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume