Video Covers
A video's cover is the still image people see before they press play. Use setVideoCover to choose a video's cover in one of two ways:
- A frame of the video: pass
offsetMs, the position of the frame in milliseconds. - Your own image: pass
imageUrlto use an image at a public URL, orimageMediaIdto use an image from your Content Library.
The cover belongs to the video in your Content Library, not to a single post. Every post that uses the video gets the cover, including posts that are already scheduled, as long as the cover is set before the post publishes. This is the same cover you can pick in the Postpone web app.
Supported Platforms
| Platform | Post types | Frame of the video (offsetMs) | Your own image (imageUrl, imageMediaId) |
|---|---|---|---|
| Reels | ✅ | ✅ | |
| TikTok | Videos | ✅ | ❌ Uses the first frame instead |
| Reels | ✅ | ✅ | |
| Videos | ✅ | ✅ | |
| Video Pins | ✅ | ✅ |
Covers are ignored everywhere else, including Instagram Stories and carousels, Facebook Stories, and platforms not listed above, such as YouTube, X (Twitter), and Threads. On those, the platform picks the cover itself.
offsetMs when you post the same video to several platforms. It's the only option that works on TikTok, and Instagram and TikTok pick the frame from the video themselves at that offset. For Facebook, LinkedIn, and Pinterest, Postpone captures the frame at that offset as an image and uploads it as the cover.Setting a Cover
mutation setVideoCover(
$mediaId: ID!
$offsetMs: Int
$imageUrl: String
$imageMediaId: ID
) {
setVideoCover(
mediaId: $mediaId
offsetMs: $offsetMs
imageUrl: $imageUrl
imageMediaId: $imageMediaId
) {
success
media {
id
name
coverImage {
url
offsetMs
}
}
errors {
field
code
message
}
}
}
{
"mediaId": "1002",
"offsetMs": 2500
}
{
"data": {
"setVideoCover": {
"success": true,
"media": {
"id": "1002",
"name": "product-launch.mp4",
"coverImage": {
"url": "https://cdn.example.com/9c8b7a6d/",
"offsetMs": 2500
}
},
"errors": []
}
}
}
0 or more, and at least 100 ms before the end of the video's duration, since the last frame starts before the video ends. For example, 2500 uses the frame 2.5 seconds into the video.Pass exactly one of offsetMs, imageUrl, or imageMediaId. Setting a cover replaces the video's existing cover, if it has one.
The returned coverImage.url is always an image you can show as a preview. For offsetMs covers, it's the frame captured at that offset.
Using an Image from a URL
{
"mediaId": "1002",
"imageUrl": "https://example.com/images/launch-cover.jpg"
}
The image doesn't need to match the video's size, but platforms crop covers that don't match the video's aspect ratio. Use an image with the same aspect ratio as the video for the best results.
Using a Local Image
To use an image file on disk as a cover, first add it to your Content Library with a direct upload, then pass the returned media id as imageMediaId:
{
"mediaId": "1002",
"imageMediaId": "1003"
}
Removing a Cover
removeVideoCover removes the video's cover. Posts that use the video go back to the cover each platform picks by default. Calling it on a video without a cover is a no-op that succeeds.
mutation removeVideoCover($mediaId: ID!) {
removeVideoCover(mediaId: $mediaId) {
success
media {
id
coverImage {
url
}
}
errors {
field
code
message
}
}
}
{
"mediaId": "1002"
}
{
"data": {
"removeVideoCover": {
"success": true,
"media": {
"id": "1002",
"coverImage": null
},
"errors": []
}
}
}
Reading a Video's Cover
The coverImage field of MediaType returns the video's current cover, or null when it has none:
query media($ids: [ID]) {
media(ids: $ids) {
objects {
id
duration
coverImage {
url
offsetMs
}
}
}
}
offsetMs is set for covers chosen from a frame of the video and null for covers made from your own image.
Scheduling a Reel with a Cover
Covers are set on Content Library videos, so the video has to be in your Content Library before you set its cover.
Upload the video
Upload the video with uploadMediaFromUrl or a direct upload, and keep the returned media id. If the video is already in your Content Library, find its id with the media query instead.
Set the cover
Call setVideoCover with the video's id as mediaId:
{
"mediaId": "1002",
"offsetMs": 2500
}
Schedule the post
Pass the video's id in media when you schedule the post. For example, an Instagram Reel:
{
"input": {
"username": "myhandle",
"caption": "Our new collection is here ✨",
"media": [{ "id": "1002" }],
"submissions": [
{
"postAt": "2026-12-01T15:30:00Z",
"mediaType": "REEL"
}
]
}
}
See Instagram for the full scheduleInstagramPost mutation.
The post publishes with the cover. You can also change the cover after scheduling, as long as you do it before the post publishes.
url when scheduling, Postpone adds it to your Content Library at that point. To give it a cover, find it with the media query and call setVideoCover before the post publishes, or upload it first as shown above.Rate Limits
Each setVideoCover call that passes validation uploads an image, so it counts against the media upload rate limit, along with the general API rate limit. removeVideoCover only counts against the general API rate limit.
Common Errors
| Error | Cause |
|---|---|
Provide exactly one of: offsetMs, imageUrl, imageMediaId. | None or more than one cover option was passed. |
Media not found. | mediaId doesn't match a file in your Content Library. |
Covers can only be set on videos. | mediaId is an image or a GIF. |
offsetMs cannot be negative. | offsetMs is below 0. |
offsetMs must be … or less for this video. | offsetMs is at or too close to the end of the video. Check the video's duration, in milliseconds, and pick an earlier frame. |
Cover image media not found. | imageMediaId doesn't match a file in your Content Library. |
The cover image must be a JPEG, PNG, or WebP image. | imageUrl or imageMediaId points to a video, a GIF, an SVG, or a file that isn't an image. |
Invalid cover image URL. | imageUrl isn't a valid public http or https URL. |
Failed to upload the cover image. | The image at imageUrl couldn't be downloaded, or the frame couldn't be captured. Check that the URL is public, then try again. |
Media upload rate limit exceeded | You've hit the media upload rate limit. |