Images and video
Attach images and video that upload directly over a presigned PUT and are validated against each channel's limits, moving through processing to ready or failed.
Attach images and video to a post from the editor’s file bar. Each file uploads directly to storage over a presigned PUT, is scanned and validated against every target channel’s own limits, and moves through a small readiness state machine — processing → ready → failed — that the composer surfaces honestly.
Uploading media
Picking a file starts a direct upload: the client requests an upload plan, receives a short-lived presigned PUT URL, and sends the bytes straight to the bucket — so large images (and video) never round-trip through the app server. The composer shows an uploading tile with live progress as the bytes go up. When storage can’t presign (in-memory development storage), it transparently falls back to an inline upload path.
Once the bytes land, the asset’s type is verified by a magic-byte sniff (not just the declared MIME), and the file enters processing.
Processing, ready, and failed
Every asset folds into one of three readiness buckets that all surfaces act on:
- Processing — still in flight (uploaded, scanning, or deriving). Wait for it.
- Ready — clean and publishable. The tile shows the real thumbnail.
- Failed — terminal: the upload broke, the file was rejected, or a scan flagged it. Remove it and add another.
A post won’t publish or schedule while any attached asset is still processing or has failed — the publish button holds with a calm “media is still processing” wait, or a “remove the media that failed” prompt. Neither is treated as a content problem with a channel; media readiness rides alongside the per-channel fit-check. See Preflight and fixes.
Per-platform media rules
Each channel enforces its platform’s real limits on count, size, format, aspect ratio, and mixing:
| Channel | Images | Video | Mixing |
|---|---|---|---|
| Up to 9, 10 MB each (PNG/JPEG) | One MP4, ≤500 MB, ≤30 min | Single-kind | |
| X | Up to 4, 5 MB each (JPEG/PNG/GIF/WebP) | One MP4, ≤512 MB, ≤140 s | Single-kind |
| Up to 10, 8 MB each (JPEG/PNG); required | Reel: one 9:16 MP4, ≤1 GB, 3 s–15 min | Single-kind per format; free in carousels | |
| Up to 10, 10 MB each (JPEG/PNG/GIF) | One MP4/MOV, ≤1 GB; Reel: 9:16, 3–90 s | Single-kind |
In prose: LinkedIn accepts up to nine PNG or JPEG images at 10 MB each, or a single MP4 up to 500 MB and 30 minutes. X takes up to four images (JPEG, PNG, GIF, or WebP) at 5 MB each, or one MP4 up to 512 MB and 140 seconds. Instagram requires media on a post — up to ten JPEG or PNG images — and a reel must be a single 9:16 MP4 up to 1 GB running 3 seconds to 15 minutes. Facebook allows up to ten JPEG, PNG, or GIF images at 10 MB each, or one MP4/MOV video up to 1 GB, and a Facebook reel must be 9:16 and run 3 to 90 seconds.
Mixing images and video
Most formats are single-kind: a post carries either images or one video, never both — LinkedIn, X, and a Facebook feed post all enforce this. The exception is an Instagram carousel, which mixes image and video slides freely up to its total slide count. When a set breaks a mixing rule, preflight surfaces it as a fixable failure before publish rather than at publish time.
Alt text
Every attached image can carry alt text, set per use on the media tile. Alt text is stored on the content reference, so the same asset can describe itself differently in different posts.
Per-channel variants
One story becomes a separate, independently editable copy per channel. A sync bar tracks whether each still matches the story or has diverged.
Preflight and fixes
The fit-check validates each placement against its platform's real rules and returns a per-placement verdict — passing, or failing with one-click Fixes.