Skip to main content
AI tutorials

Build and Launch an AI Viral-Video SaaS with ShrimpReel

Learn how to run ShrimpReel locally, customize it for a viral video trend, configure payments and video generation, provision Cloudflare resources, deploy safely, and keep each keyword-specific site synchronized with the upstream template.

Build and Launch an AI Viral-Video SaaS with ShrimpReel

What is ShrimpReel?

ShrimpReel is an open-source SaaS template for building websites that transform one uploaded photo into an AI-generated video based on a viral format. The intended workflow is to create a separate repository for each trending keyword, change the site's configuration and bilingual content, replace the media, and deploy the finished application on Cloudflare.

The stack combines TanStack Start with React 19 and Tailwind CSS 4 for the frontend and server-side rendering. A Hono API handles routes under /api/*, media delivery, robots directives, the sitemap, and IndexNow verification. The server entry point is src/server.ts.

The application is designed around Cloudflare Workers, D1, R2, KV, Queues, Rate Limiting, and Cron Triggers. English pages are served from /, while Chinese pages are available under /zh.

Project status: According to the README, the complete workflow passes local unit and Playwright end-to-end tests, but the template has not yet been verified as a production deployment. Review ROADMAP.md before relying on individual integrations with real services.

Key features

Accounts, billing, and credits

  • Google sign-in, including Google One Tap, plus a localhost-only development login.
  • Credit packs and optional monthly or yearly subscriptions.
  • A credit ledger, redeem codes, referral links, billing history, printable order details, account deletion, and data export.
  • Waffo Pancake as the default payment provider or Dodo Payments as an alternative.
  • Partial and full refunds with automatic credit clawback.

Video generation

  • fal.ai's queue API as the default video provider.
  • Optional routing through yir.ai.
  • A mock provider that copies a template video during local development and tests.
  • A generation queue, dead-letter queue, and automatic credit returns when a generation fails.
  • Public video sharing pages that users can enable per video.

Growth, administration, and operations

  • First-touch and last-touch attribution using UTM values and advertising click identifiers.
  • A visit-to-generation funnel and consent-controlled GA4 events.
  • Admin interfaces for users, orders, generations, payment events, takedowns, reports, emails, audit records, referrals, runtime settings, and connection tests.
  • Provider cost and gross-margin reporting.
  • Maintenance mode, announcements, daily generation limits, health alerts, browser error reporting, and payment notifications.
  • Daily D1 backups to R2.

Safety, retention, and SEO

  • Upload moderation and an AI-generated label on videos.
  • Automatic photo deletion after seven days and video deletion after 30 days.
  • A 48-hour takedown queue that removes videos made from the same source photo and blocks that photo.
  • Turnstile support on contact and report forms.
  • Canonical URLs, hreflang metadata, JSON-LD, a sitemap, legal pages, guides, related articles, and code-split localized copy.
  • A site-wide SEO linter available through npm run seo:check.

Prerequisites

Install Node.js and npm 11.19 or newer. Older npm versions can rewrite package-lock.json in a form that later causes npm ci to fail in continuous integration.

For a production deployment, you will also need a Cloudflare account, a payment-provider account, a video-provider API key, and Google OAuth credentials. FFmpeg is required only when regenerating placeholder media with the bundled script.

Install and run ShrimpReel locally

1. Install dependencies and create local variables

npm install
cp .dev.vars.example .dev.vars

Open .dev.vars and set at least SESSION_SECRET. Production and staging require a strong value of at least 32 characters. The README recommends generating one with:

openssl rand -hex 32

2. Prepare the local database and media storage

npm run seed:local

This command applies the D1 migrations and uploads files from seed/templates/*.mp4 to the locally emulated R2 storage.

3. Start the development server

npm run dev -- --host 127.0.0.1

Open http://127.0.0.1:3000. On Windows, using 127.0.0.1 explicitly also avoids cases where test tools resolve localhost to IPv6.

Do not run the development server on 0.0.0.0 or expose it directly to the internet. Development login, mock payments, and /api/dev/* are intended only for direct localhost requests.

Try the basic workflow

The default local configuration uses PAYMENT_PROVIDER=mock, VIDEO_PROVIDER=mock, and MODERATION_PROVIDER=mock. This lets you exercise the product without charging a card or submitting a job to an external video service.

  1. Open the sign-in page and use the development login shown outside production.
  2. Choose a credit pack. The mock checkout simulates payment without charging anything.
  3. Upload a photo and start a generation.
  4. The mock video provider copies a seeded template video instead of calling an AI model.
  5. Open the dashboard to inspect the generated video, credit ledger, billing records, and sharing settings.

To simulate upload rejection, submit the upload form with mockOutcome=reject. Leave TURNSTILE_SITE_KEY empty if you want Turnstile disabled locally.

You can also test retention cleanup for the current signed-in user's media:

POST /api/dev/sweep
Content-Type: application/json

{"days": 8}

Local email delivery is simulated. Inspect the outbox with:

GET /api/dev/emails?to=user@example.com&ref=<order-or-takedown-id>

Create a site for a new trend

1. Clone the repository while preserving upstream history

git clone https://github.com/qianshuixia/shrimpreel.git moonhop
cd moonhop
git remote rename origin upstream
git remote add origin git@github.com:<owner>/moonhop.git

Do not use GitHub's template button if you want to merge future template updates. A repository created that way does not share history with the source repository. A normal clone with an upstream remote preserves the merge base.

2. Run the site scaffolder

Start with a dry run, inspect the proposed changes, and then add --write:

node scripts/new-site.mjs --keyword "Moon Hop" --domain moonhop.ai --keywords "AI dance video,Moon Hop filter"
node scripts/new-site.mjs --keyword "Moon Hop" --domain moonhop.ai --keywords "AI dance video,Moon Hop filter" --write

The scaffolder updates site.ts, Cloudflare resource names in wrangler.jsonc, and the package name. It resets deployment-specific identifiers and removes the template's staging configuration. It then prints a checklist for the remaining manual work.

3. Configure pricing and generation

Edit src/config/site.ts. Review the credit packs in packages, the subscriptionsEnabled switch, subscription plans, available durations, and video.falModel.

Set subscriptionsEnabled to false if the site should sell only one-time packs. A pack may use anchorPriceCents to display a crossed-out comparison price, but the README warns that it should represent a price at which the pack was genuinely sold. New sites normally leave it unset.

4. Rewrite the localized content

Replace the trend-specific copy in src/content/en.ts and src/content/zh.ts. At minimum, rewrite the hero section, explanation, ideas, FAQ, and both included articles. The optional problem and comparison blocks should also be rewritten or set to null.

Avoid changing only the keyword throughout the existing text. The template explicitly cautions that mechanically duplicated sites may be treated as scaled content abuse by search engines.

To add an article, create its metadata entry in the articles section of site.ts, then add the matching content key to every locale. Articles are automatically included in the guides hub, sitemap, and configured related-article links. Keep the existing trend and howTo entries because the home page links to them.

5. Replace all placeholder media

  • Put source generation clips in seed/templates/ using the pattern <template.id>-<seconds>s.mp4.
  • Replace home-page videos and posters in public/demo/.
  • Replace public/og.png and public/favicon.svg.
  • Use only original or licensed demo media and record its attribution in site.examples.*.credit.

If FFmpeg is available, regenerate the project's original placeholder assets with:

node scripts/generate-placeholder-media.mjs

After changing template.id, remove obsolete template files from seed/templates/.

Configure real providers

Runtime variables

Set the non-secret production variables in wrangler.jsonc. Important values include SITE_URL, APP_ENV=production, PAYMENT_PROVIDER, VIDEO_PROVIDER, MODERATION_PROVIDER, TURNSTILE_SITE_KEY, ADMIN_EMAILS, EMAIL_FROM, product mappings, and GOOGLE_CLIENT_ID.

The payment provider's product prices are authoritative. Prices displayed by the site must be kept in sync with the provider dashboard. Product mappings associate each configured pack or plan with its provider product ID.

Secrets

Depending on the selected integrations, secrets can include SESSION_SECRET, GOOGLE_CLIENT_SECRET, Waffo credentials, Dodo credentials, FAL_KEY, optional YIR_API_KEY, optional OPENAI_API_KEY for moderation, and TURNSTILE_SECRET_KEY.

Set an individual secret with:

npx wrangler secret put <NAME>

Alternatively, copy and complete the production variables file, review the plan, and then apply missing secrets:

cp .dev.vars.example .dev.vars.production
node scripts/sync-secrets.mjs
node scripts/sync-secrets.mjs --apply

The synchronization script does not print secret values. Existing remote secrets are preserved unless --overwrite is supplied.

Provision Cloudflare resources

Create a separate resource set for every keyword site. Names must match the bindings in wrangler.jsonc.

npx wrangler d1 create <name>
npx wrangler r2 bucket create <name>-media
npx wrangler kv namespace create <name>-kv
npx wrangler queues create <name>-jobs
npx wrangler queues create <name>-jobs-dlq
npm run db:migrate:remote
npx wrangler r2 object put <name>-media/templates/<file>.mp4 --file seed/templates/<file>.mp4 --content-type video/mp4 --remote

Copy the generated D1 database ID and KV namespace ID into wrangler.jsonc. Each site's rate-limit namespace_id must also be unique within the Cloudflare account.

Configure the R2 lifecycle rules described by the project so that uploaded photos and generated videos follow the seven-day and 30-day retention periods. The sending domain must also be onboarded with Cloudflare Email Service before transactional email can work.

Verify and deploy

Run the local quality checks

npm run typecheck
npm test
npm run test:e2e
npm run seo:check

Before deploying, run the configuration doctor:

npm run doctor

The doctor checks the environment, domain, selected providers, product mappings, Cloudflare resource bindings, queues, Cron configuration, required secret names, unapplied migrations, and unresolved TODO(site) markers. Use --offline when remote checks are intentionally unavailable.

Deploy and run a smoke test

npm run deploy
SMOKE_BASE_URL=https://<domain> npm run test:smoke

npm run deploy runs the pre-deployment checks first. After deployment, attach the custom domain in Cloudflare and ensure that SITE_URL exactly matches site.domain. Canonical URLs, the sitemap, and same-origin CSRF checks depend on that match.

When the custom domain is working, set workers_dev and preview_urls to false. Otherwise, the production Worker remains accessible through public Cloudflare development and version URLs using the same D1 and R2 resources.

Complete the SEO launch tasks

npm run seo:check -- --base https://<domain> --production
npm run seo:indexnow -- --submit

Run the IndexNow command only after configuring site.seo.indexNowKey. Verify the domain in Google Search Console and Bing Webmaster Tools, then submit https://<domain>/sitemap.xml.

Advanced tips

Keep production free of mocks

Production and staging reject checkout, generation, and uploads with a 503 response if their selected providers remain set to mock. Development login, mock checkout routes, and development API endpoints return 404 in those environments. Treat this as a safety mechanism, not a substitute for running npm run doctor.

Merge template updates instead of copying patches

Keep site-specific work in src/config/site.ts, src/content/*, public/*, seed/, wrangler.jsonc, and the package name. Shared fixes should be made in the template and merged into each site.

git fetch upstream
git show upstream/main:scripts/sync-plan.mjs > .tmp/sync-plan.mjs
node .tmp/sync-plan.mjs
git merge --no-ff upstream/main
npm install
npm run typecheck
npm test
npm run test:e2e
npm run db:migrate:remote

Use merge commits rather than squash merges, rebases, or cherry-picks. The sync plan relies on git merge-base HEAD upstream/main. When recording the merge, end the commit message with Template-sync: <template commit sha>.

Preserve backward compatibility during deployments

If a deployment fails after migrations have run, the new Worker version may be rolled back, but D1 migrations are not automatically reversed. Keep migrations compatible with the previous application version so rollback remains possible.

Use the bundled Claude Code workflows when appropriate

The repository includes a new-hot-site skill for scaffolding a trend-specific site, a sync-upstream skill for merging template changes, and a read-only launch-audit skill for pre-launch and live checks. These tools do not replace manual review: generated copy, licensed media, domains, provider products, OAuth settings, email onboarding, and lifecycle policies still require verification.

Review the project documentation before changing core logic

Consult AGENTS.md before modifying credits, payment fulfillment, bilingual content, migrations, or end-to-end tests. Additional details are available in docs/env.md, docs/payments.md, docs/subscriptions.md, docs/SEO_AUDIT.md, and docs/SAAS_VIDEO_FEATURES.md. The README notes that these documents are currently written in Chinese.

Conclusion

ShrimpReel provides a substantial starting point for a keyword-focused AI video SaaS, including generation queues, billing, credits, administration, retention, compliance workflows, analytics, SEO, and Cloudflare operations. Start with the safe mock workflow, customize every site-specific layer, replace placeholder content with licensed assets, verify all provider and Cloudflare settings, and deploy only after the complete test, doctor, SEO, and smoke-test sequence passes.