ProductReel
Paste a Shopify product URL. Get a 36-second video in under 60 seconds.

- Time to render
- < 60s
- Entry points
- 3
- Pipeline
- 1 orchestrator
- Render template
- Cinematic
Overview
Shopify merchants need vertical video for TikTok, Reels and Shorts. The normal way to get one runs $200 to $2,000 and takes days. ProductReel takes the product URL and ships a 36-second MP4 in under 60 seconds. The merchant pastes one link. That's it.
It's built for the segment Shopify usually doesn't talk about: stores under 1,000 SKUs with no creative team. The goal is the smallest thing that gets that merchant to a first finished render.
“Render state lives in the callback, not the client. The function exits clean in 60s. The MP4 URL lands when Shotstack is actually done.”
Architecture
Steps 01–04 fit inside Vercel's 60-second function cap. Steps 05–06 land later, when Shotstack finishes the render and fires the callback.
Steps 01–04 fit inside Vercel's 60-second function cap. Steps 05–06 land later, when Shotstack finishes the render and fires the callback.
The 60-second function cap splits the pipeline into submit + callback.Key features
- /01
Three entry points, one pipeline
/api/scrape, /api/backfill and /api/webhook all converge on lib/pipeline.ts. Same contract, different triggers.
- /02
Submit-then-callback
Renders submit and return in under 60s. Enhanced images go up through Shotstack Ingest as HTTPS URLs, then Shotstack Edit renders. When it finishes, the callback writes the MP4 URL to KV. The function never polls and never times out.
- /03
AI-ranked hero shot
Gemini returns an image_priority ranking that reorders the product images, so the strongest shot opens the video instead of whatever order Shopify listed them in.
- /04
HMAC-verified webhooks
The pipeline validates each Shopify product.created webhook against SHOPIFY_WEBHOOK_SECRET before doing any work. The /stats dashboard reads Vercel KV sorted-sets, tracking renders per active store as the north-star metric.
- /05
Fail-soft enhancement
Nano Banana image upgrades run best-effort. If the enhancement fails, the pipeline uses the original Shopify image. A blurry render beats no render.
Technical decisions
What I'd do differently
- /01
Build the reconciliation cron up front. If a Shotstack callback never arrives, the job sits in KV forever. A 5-minute cron that re-checks submitted jobs older than 10 minutes would catch the orphans without touching the happy path.
- /02
Pick structured logging before /stats matters. By the time the dashboard needed real error data, the logs were plain text. Migrating mid-flight is way harder than starting structured.

