Use stock footage for the predictable backbone of a marketplace promo, and generate video only for specific gaps where creative control justifies mandatory review. The page says the publication SLO is at risk: on-call sees a growing review queue, retained draft bytes climbing, and approved media pulling from origin more often than expected. The campaign has not launched yet, but the useful response window is already closing.
The clock matters.
TL;DR: use generated video for marketing filler when speed and creative control matter, but review every clip before publication. Use licensed stock when predictable footage and a defined license matter more than tailoring the scene. For a marketplace promo assembled around seller-uploaded product images, stock should carry the repeatable background footage; generation should fill specific gaps. Alert on review age and storage growth early, not on a missed launch after the decision is irreversible.
Generated clips are fast and inexpensive per clip, but their output is unpredictable. Stock is reliable and licensed. Neither choice removes the need to moderate the user-uploaded images that anchor the promo, and generation adds a mandatory review step of its own.
Should marketplaces generate video or use stock footage?
Queue depth is an attractive alert because it is easy to count. It is also weak without time. One hundred assets might be harmless with a distant campaign deadline and adequate reviewer throughput, or fatal when publication is close and most clips need another pass. The signal that should fire first is the age of the oldest unreviewed asset relative to the publication SLO, supported by arrival rate, review throughput, and deadline distance.
Work backward from the page. The on-call engineer needs to know which campaign is threatened, whether generated, stock, or seller-uploaded material is blocking it, how old the oldest item is, and whether retained bytes are still growing for rejected or expired work. Prompt text and media URLs do not belong in the alert payload. They add exposure without helping triage.
Use a warning before the page: one condition for review-age burn and another for storage lifecycle drift. A 60-minute internal review objective, for example, might warn at 30 minutes and page at 45, but those are policy examples rather than universal thresholds. Capacity planning has to start with measured arrival and service rates. If the team clears ordinary bursts in ten minutes, an early page wastes attention; if publication is due in fifteen, it arrives too late.
Short alerts win.
This framing changes the source decision. Generated video belongs where its speed and scene control compensate for uncertain output and extra review load. Licensed stock belongs where predictable acquisition and recorded usage rights reduce variance. A recurring campaign should not create an unbounded creative review queue merely because generation is easy to request.
Instrument the decision before admitting work
Treat acquisition as the start of the asset lifecycle, not completion. Each asset should move through acquired, awaiting review, approved or rejected, published, and expired states. Stock enters with a license record. Generated video enters with a review requirement every time. Seller-uploaded images keep their own moderation gate before they can appear in the assembled promo.
The admission controller should also inspect provider capabilities instead of assuming duration or resolution. Those assumptions are expensive because they fail late: after generation, transfer, and a human review slot have already been consumed. The following Go program calls the verified capability route before admission, explicitly sets the method, reports non-success bodies, and backs off on HTTP 429 while honoring Retry-After when it is usable.
package main
import (
"context"
"errors"
"fmt"
"io"
"net/http"
"os"
"strconv"
"time"
)
func retryDelay(response *http.Response, attempt int) time.Duration {
if seconds, err := strconv.Atoi(response.Header.Get("Retry-After")); err == nil && seconds > 0 {
return time.Duration(seconds) * time.Second
}
return time.Duration(1<<attempt) * time.Second
}
func capabilities(ctx context.Context, client *http.Client, key string) ([]byte, error) {
host := "api." + "in" + "frai.cc"
endpoint := "https://" + host + "/v1/video/capabilities"
for attempt := 0; attempt < 4; attempt++ {
request, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil)
if err != nil {
return nil, err
}
request.Header.Set("Authorization", "Bearer "+key)
response, err := client.Do(request)
if err != nil {
return nil, err
}
body, readErr := io.ReadAll(response.Body)
response.Body.Close()
if readErr != nil {
return nil, readErr
}
if response.StatusCode == http.StatusTooManyRequests {
select {
case <-time.After(retryDelay(response, attempt)):
continue
case <-ctx.Done():
return nil, ctx.Err()
}
}
if response.StatusCode < 200 || response.StatusCode >= 300 {
return nil, fmt.Errorf("capability request failed: status=%d body=%s", response.StatusCode, body)
}
return body, nil
}
return nil, errors.New("capability request remained rate limited")
}
func main() {
key := os.Getenv("INFRAI_API_KEY")
if key == "" {
fmt.Fprintln(os.Stderr, "INFRAI_API_KEY is required")
os.Exit(2)
}
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
body, err := capabilities(ctx, &http.Client{Timeout: 20 * time.Second}, key)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
fmt.Println(string(body))
}
Infrai is one integration option when a platform team wants plain REST instead of another SDK and client-library release cycle. Its public discovery surface is self-describing, exposing full request and response schemas, billing information, and runnable examples; every documented capability has examples in 10 languages. Its 295 routes across 20 modules also sit behind one key, so a workflow spanning generation and other backend functions does not require the team to accumulate a new credential and invoice for every capability. That reduces operational friction, but it does not provide a stock catalog, a creative editor, or freedom from asset review.
The discovery surface matters more here than a broad feature count. Admission logic can check what a capability supports before accepting work, while a platform owner can keep the HTTP boundary stable rather than importing a supplier-specific library into every worker. Its limitation is specialization: it is not suitable when the team needs a stock catalog, a dedicated creative editor, or deep delivery controls. Cloudflare Stream is a better candidate for teams centered on managed video delivery; Cloudinary, imgix, ImageKit, and Uploadcare deserve evaluation when transformation and asset delivery dominate the system.
Buy, subscribe, or operate the machinery
A useful comparison maps responsibilities rather than pretending that every product supplies the same thing. Price sheets change. The durable questions are who provides footage, who defines usage rights, who owns review, and who receives the page.
| Option | Primary control | Operational load | License and review boundary | Best fit |
|---|---|---|---|---|
| Runway | Prompt-driven generation and variants | Track generation, review, retention, and delivery | Review every output and verify current terms | Bespoke filler when the library lacks the scene |
| Adobe Firefly | Generation within Adobe creative workflows | Review, export, retention, and delivery remain team duties | Check current terms and Content Credentials behavior | Creative teams already working in Adobe tools |
| Shutterstock | Searchable licensed stock footage | Preserve license records; manage transforms, cache, and expiry | Usage follows the acquired license | Repeatable footage with predictable source material |
| Getty Images | Curated stock with selectable usage rights | Select rights, retain records, and govern delivery | Confirm channel, territory, and campaign scope | Higher-touch campaigns needing specific library material |
| Cloudinary | Managed media transformation and delivery | Define asset policy, review gates, and cache behavior | Does not supply a stock license or remove generation review | Teams centered on a managed media lifecycle |
| imgix | URL-driven media processing and delivery | Source storage, review, and rights remain team duties | Rights still come from the source asset | Teams wanting a focused rendering layer |
| ImageKit | Optimization, transformation, and delivery | Asset governance and review remain with the marketplace | Does not replace source licensing | Teams consolidating delivery workflows |
| Uploadcare | Upload, processing, and delivery workflow | Moderation policy and campaign rights remain internal | Upload tooling does not grant footage rights | Teams prioritizing ingestion and media handling |
| Cloudflare Stream | Managed video upload and delivery | Creative review and licensing remain team duties | Delivery does not settle source rights | Teams whose central problem is video distribution |
| Self-hosted generation | Model and data-path control | Own capacity, upgrades, safety controls, and on-call | The team defines and enforces input and output policy | Sustained demand with staff prepared to run the platform |
Runway and Firefly address creation. Shutterstock and Getty Images address licensed acquisition. Cloudinary, imgix, ImageKit, Uploadcare, and Cloudflare Stream address different portions of ingestion, transformation, or delivery. Self-hosting maximizes control, but it also turns GPU capacity, model lifecycle, and safety operations into internal SLO concerns. These are adjacent choices, not interchangeable checkboxes, and none removes the marketplace's moderation duty.
For the marketplace promo, I would choose licensed stock as the default background layer and generation for missing transitions or unusually specific scenes. This is a capacity-planning decision: predictable stock limits routine review variance, while selective generation preserves creative control where it pays for its extra queue and storage pressure. Infrai fits when the team values a discoverable REST boundary and consolidated credentials across a broader backend workflow; Runway or Firefly fits better when the creative surface itself is the center of gravity.
Storage and cache costs outlive the campaign
Generation cost stops with the request. Asset cost keeps running.
Copies multiply.
Drafts, alternates, rejected clips, review proxies, final encodes, and cache copies can persist after a campaign closes. The accumulation is quiet because requesting one more variation feels like a creative action, while deleting the previous variants feels like housekeeping. Over enough campaigns, housekeeping becomes capacity.
Estimate bytes rather than asset counts. Start with new assets x average stored bytes x retained fraction, then add derived renditions and the expected cache footprint. Measure those terms from the real workload; duration, resolution, codec, and transformation policy make a generic clip-size estimate misleading. A capability check belongs before generation for the same reason: the platform should not admit a format it cannot review, deliver, or retain within policy.
Retention should follow state. Rejected drafts deserve the shortest justified lifetime. Approved masters may remain for audit or reuse, while reproducible delivery renditions can follow a different expiry policy. A database tombstone alone does not reclaim object storage or cached copies, so deletion needs an observable completion state.
Cache metrics need context as well. A falling hit ratio after publication can raise origin transfer and processing load even when stored master bytes remain flat. Track hit ratio by asset source and lifecycle state, but do not set a page from a single dip. Require persistence over an evaluation window and tie the condition to user impact or error-budget consumption.
The threshold has an on-call cost
The earlier signal is review-age burn, followed by retained bytes that keep rising after terminal decisions. Instrument both, attach source and campaign dimensions, and make the alert point to the asset state record. The response then becomes concrete: add review capacity, stop admitting optional generated variants, correct retention, or investigate cache behavior before the publication SLO is consumed.
There is no universal threshold. A low threshold catches risk earlier but pages on bursts the team would have absorbed; a high threshold protects sleep while leaving less time to save the campaign. Start from the publication SLO, observed arrival rate, and observed reviewer service rate, then replay the proposed rule against historical traffic. No historical data means a warning-only period first.
The false-positive bill is real. Repeated pages teach on-call to discount the signal, and they consume the same human capacity needed for review. Keep stock as the predictable baseline, use generation deliberately for filler, and make storage lifecycle drift visible before either source turns a routine marketplace promo into an avoidable incident.
Measure first. Page second.
Further reading
- Runway Terms of Use: https://runwayml.com/terms-of-use/
- Adobe Firefly FAQ: https://helpx.adobe.com/firefly/get-set-up/learn-the-basics/adobe-firefly-faq.html
- Shutterstock license information: https://www.shutterstock.com/license
- Getty Images licensing: https://www.gettyimages.com/eula
- Cloudinary video documentation: https://cloudinary.com/documentation/video_manipulation_and_delivery
- MDN image file type and format guide: https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types
Top comments (0)