If you run growth at a consumer app, someone has probably sent you two UGC quotes this month. One charges a flat fee per video. The other charges per verified view, up to a ceiling. They are hard to compare on a spreadsheet because one is priced on effort and the other on results.
So let's compare them the way engineers compare anything: write a small simulation, feed it the same assumptions, and look at the distribution instead of the average.
Everything below runs in Node 18+ with no dependencies.
The one fact the simulation has to respect
Short-form views are lopsided. Most posts do modest numbers and a few posts do most of the work. A model that assigns every video the "average" view count will lie to you. We'll use a log-normal distribution, which produces exactly that long tail.
// Box-Muller: turn two uniform randoms into one standard normal function randNormal() { const u = 1 - Math.random(); const v = Math.random(); return Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * v); } // Log-normal views: median sets the typical post, sigma sets how wild the tail is function viewsForPost(median, sigma = 1.6) { return Math.round(median * Math.exp(sigma * randNormal())); } The median and sigma are inputs you choose. Pull them from your own past posts if you have them. The numbers in this article are illustrative.
Model 1: flat fee per video
You pay per video, before anyone knows how it performs.
function flatFee({ videos, feePerVideo, median }) { let views = 0; for (let i = 0; i < videos; i++) views += viewsForPost(median); const spend = videos * feePerVideo; return { spend, views, cpm: (spend / views) * 1000 }; } Model 2: pay per verified view, with a ceiling
Here the bill follows delivery. You set a budget cap and a CPM ceiling (the most you pay per 1,000 views). Spend can never pass the cap, and views beyond what the cap buys are still delivered by the posts, you just are not charged more than the cap.
function perView({ posts, ceilingCpm, budgetCap, median }) { let views = 0; for (let i = 0; i < posts; i++) views += viewsForPost(median); const spend = Math.min(budgetCap, (views / 1000) * ceilingCpm); return { spend, views, cpm: (spend / views) * 1000 }; } Notice what changed. In model 1 the number of videos drives cost. In model 2 the number of posts drives reach, and the ceiling drives cost. That is why per-view campaigns spread a budget across many creators and pages instead of a handful of videos.
Run both a thousand times
function simulate(fn, args, runs = 1000) { const out = Array.from({ length: runs }, () => fn(args)); const pct = (key, p) => { const sorted = out.map(r => r[key]).sort((a, b) => a - b); return sorted[Math.floor(p * (runs - 1))]; }; return { viewsP10: pct("views", 0.1), viewsP50: pct("views", 0.5), cpmP50: +pct("cpm", 0.5).toFixed(3), cpmP90: +pct("cpm", 0.9).toFixed(3), maxSpend: Math.max(...out.map(r => r.spend)), }; } // Illustrative flat-fee quote: 10 videos at $300 each console.log("flat", simulate(flatFee, { videos: 10, feePerVideo: 300, median: 20_000 })); // Illustrative per-view campaign: 200 posts, $1 ceiling, $3,000 cap console.log("perView", simulate(perView, { posts: 200, ceilingCpm: 1.0, budgetCap: 3000, median: 8_000 })); Read the output by column, not by row:
- viewsP10 is your bad week. With ten videos, a bad week is very bad, because a single post carries the result.
- cpmP90 is the expensive tail. Flat fees have a long one. Per-view pricing has a hard wall at the ceiling, so
cpmP90can never exceedceilingCpm. - maxSpend for the per-view model never passes the cap. That is the worst case, and you can write it into a contract.
Plug in real ranges
A few real numbers from our own campaigns at FindClout, so your inputs are not pure guesses:
- Logo and watermark runs on clips: ceilings of $0.20 to $0.30 per 1,000 views, and the real CPM has landed as low as $0.08.
- Meme carousels with a brand card on slide two: around a $1 ceiling.
- Full UGC made by real creators, paid per verified view, is quoted per campaign.
- Delivery: clients average 130% of the views they bought.
Add delivery to the per-view model to see what over-delivery does to your effective CPM:
function effectiveCpm(spend, viewsBought, deliveryRatio = 1.3) { return (spend / (viewsBought * deliveryRatio)) * 1000; } console.log(effectiveCpm(2000, 10_000_000).toFixed(3)); // 0.154 $2,000 for 10 million views is a $0.20 CPM. At 130% delivery, 13 million views arrive, and the same $2,000 works out to about $0.154.
What the simulation cannot check
Code can model price. It cannot tell you whether the views were human. Three things to ask any vendor before the numbers mean anything:
- Is billing tied to verified views? At FindClout, views are verified and bot-filtered before any payout, and brands pay only for the verified ones.
- Do the posts have real engagement? A post with 100,000 views and 10 likes is a red flag. Ask for links, not screenshots.
- Whose audience is it? Ask for the platform's own report. Ours, from Meta's Insights on connected pages: 60% aged 18 to 34, 90% of reported gender male, 84% US.
If you'd rather not write code, the clipping cost calculator does the ceiling math in a browser.
Try it on your next quote
Copy the functions, set median from your last 20 posts, and run both models against the quotes on your desk. If the per-view version wins and you want a real plan for your launch (formats, a ceiling, a budget cap, a start date), book a call with our team. We run performance UGC and clipping campaigns across Instagram, TikTok, YouTube Shorts, X and Facebook Reels.
If you're a creator reading this: brands on FindClout pay per verified view, and you can join free at app.findclout.com.




