Reels Live Commerce gated
Short-form vertical video, Instagram-style. Mobile-first; web has a viewer but no upload (web app shows a referral gate then "use the mobile app to post").
Commerce mode is gated. Product/store tagging is hidden by default — controlled by
REELS_COMMERCE_ENABLEDenv flag. See Feature Flags.
1. Overview
A consumer scrolls a vertical feed of 60-second videos. Tap to play, double-tap to like, swipe down for comments. Creators (consumers and sellers) upload from mobile only — must have 2 referrals to unlock posting (see Referral Gate). Each reel optionally has up to 5 product tags that link to store products or restaurants (currently disabled at launch). Engagement metrics are deduplicated per fingerprint to prevent inflation.
2. User journey
Viewer
- Open Reels tab (mobile) or
/reels(web) - Vertical scroll between reels (TikTok-style)
- Tap = pause; double-tap = like; tap "💬" = comments
- Tap creator avatar → their Reels Profile (read-only view)
- If commerce enabled: tap a product tag chip → opens product detail (or restaurant menu)
Creator (mobile only)
- Reels tab → "+" button
- Referral gate: must have 2+ verified referrals to unlock. If not, see "Invite friends to unlock" screen.
- Pick video from camera roll (max 100MB, max 60s)
- Edit video: trim with start/end markers
- Edit cover: pick frame, app generates 8 thumbnail candidates
- Details: caption (max 200 chars), tag products (gated by flag), select category
- Post: uploads to GCS via signed URL, creates
Reelrow, optionally createsReelTag[] - Visible in feed immediately
3. Web ↔ Mobile parity
| Capability | Web | Mobile |
|---|---|---|
| View feed | ✅ /reels (vertical scroll) | ✅ Reels tab (TikTok-style) |
| Like | ✅ | ✅ |
| Comment | ✅ | ✅ |
| Share (WhatsApp deep link) | ✅ | ✅ |
| Report a reel | ✅ | ✅ |
| Upload | ❌ "Use mobile app" prompt | ✅ Full edit/cover/trim flow |
| Cover frame picker | — | ✅ 8 candidates from expo-video-thumbnails |
| Video trim | — | ✅ Start/end ms markers |
| Product tag in viewer | 🟡 Gated by REELS_COMMERCE_ENABLED | 🟡 Same gate |
| Tag products in post flow | — | 🟡 "Tag products" entry hidden when flag off |
4. Key components
Web
src/app/(consumer)/reels/page.tsx— feed + viewer (single-component, ~1800 lines)src/app/(consumer)/profile/reels/page.tsx— Reels Profile (own + others via?consumerId=)
Mobile
mobile/app/(tabs)/reels.tsx— feed + viewer + full post flow (~3500 lines, the largest mobile file)mobile/app/reels-profile.tsx— Reels Profile screen
Shared backend
src/app/api/reels/**— list, create, like, comment, view-track, tags, redirect-track
5. APIs
| Endpoint | Method | Purpose |
|---|---|---|
/api/reels | GET | Feed (paginated, supports cursor, limit, search) |
/api/reels | POST | Create reel (after video uploaded to GCS) |
/api/reels/[id] | GET | Single reel detail |
/api/reels/[id] | DELETE | Delete own reel |
/api/reels/[id]/like | GET, POST | Get like status / toggle like (deduplicated by fingerprint) |
/api/reels/[id]/comments | GET, POST | Comments |
/api/reels/[id]/view | POST | Track view (deduplicated, weighted) |
/api/reels/[id]/tags | GET, PUT | Get tags / replace tags. PUT returns 503 when REELS_COMMERCE_ENABLED=false |
/api/reels/[id]/redirect | POST | Track product-redirect attribution (for creator earnings) |
/api/upload-video | POST | Get signed GCS upload URL |
6. Database touchpoints
Reel— main entity.consumerIdORsellerId(creator),videoUrl,thumbnailUrl,caption,category,productId(legacy single-tag),restaurantId(legacy)ReelTag— many-to-many: a reel can tag up to 5 products / menu items. Position field for ordering.ReelLike,ReelComment,ReelView— engagement, all dedupe byfingerprint+consumerIdto prevent inflationReelProductRedirect— every tap on a tagged product is logged here for creator earnings attributionReelEarning— accrued earnings; confirmed when the linked store order moves todelivered, reversed oncancelled
7. Business logic
Referral gate (creator unlock)
- Constant
REFERRAL_THRESHOLD = 2insrc/lib/constants.ts(changed from 3 on 2026-04-04 — see CHANGELOG) - Mobile checks
referralInfo.canUploadbefore showing the post UI - Web shows the same gate before allowing upload (which is unsupported but the messaging is consistent)
Engagement deduplication
fingerprintis computed client-side (src/lib/fingerprint.ts) — combination of UA, screen, fonts, timezone- Same fingerprint can like once, view once (per N seconds)
- Even if the same user is logged out then in, fingerprint persists → no inflation
Creator earnings
- 1% commission on attributed orders (constant
REEL_COMMISSION_RATE) - Attribution window: 24 hours from view-tap (
REEL_ATTRIBUTION_WINDOW_MS) - Min product value: ₹100 (
REEL_MIN_PRODUCT_VALUE_PAISE = 10000) - Max 5 tags per reel (
REEL_MAX_TAGS) - Earnings are PENDING until the order is
delivered, then CONFIRMED. Cancelled orders REVERSE the pending earnings.
Auto-moderation
- Auto-hide a reel after 3 user reports (
REEL_MAX_REPORTS_AUTO_HIDE) - Caption max 200 chars (
REEL_MAX_CAPTION_LENGTH) - Duration max 180s (
REEL_MAX_DURATION_SECONDS)
8. Feature flags / env vars
REELS_COMMERCE_ENABLED— gates product/store tagging UI +/api/reels/[id]/tagsPUT (returns 503 when off). Defaultfalse. See Feature Flags.- Env:
GCS_VIDEO_BUCKETfor video storage (signed URL upload)
9. Tests
tests/build-integrity.test.ts— Reels API surface, schema fieldstests/offline-only-launch.test.ts— REELS_COMMERCE_ENABLED gate (server + viewer + post flow)tests/web-mobile-parity-requests.test.ts— pattern reused for reelsmobile/tests/mobile-code-integrity.test.ts— Reels post flow features (cover picker, trim, etc.)
10. Known gotchas
- Reel tags survive the flag toggle. If commerce gets disabled while reels have tags, the tags stay in DB — we just hide the UI and reject new writes. So flipping the flag back ON makes existing tags visible again.
- Mobile viewer also filters out
menuItemtags (Eats was archived). Code path:tags = allTags.filter(t => !t.menuItem). - Legacy single-product reels: older reels have
Reel.productIdinstead ofReelTag[]. The viewer renders both forms (legacy single-product card OR multi-tag carousel). - GCS direct upload: video upload is from the mobile client directly to GCS (not through our API). Means the API doesn't see the video bytes — only the resulting URL.
11. Related
- Feature Flags · Notifications (push when someone likes your reel)
- CHANGELOG: 2026-04-08 Instagram-style post reel, 2026-04-17 offline-only launch