Check an AI clip against Instagram's Reel rules in Python
Instagram's help page gives three Reel limits: 1.91:1 to 9:16, 30 FPS and 720 pixels. This Python check reads Sume's probe and prints PASS or FAIL for each.
Instagram's help page for Reels gives three technical limits you can test on a file: an aspect ratio between 1.91:1 and 9:16, a minimum frame rate of 30 FPS, and a minimum resolution of 720 pixels. A short Python script can read the clip's probe from Sume and print PASS or FAIL for each before you upload.
The limits come from Reel size & aspect ratios on Instagram (read 2026-10-03). The page says 720 pixels without naming the side, so the script tests the shorter side. A 1080x1920 file passes on either reading, and so does 720x1280.
Where the numbers come from
Video inspect returns probe.width, probe.height and probe.fps for a Sume-hosted clip, with frames: false to skip the stills. fps can be null, and stills report is_still: true, so the script treats a missing rate as a fail rather than guessing.
The check
The ratio test is width divided by height, compared with 9/16 and 1.91. The script polls the inspect resource if the submit comes back as queued rather than finished.
import json, os, time, urllib.request as u
def call(method, path, body=None, key=None):
h = {"Authorization": "Bearer " + os.environ["SUME_API_KEY"],
"Content-Type": "application/json"}
if key:
h["Idempotency-Key"] = key
data = json.dumps(body).encode() if body is not None else None
req = u.Request("https://api.sume.com" + path, data, h, method=method)
with u.urlopen(req) as r:
out = json.load(r)
return out.get("data", out)
def probe(url, key):
d = call("POST", "/v1/video-inspect", {"video_url": url, "frames": False}, key)
for _ in range(30):
if d.get("probe"):
return d["probe"]
time.sleep(2)
d = call("GET", "/v1/video-inspect/" + d["id"])
raise TimeoutError("probe not ready")
p = probe("https://media.sume.com/artifacts/artf_demo/clip.mp4", "reel-check-001")
rules = {
"ratio 1.91:1 to 9:16": 9 / 16 <= p["width"] / p["height"] <= 1.91,
"fps >= 30": (p["fps"] or 0) >= 30,
"shorter side >= 720": min(p["width"], p["height"]) >= 720,
}
for name, ok in rules.items():
print("PASS" if ok else "FAIL", name)
Sample verdicts
These sizes show where each rule bites. The ratio column is width divided by height.
| File | Ratio | Result |
|---|---|---|
| 1080x1920 at 30 fps | 0.5625 | Pass |
| 1920x1080 at 30 fps | 1.778 | Pass |
| 2560x1080 at 30 fps | 2.370 | Fail: wider than 1.91:1 |
| 1080x1920 at 24 fps | 0.5625 | Fail: under 30 FPS |
| 480x854 at 30 fps | 0.562 | Fail: under 720 |
What to do with a fail
A frame-rate fail is a re-encode, and video trim can conform it with output.fps. For a ratio that is too wide, crop or reframe the clip before it reaches Instagram. A resolution fail means the clip was generated or exported too small, so regenerate at a higher setting instead of stretching it.
The script checks only what the help page states. It does not predict whether the Instagram app or API will accept a file for other reasons, such as codec or file size.
Run it on the whole batch
The script prints three lines per file, so looping it over a folder of URLs gives you a quick table of which clips need work. Each probe is billed by Modal compute, so keep frames: false to avoid the still extraction you do not need here.
Sources
Related posts
More in Media tools
- Check the transcript before captions: Scribe v2 error tiers
ElevenLabs lists Scribe v2 error rates by language group. Before burning captions on Sume, pass script_text or your own words so a wrong transcript never ships.
- Children's captions at 17 characters per second: Netflix rule and Sume
Netflix's English style guide sets 20 chars per second for adults and 17 for children. See how to approximate it with Sume caption phrasing overrides.
- Cloudflare Images segment=foreground vs Sume RMBG PNG alpha
Cloudflare Images removes a background with segment=foreground, but its listed output formats lack PNG. Sume RMBG returns PNG artifacts with alpha.
- Cloudflare transforms: 100 MB, 10 min input vs Sume trim's 1800 s
Cloudflare Media Transformations takes input up to 100 MB and 10 minutes and returns 1-60 s. Sume trim reads sources to 1800 s and cuts up to 900 s.
Written by Sume