How to Make AI UGC at Scale: From Concepts to Approved Videos

By Meet Shukla··11 min read
ai ugc at scaleproduction engineeringworkflow reliabilitycontent automationghostfeed

Making one AI UGC video is a generation task.

Making hundreds that are meaningfully different is a production design problem first.

The scalable sequence is:

Step 1: generate concept families

Start from several customer problems, not hundreds of output requests.

For each problem, create different angle families:

  • recognition;
  • objection;
  • product mechanism;
  • comparison;
  • result;
  • boundary or "not for you."

This gives the batch real creative width before a generation model touches it.

Step 2: write scripts in format-specific batches

Write reaction hooks together, talking heads together, demos together, and slideshows together. Each format has a different proof burden.

Keep one record per script with the audience, hook mechanic, product claim, proof asset, format, and CTA. That lets the next stage execute instead of reinterpret.

Step 3: reuse approved creators

Ghostfeed avatars are built as drafts and explicitly approved into the library. That matters at scale: you can establish Stella, Maddie, Gia, Leah, Ethan, or another approved persona once, then reuse the identity across first frames, reactions, and slideshow assets.

Do not treat "500 videos" as "500 new people." A small recognizable roster creates more continuity and far less review work.

Step 4: build first frames before videos

For reaction-style UGC, Ghostfeed separates first-frame generation from animation.

  1. Search the workspace's owned and stock templates.
  2. Search the inspiration library only when the first library has no useful opening pose.
  3. Import an owned reference only when the libraries do not cover the job.
  4. If a 30–120 second import needs a crop, use the dashboard to select a window or let Smart Crop turn scene boundaries into several shorter templates.
  5. Inspect the chosen source's opensOn pose and stored motion analysis.
  6. Generate one frame per approved avatar.
  7. Approve the frames that match the hook.
  8. Regenerate only the failures.

This makes the expensive part downstream of a visible quality decision.

Step 5: animate through the right route

Clone an authorized source motion when its exact performance matters. Use prompt mode when you only need the opening pose and want a fresh action.

The motion model should receive the job it is good at. Screen interaction, product close-ups, exact typography, and changing prices should remain real or deterministic assets.

What the Ghostfeed-enabled agent actually automates

“Use an agent” is meaningless unless the agent can act on the same production state as the team. With Ghostfeed MCP connected, it can:

  • list the target workspace and its approved avatars;
  • search owned templates before the inspiration library;
  • import a reference and poll until it is usable or needs a crop;
  • render up to ten first-frame candidates in one request;
  • stop while a person approves or regenerates frames;
  • send only approved frame IDs to clone or prompt-mode animation;
  • return the finished asset and the same dashboard project the team sees.

It cannot make the rights decision, choose a crop through MCP, or edit and publish the finished video without those separate human actions.

Ask your agent
You: Build a restrained "subscription total" reaction in Client A. Search our library first. Use Maddie, Gia, and Ethan. Frames only. Agent: I found one owned template and one inspiration candidate with the right medium-close opening. The owned template is the safer source. I will render three first frames and stop. You: Approve Gia. Use the source motion exactly; we own that clip. Agent: I will use the explicit clone route for Gia's approved frame and return the generated video plus its Ghostfeed dashboard link.

The details of that two-phase contract are in the Ghostfeed UGC reactions MCP guide.

Step 6: add the product-demo layer

Many AI UGC videos fail here. The creator performs well, but the product proof is decorative or invented.

For apps, use a real screen capture from a demo account. For physical products, use owned footage or an approved product asset. The creator introduces the problem and emotion; the proof shows the mechanism.

Step 7: assemble and review

Review in this order:

  1. hook and first-frame fit;
  2. identity and motion;
  3. product truth;
  4. captions and audio;
  5. CTA;
  6. disclosure and rights.

Reject only the broken layer. A weak caption should not force a new animation.

Step 8: multiply the winner carefully

If one execution works, branch the element you believe caused it:

  • same creator, three hook mechanics;
  • same hook, two proof screens;
  • same proof, two approved creators;
  • same structure, two emotional drivers.

This is how the batch becomes a test matrix instead of 500 cosmetic duplicates.

Step 9: close the loop

Record which hypothesis, script, avatar, template, proof asset, and CTA produced each deployment. Feed the result into the next concept batch.

The model is not the hardest part.

State is.

The system section below is what keeps that nine-step loop reliable once volume grows. It should support the creative operation, not replace it with engineering theatre.

Start with a state machine

Every creative needs one authoritative status.

Ask your agent
draft → brief_pending → brief_approved → source_frame_pending → source_frame_approved → motion_queued → motion_running → qc_pending → qc_failed | final_pending → final_approved → scheduled → published

Terminal states:

Ask your agent
rejected cancelled expired failed_manual_review

Do not infer state from which folder contains the MP4.

Make transitions explicit

Ask your agent
type CreativeStatus = | 'draft' | 'brief_pending' | 'brief_approved' | 'source_frame_pending' | 'source_frame_approved' | 'motion_queued' | 'motion_running' | 'qc_pending' | 'qc_failed' | 'final_pending' | 'final_approved' | 'scheduled' | 'published' | 'rejected' | 'cancelled' | 'expired';

An allowed transition table is boring and useful:

Ask your agent
const AllowedTransitions: Record<CreativeStatus, CreativeStatus[]> = { draft: ['brief_pending', 'cancelled'], brief_pending: ['brief_approved', 'rejected', 'cancelled'], brief_approved: ['source_frame_pending', 'cancelled'], source_frame_pending: ['source_frame_approved', 'rejected', 'cancelled'], source_frame_approved: ['motion_queued', 'cancelled'], motion_queued: ['motion_running', 'cancelled'], motion_running: ['qc_pending', 'cancelled'], qc_pending: ['qc_failed', 'final_pending'], qc_failed: ['motion_queued', 'failed_manual_review', 'cancelled'], final_pending: ['final_approved', 'rejected'], final_approved: ['scheduled', 'cancelled'], scheduled: ['published', 'cancelled', 'expired'], published: [], rejected: [], cancelled: [], expired: [], failed_manual_review: [], };

The exact statuses will differ. The invariant should not: only valid transitions are accepted.

Use idempotency everywhere money moves

Providers timeout.

A timeout does not prove the job failed.

If you retry blindly, you may create two generations and pay twice.

Idempotency key:

Ask your agent
hash( creative_id + shot_id + source_asset_hash + prompt_version + provider + model_version + attempt_policy )

Before creating a provider job:

  1. look up the key;
  2. return the existing job if present;
  3. create a new record transactionally;
  4. submit to the provider;
  5. persist the provider job ID immediately.

“Immediately” matters. Do not keep expensive results only in process memory.

Separate orchestration from workers

Orchestrator:

  • decides which job is allowed next;
  • enforces approvals;
  • checks budgets;
  • writes state;
  • emits work.

Worker:

  • accepts one bounded job;
  • talks to one provider;
  • stores artifacts incrementally;
  • reports success or a typed failure.

Do not let a generation worker decide that a claim is approved.

Build a durable job record

Ask your agent
{ "jobId": "motion-98122", "creativeId": "creative-184", "shotId": "shot-03", "kind": "image_to_video", "status": "running", "attempt": 2, "maxAttempts": 4, "idempotencyKey": "sha256:...", "provider": "seedance", "providerJobId": "provider-481", "inputAssetHashes": ["sha256:..."], "promptVersion": "motion-v17", "estimatedCostUsd": 1.82, "createdAt": "2026-06-07T17:00:00Z", "heartbeatAt": "2026-06-07T17:04:10Z" }

Persist the request and response metadata needed for debugging, without storing secrets in logs.

Retry errors, not disappointment

Retryable:

  • provider rate limit;
  • transient network failure;
  • provider 5xx;
  • job poll timeout while provider job still exists;
  • temporary storage failure.

Not automatically retryable:

  • missing rights;
  • rejected claim;
  • invalid aspect ratio request;
  • contradictory references;
  • budget exceeded;
  • creator expired;
  • final output judged off-brand.

Quality failure may allow a directed new attempt, but that is not the same as replaying a failed HTTP request.

Use exponential backoff with jitter

Ask your agent
delay = min(cap, base × 2^attempt) + random_jitter

Jitter prevents all delayed jobs from hitting the provider again at once.

Keep provider-specific concurrency limits:

Ask your agent
providers: rendererA: maxInFlight: 20 maxRequestsPerMinute: 60 rendererB: maxInFlight: 6 maxRequestsPerMinute: 15

One vendor outage should not exhaust every worker.

Use a dead-letter queue

After the retry policy is exhausted, move the job to an exception queue with:

  • input summary;
  • attempts;
  • failure codes;
  • provider job links;
  • spend;
  • current artifacts;
  • recommended operator action.

Actions:

Ask your agent
retry unchanged retry with modified spec route to another provider repair manually reject creative request missing input

The operator should not reconstruct the history from logs.

Store artifacts by content hash

Ask your agent
sha256(bytes) → asset record

Benefits:

  • deduplication;
  • immutable references;
  • provenance;
  • safe caching;
  • exact attribution;
  • detection of provider callbacks that return the same asset.

Logical names can point to immutable versions:

Ask your agent
maya-kitchen-source-frame → asset sha256:abc...

A new approval creates a new hash.

Put budgets in the scheduler

Ask your agent
budget: campaignDailyUsd: 250 creativeMaxUsd: 18 shotMaxUsd: 6 unapprovedSpecUsd: 0 retryReservePercent: 20

Before enqueueing:

Ask your agent
reserved spend + estimated job cost <= available budget

Reserve on enqueue. Settle on completion. Release on confirmed cancellation.

Otherwise 100 workers can each see the same remaining $20 and spend $2,000.

Apply backpressure

If reviewers can approve 80 assets a day, generating 500 final candidates a day is not scale.

It is inventory.

Monitor:

Ask your agent
queue age review queue depth approval throughput rejection rate time in state cost per approved asset

Pause upstream work when:

  • review queue exceeds its limit;
  • approval SLA is breached;
  • downstream publishing is unavailable;
  • claim or rights review is unresolved.

A staged workflow makes bottlenecks visibleA staged workflow makes bottlenecks visible

Version prompts and briefs

Every output should trace to:

  • evidence version;
  • concept version;
  • creator version;
  • source-frame hash;
  • prompt/template version;
  • model and provider version;
  • evaluator version.

Without that, a performance result cannot teach the system which decision produced it.

Observe the pipeline

Useful dashboard:

SignalWhy it matters
Jobs completed/hourThroughput
P50/P95 job latencyCapacity and incidents
Provider failure rateVendor health
Retry rateHidden cost
Acceptance rateOutput quality
Cost/accepted assetReal unit economics
Oldest review itemHuman bottleneck
Invalid transition attemptsWorkflow bugs
Orphaned provider jobsLost state or spend

Alerts should be actionable.

Bad:

Error count increased.

Useful:

Renderer B quality-failure rate exceeded 35% for talking-head jobs using prompt v18. New jobs paused; 17 remain in flight.

Reconcile provider state

Callbacks get lost.

Run a periodic reconciliation job:

  1. find local jobs in non-terminal states beyond a threshold;
  2. query the provider with the persisted provider job ID;
  3. update local state;
  4. ingest completed artifacts;
  5. flag contradictory or missing provider records.

Never assume webhook delivery is exactly once.

Design cancellation

Cancellation has at least three cases:

Not submitted

Cancel locally and release budget.

Submitted, provider supports cancellation

Request cancellation, then wait for confirmation before settling spend.

Submitted, provider cannot cancel

Mark result as discard-on-arrival. Do not route it forward.

Cancellation is a workflow, not a boolean.

Test failure paths

Before increasing volume, simulate:

  • duplicate webhook;
  • callback before initial response is persisted;
  • provider timeout after accepting job;
  • storage write failure;
  • worker crash after upload;
  • budget exhausted between approval and enqueue;
  • creator rights expiring mid-queue;
  • reviewer rejecting the source frame while a stale job exists;
  • publish integration returning unknown state.

The happy path will demo well.

The failure paths decide whether the system survives Tuesday.

A capacity example

Assume:

Ask your agent
120 motion jobs/day 70% first-pass acceptance 20% accepted on one directed retry 10% rejected/manual

Expected attempt load:

Ask your agent
120 first attempts + 36 directed retries = 156 generation attempts/day

If the provider completes six concurrent jobs with P95 latency of ten minutes:

Ask your agent
theoretical capacity = 6 × 6 jobs/hour × 24 = 864 attempts/day

But do not plan at theoretical capacity.

Rate limits, daily traffic shape, review availability, provider incidents, and storage all reduce it.

The human queue is part of the architecture

Surface:

  • highest-cost exceptions first;
  • rights and claims blockers distinctly;
  • side-by-side source and output;
  • exact failed checks;
  • one-click safe actions;
  • full provenance.

No filming, no editing, no prompting should not mean no control.

Ghostfeed turns creative production into a visible system: approved source frames, queued generations, reusable creators, and many deployable variants.

At scale, output is easy to count.

Reliability is the product.