Blur and dim a video background so captions stay readable via API
Use video-filter with a dim op and a gblur filtergraph: $0.02 per encode, a free check first, 300 s source limit. Whole-frame only. Read 2026-10-10.

Send one clip to video filter with a dim op of about 0.45 and a gblur filtergraph. You get a darker, softer copy of the whole frame for $0.02 per encode job, and the check that proves the program is valid before you pay is free.
The pattern fits a common problem: text or captions sit on top of a busy clip and lose contrast. Dimming the luma and blurring the picture are the two cheapest fixes, and both are inside the allowlist that Sume compiles on its own worker. The table captions below cite the docs page as read 2026-10-10.
What the two pieces do
ops[] is the ordered, validated program. A dim op takes one number, amount, in the range greater than 0 and up to 1. At 0.45 the picture is darker, at 1 nothing changes, and 0 or anything above 1 is refused with video_filter_amount_out_of_range. Black stays black and chroma does not move, because Sume multiplies luma only.
filtergraph is a filters-only graph that Sume applies after ops[]. The allowlist in VIDEO_FILTER_GRAPH_ALLOWED_FILTERS has four blur filters: boxblur, gblur, avgblur and smartblur. Sume adds the input and output labels itself, so you send only the filter expression.
Order matters. Sume runs the ops first and the filtergraph second, so the dim lands on the sharp picture and the blur then smooths the result. Stream specifiers such as [0:v], file paths and external inputs are refused with invalid_filtergraph, and so is any filter that is not on the list, with unknown_filter naming the token and the allowlist.
Run the free check first
POST /v1/video-filter/check runs the same schema, allowlist and source-preflight checks as the encode. It does not create a job, reserve credits or start the encoder, and it needs no Idempotency-Key. A valid answer has valid, encode: "not_run", the compiled filter names and an estimate, plus a next_action of submit_video_filter or fix_program_and_recheck.
A program that passes can still fail on the worker, for example on a bad expression or memory. In that case you get a structured job error rather than a validation answer. Keep that in mind before you queue 200 clips.
curl -X POST https://api.sume.com/v1/video-filter/check \
-H "Authorization: Bearer $SUME_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"video_url": "https://media.sume.com/artifacts/artf_demo/talk.mp4",
"ops": [{ "op": "dim", "amount": 0.45 }],
"filtergraph": "gblur=sigma=12"
}'Limits that matter for this recipe
The source must already be a Sume-hosted clip, so a clip from elsewhere has to be imported or generated on Sume first. A source longer than 300 seconds fails with output_duration_exceeded; cut it with video trim first.
| Item | Value |
|---|---|
| Encode price | $0.02 per job |
| Check price | Free |
| Ops per request | 8 at most |
| Filtergraph length | 2048 characters, 32 named filters |
| Source length | 300 s at most |
| Source location | media.sume.com clip in your workspace |
What this does not do
The blur and the dim cover the entire frame. This page documents no region mask or face-tracking blur, and drawtext and subtitles are off the allowlist, so you cannot burn text in with this route. Captions are a separate job: video captions has a fixed estimate for clips of 60 seconds or less, and the filter docs point caption plates to the HyperFrames compose and caption assembler path.
If the blur is too strong, lower sigma and recheck; the check is free, so tuning costs nothing until you encode. If the clip still reads busy, raise the dim amount toward 0.35 instead of stacking more blur. The output keeps the geometry, frame rate and audio of the source unless the program changes them.
Cost for a batch
One encode is $0.02, so 50 clips cost 50 x $0.02 = $1.00 and 200 clips cost $4.00. Because there is no provider inference, the price does not rise with clip length inside the 300-second limit. Submit each paid encode with its own Idempotency-Key so a retry after a timeout does not create a second charge.
Default mode is async, so poll GET /v1/jobs/:id/status and then GET /v1/jobs/:id/result. The result has a new video_url, never the source, plus ops_applied and the compiled filters[], which lets you confirm that the dim and the blur both ran before you hand the new MP4 to the next step.
Sources
Related posts
More in Media tools
- Crop a 16:9 master to 1:1 and 4:5: widths 0.5625 and 0.45
A centred 1:1 crop of 16:9 keeps 0.5625 of the width; 4:5 keeps 0.45. LinkedIn lists both ratios. Exact Sume video-filter crop values with rounding notes.
- Instagram's 1% aspect tolerance: which odd sizes still pass 9:16
Instagram video ad pages list a 1% aspect ratio tolerance. Here is the arithmetic for 9:16 widths, and how to render an exact 1080x1920 shot in Sume Timeline.
- Instagram Stories ad at 16 seconds: split into cards or trim?
Instagram may split Stories video ads of 16 seconds or longer into one to three cards. Cut under 16 seconds with one Sume video trim at $0.02 to keep one card.
- LinkedIn video ads max out at 1920 px per edge: set the size
LinkedIn lists 360 to 1920 pixels per edge for video ads. Sume Timeline allows up to 2160, so set 1080x1920 or 1920x1080 yourself and keep sizes in range.
Written by Sume