Generate creator-style product stills, upscale and polish one, then animate it into a short UGC video.
UGC Product Video
Use this workflow when you want a creator-style product ad. It starts from your trained creator model, produces a recognizable product still, upscales the best still, improves it with a known image model, and uses the final image as the first frame for a short video.
Before you start
Complete Setup and Training first. These snippets assume
modelId or model_id, triggerImageGeneration, triggerImageUpscaling,
triggerVideoGeneration, waitForJob, and firstImage are already available.
Workflow
- Generate a product still with
POST /images/generation. - Upscale the selected still with
POST /images/upscaling. - Create a polished ad still with
POST /images/generation. - Animate the polished still with
POST /videos/generation.
Generate the creator product still
This uses the trained model ID, so the generated image should preserve the trained identity while following the product prompt.
const trainedImageJobId = await triggerImageGeneration({
modelID: modelId,
prompt:
'authentic UGC product photo, creator holding a skincare bottle near a bathroom mirror, natural phone camera lighting',
width: 1024,
height: 1024,
numImages: 2,
enhanceFace: true,
})
const trainedImage = firstImage(await waitForJob(trainedImageJobId), 'UGC trained image')trained_image_job_id = trigger_image_generation(
{
"modelID": model_id,
"prompt": "authentic UGC product photo, creator holding a skincare bottle near a bathroom mirror, natural phone camera lighting",
"width": 1024,
"height": 1024,
"numImages": 2,
"enhanceFace": True,
}
)
trained_image = first_image(wait_for_job(trained_image_job_id), "UGC trained image")Upscale the selected still
Upscale the best generated still before using it as a reference image for a cleaner campaign version.
const upscaleJobId = await triggerImageUpscaling({
imageID: trainedImage.id,
})
const upscaledImage = firstImage(await waitForJob(upscaleJobId), 'UGC upscale')upscale_job_id = trigger_image_upscaling(
{
"imageID": trained_image["id"],
}
)
upscaled_image = first_image(wait_for_job(upscale_job_id), "UGC upscale")Improve the still with a public image model
Use a public image model such as gpt-image-2 for a more polished ad still. The upscaled image
becomes the visual reference.
const polishedImageJobId = await triggerImageGeneration({
modelID: 'gpt-image-2',
prompt:
'polished social ad still, creator holding the skincare bottle, clean bathroom counter, premium but natural UGC style',
aspectRatio: '16:9',
numImages: 1,
referenceImageURLs: [upscaledImage.url],
options: {
openai: {
imageSize: '1K',
outputFormat: 'jpeg',
quality: 'high',
},
},
})
const polishedImage = firstImage(await waitForJob(polishedImageJobId), 'UGC polished image')polished_image_job_id = trigger_image_generation(
{
"modelID": "gpt-image-2",
"prompt": "polished social ad still, creator holding the skincare bottle, clean bathroom counter, premium but natural UGC style",
"aspectRatio": "16:9",
"numImages": 1,
"referenceImageURLs": [upscaled_image["url"]],
"options": {
"openai": {
"imageSize": "1K",
"outputFormat": "jpeg",
"quality": "high",
},
},
}
)
polished_image = first_image(wait_for_job(polished_image_job_id), "UGC polished image")Generate the UGC video
Use the polished image as first_frame so the video starts from the campaign still.
const videoJobId = await triggerVideoGeneration({
modelID: 'seedance-2.0',
prompt:
'short UGC product video, creator lifts the skincare bottle, smiles, and points to the label, handheld phone camera energy',
numVideos: 1,
referenceImages: [
{
url: polishedImage.url,
role: 'first_frame',
},
],
options: {
seedance: {
duration: 6,
ratio: '16:9',
resolution: '1080p',
generateAudio: false,
},
},
})
const videoJob = await waitForJob(videoJobId, 8000)
const video = videoJob.videos?.[0]video_job_id = trigger_video_generation(
{
"modelID": "seedance-2.0",
"prompt": "short UGC product video, creator lifts the skincare bottle, smiles, and points to the label, handheld phone camera energy",
"numVideos": 1,
"referenceImages": [
{
"url": polished_image["url"],
"role": "first_frame",
},
],
"options": {
"seedance": {
"duration": 6,
"ratio": "16:9",
"resolution": "1080p",
"generateAudio": False,
},
},
}
)
video_job = wait_for_job(video_job_id, interval_seconds=8)
video = video_job.get("videos", [])[0]Production notes
- Store the generated
image.idvalues so you can upscale, inspect, or reuse assets later. - Keep the product prompt specific about object placement, hand position, and scene style.
- Use
referenceImageURLsfor known-image-model workflows andreferenceImageswithrole: "first_frame"for image-to-video workflows.