Gate a Format run on TikTok limits: artifact size, length, pixels

Check a Sume Format run's artifacts[] for size, duration and dimensions against TikTok's non-Spark limits before upload. A Python gate under 30 lines.

5 min readSume
All posts

Every terminal Format run receipt carries artifacts[] with size_bytes, duration_ms, width and height for each file. That is enough to test a finished video against TikTok's non-Spark limits before anyone uploads it: at most 500 MB, up to 10 minutes, and at least 540x960 for 9:16. The check below is 28 lines of Python and runs as written.

Where the numbers come from

The run receipt documents artifacts[] as each durable file the run generated, shaped { id, type, url, content_type, size_bytes, width, height, duration_ms, checksum_sha256 }, empty until the run is terminal. The structured-output page types size_bytes and duration_ms as integer or null, and notes that duration_ms is checked against the file, so a value you read back is the artifact's, or it is null.

TikTok's page (read 2026-10-08) lists the limits the script uses.

Limits used by the check, as of 2026-10-08
CheckLimitReceipt field
File size500 MB or lesssize_bytes
Durationup to 10 minutesduration_ms
9:16 pixelsat least 540x960width, height

The check

The script treats null as a failure, not a pass, because a missing value means the number was not measured. It also refuses a run that is not completed, because artifacts[] is only complete once the run is terminal.

MAX_BYTES = 500 * 1000 * 1000      # TikTok: 500 MB or less
MAX_MS = 10 * 60 * 1000            # TikTok: up to 10 minutes
MIN_W, MIN_H = 540, 960            # TikTok 9:16 minimum

def problems(receipt):
    if receipt.get("status") != "completed":
        return ["run status is %s" % receipt.get("status")]
    found = [a for a in receipt.get("artifacts", []) if a.get("type") == "video"]
    if not found:
        return ["no video artifact"]
    out = []
    for a in found:
        need = ("size_bytes", "duration_ms", "width", "height")
        missing = [k for k in need if a.get(k) is None]
        if missing:
            out.append("%s: %s is null" % (a["id"], ", ".join(missing)))
        elif a["size_bytes"] > MAX_BYTES:
            out.append("%s: over 500 MB" % a["id"])
        elif a["duration_ms"] > MAX_MS:
            out.append("%s: over 10 minutes" % a["id"])
        elif a["width"] < MIN_W or a["height"] < MIN_H:
            out.append("%s: below 540x960" % a["id"])
    return out

sample = {"status": "completed", "artifacts": [{"id": "artf_1", "type": "video",
    "size_bytes": 4210233, "duration_ms": 12000, "width": 1080, "height": 1920}]}
print(problems(sample) or "ok")

What it does not check

It does not read the bitrate (TikTok wants at least 516 kbps), the container or the codecs; none of those is a field on the artifact. Compute a rough bitrate yourself as size_bytes x 8 / duration seconds: the sample is 4,210,233 x 8 / 12 = about 2.81 Mbps. Anything near the floor deserves a probe with video inspect.

It also assumes a 9:16 deliverable. For 16:9 the minimum is 960x540, and for 1:1 it is 640x640. Add the ratio to your Format's output_schema so the check knows which minimum applies.

Wiring it in

Run it in the webhook handler or the poll loop after status reaches completed. If it returns problems, treat the run as a failed delivery in your own system and retry with a changed instruction, rather than uploading anyway.

Mind the 500 MB reading: TikTok writes MB, and the script uses 500 x 1,000,000 bytes, which is the stricter reading.

Why gate before upload

A rejected upload costs you a round trip and, for a team, a manual step. Every limit this script tests is a number TikTok's page states for non-Spark ads: 500 MB, 10 minutes and the per-ratio minimum sizes. The script reads the same numbers off the Format run receipt, so the answer is available the moment the run completes and before any bytes leave your account.

Keep the limits in one table at the top of your own copy so a change on TikTok's page is a one-line edit. Re-read the page on the date you ship, because the sample reflects the page as read on 2026-10-08.

A pass here means only that three numbers are inside TikTok's stated limits. It is not a check of content rules, audio, captions or bitrate, and it does not replace the checks TikTok runs on upload.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume