RevenueCat Shipyard 2026
Technical Documentation
Architecture, tech stack, and RevenueCat implementation
Tech Stack
| Layer | Technology | Purpose |
|---|---|---|
| Mobile Framework | React Native + Expo SDK 54 | Cross-platform iOS/Android |
| Routing | expo-router (file-based) | Navigation and deep linking |
| Backend | Convex | Real-time database, server functions, webhooks |
| Authentication | Clerk | Email, Apple, Google sign-in |
| Subscriptions | RevenueCat | Billing, entitlements, paywall, analytics |
| AI Extraction | Google Gemini 2.0 Flash | Recipe parsing from URLs, YouTube, cookbook photos |
| Voice Assistant | Speechmatics Flow | Real-time voice interaction in Cook Mode |
| Messaging | OneSignal | In-app messaging and push notifications |
| Styling | NativeWind v4 (Tailwind CSS) | Responsive styling with dark mode |
| Distribution | EAS Build + TestFlight | iOS builds with OTA update support |
Architecture Overview
┌──────────────────────────────────────────────────────────┐
│ MOBILE CLIENT │
│ React Native + Expo SDK 54 │
│ │
│ ┌─────────────┐ ┌──────────────┐ ┌────────────────┐ │
│ │ Clerk Auth │ │ RevenueCat │ │ OneSignal SDK │ │
│ │ (identity) │ │ SDK (billing)│ │ (messaging) │ │
│ └──────┬──────┘ └──────┬───────┘ └───────┬────────┘ │
│ │ │ │ │
│ ┌──────┴────────────────┴───────────────────┴────────┐ │
│ │ SubscriptionContext (global state) │ │
│ │ isPremium, tier, purchase(), restore(), refresh() │ │
│ └────────────────────────┬───────────────────────────┘ │
│ │ │
│ ┌────────────────────────┴───────────────────────────┐ │
│ │ PaywallModal (6 triggers) │ │
│ │ Recipe limit · Scan limit · AI chat · Exclusive │ │
│ │ content · Shop discount · Feature gate │ │
│ └────────────────────────────────────────────────────┘ │
└──────────────────────────┬───────────────────────────────┘
│
Convex React Client (real-time sync)
│
┌──────────────────────────┴───────────────────────────────┐
│ CONVEX BACKEND │
│ │
│ ┌──────────────────┐ ┌──────────────────────────────┐ │
│ │ HTTP Router │ │ Server Functions │ │
│ │ │ │ │ │
│ │ /webhooks/ │ │ Queries: │ │
│ │ revenuecat │ │ getSubscriptionStatus() │ │
│ │ clerk │ │ isPremium() │ │
│ │ │ │ checkRecipeLimit() │ │
│ │ HMAC-SHA256 │ │ checkScanLimit() │ │
│ │ verification │ │ getCreatorEarnings() │ │
│ │ │ │ │ │
│ │ │ │ Mutations: │ │
│ │ │ │ syncSubscriptionFromClient()│ │
│ │ │ │ updateSubscription() │ │
│ │ │ │ clearSubscription() │ │
│ └──────────────────┘ └──────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Convex Database │ │
│ │ users · recipes · revenueTransactions │ │
│ │ creatorProfiles · creatorPayouts · recipeEngagement│ │
│ └──────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────┘
│
┌────────────────┼────────────────┐
▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────────┐
│ RevenueCat │ │ Clerk │ │ OneSignal │
│ Cloud │ │ Cloud │ │ Cloud │
│ (billing) │ │ (auth) │ │ (push/IAM) │
└────────────┘ └────────────┘ └────────────────┘RevenueCat Implementation
Products and Entitlements
| Product ID | Price | Type | Entitlement |
|---|---|---|---|
| digero_plus_monthly | $4.99/mo | Auto-renewable | plus |
| digero_plus_annual | $49.99/yr | Auto-renewable | plus |
| digero_creator_monthly | $9.99/mo | Auto-renewable | creator |
| digero_creator_annual | $89.99/yr | Auto-renewable | creator |
Entitlement hierarchy: creator grants all plus features plus creator-specific tools.
Client-Side SDK Integration
Initialization (lib/revenuecat.ts)
- RevenueCat SDK configured on app launch with Clerk user ID as the app_user_id
- Enables cross-platform identity mapping between Clerk, RevenueCat, and Convex
- StoreKit 2 enabled for simulator testing
Subscription Context (contexts/SubscriptionContext.tsx)
- Global React context wrapping the entire app
- Listens to CustomerInfo updates in real-time
- Syncs subscription state to Convex on every change
const { isPremium, purchase, restore, refresh } = useSubscription();Paywall Component (components/subscription/PaywallModal.tsx)
- Single reusable component triggered from 6 strategic locations
- Shows tier comparison, pricing, and contextual messaging
- Handles purchase flow and restore directly
Paywall Trigger Strategy
Rather than a single onboarding paywall, Digero triggers contextual paywalls at moments of peak user motivation:
| Trigger | Location | Context |
|---|---|---|
| RECIPE_LIMIT_EXCEEDED | Recipe save flow | "You've saved 10 recipes. Upgrade for unlimited." |
| SCAN_LIMIT_EXCEEDED | Cookbook scanner | "3 scans used this month. Upgrade for unlimited." |
| AI_CHAT_LIMIT_EXCEEDED | AI Sous Chef (hard lock at 5/5) | Full-screen overlay at daily limit |
| EXCLUSIVE_CONTENT | Creator channel Exclusive tab | Locked recipe cards open paywall on tap |
| SHOP_DISCOUNT | Creator Shop product pages | "Subscribe to save $X.XX on this item" |
| (inline) | AI Sous Chef (soft prompt at 4/5) | Upgrade card injected into chat conversation |
Server-Side Webhook Handler
| Event | Action |
|---|---|
| INITIAL_PURCHASE | Set subscription tier, detect trial, store RevenueCat user ID |
| RENEWAL | Update expiration, clear billing issues |
| CANCELLATION | Mark cancelled, maintain access until expiration |
| EXPIRATION | Revert to free tier |
| BILLING_ISSUE | Flag billing issue, maintain current tier |
| PRODUCT_CHANGE | Update tier on upgrade/downgrade |
After processing each event, the handler syncs the subscription tier to OneSignal as player tags for targeted push notification segmentation.
Data Flow
User taps "Subscribe" in PaywallModal
│
▼
RevenueCat SDK processes purchase via App Store
│
├──► Client: CustomerInfo listener fires
│ └──► SubscriptionContext updates isPremium
│ └──► syncSubscriptionFromClient() writes to Convex users table
│
└──► Server: RevenueCat sends webhook to /webhooks/revenuecat
└──► Convex verifies HMAC signature
└──► updateSubscription() writes to Convex users table
└──► Syncs tier to OneSignal for push targetingBoth paths (client SDK and server webhook) write to the same Convex users table, providing redundancy. The webhook is the source of truth for renewals, cancellations, and expirations that happen outside the app.
Feature Gating
Free Tier Limits
| Feature | Limit | Enforcement |
|---|---|---|
| Saved recipes | 10 | checkRecipeLimit() query before createRecipe mutation |
| Cookbook scans | 3 per 30-day rolling window | checkScanLimit() query + recordScan() mutation |
| AI Sous Chef | 5 messages per day | useAIChatLimit() hook with Convex daily counter |
| Exclusive content | Locked | isPremium check in UI, no API exposure |
| Creator shop discount | 0% | getMemberDiscountRate() returns 0 for free |
Plus Tier
$4.99/mo
All free limits removed. 15% discount on creator shop products.
Creator Tier
$9.99/mo
All Plus features plus: creator dashboard, product shop, payout eligibility, RES multiplier bonuses.
Creator Economy Infrastructure
Recipe Engagement Score (RES)
Every user interaction with a creator's recipe generates engagement points stored in the recipeEngagement table:
| Action | Points | Rationale |
|---|---|---|
| Save | 1x | Low-intent bookmark |
| Rating | 2x | Active feedback |
| Share | 3x | Distribution value |
| "I Made This" cook | 5x | Highest intent — user actually cooked the recipe |
| Exclusive view | 2x | Subscriber-only content engagement |
Creator Tier Multipliers
| Creator Tier | YouTube Subs | RES Multiplier |
|---|---|---|
| Emerging | 10K+ | 1.0x |
| Established | 100K+ | 1.2x |
| Partner | 500K+ | 1.5x |
Payout Calculation
Monthly Subscription Revenue
│
├──► App Store fee (15-30%)
├──► RevenueCat fee (~1.5%)
│
▼
Net Revenue
│
├──► Platform (50%)
└──► Creator Pool (50%)
│
▼
Distributed by RES share:
Creator Payout = (Creator RES × Tier Multiplier)
──────────────────────────────── × Creator Pool
Total Platform RESImplementation: getCreatorEarnings() in convex/creator.ts queries the recipeEngagement table, aggregates RES for the current period, and calculates the creator's estimated payout in real-time. The Creator Dashboard displays this data with a 7-day earnings chart and engagement breakdown.
Revenue Tracking
The revenueTransactions table stores every subscription event from the RevenueCat webhook with a full revenue breakdown:
{
grossRevenue: number, // Full subscription price
appStoreFee: number, // Apple/Google cut
revenuecatFee: number, // RevenueCat platform fee
netRevenue: number, // After all fees
platformShare: number, // Digero's 50%
creatorPoolShare: number, // Creator pool's 50%
}Database Schema
users
| Field | Type | Purpose |
|---|---|---|
| clerkId | string | Identity (indexed) |
| subscriptionStatus | "free" | "plus" | "creator" | "trial" | Current tier |
| subscriptionType | "monthly" | "annual" | "lifetime" | Billing period |
| subscriptionExpiresAt | number | Unix ms expiration |
| hasBillingIssue | boolean | Payment failure flag |
| revenuecatUserId | string | Webhook correlation |
| onesignalPlayerId | string | Push notification targeting |
creatorProfiles
| Field | Type | Purpose |
|---|---|---|
| userId | string | Clerk user ID |
| youtubeChannelId | string | YouTube channel link |
| tier | "emerging" | "established" | "partner" | Partnership level |
| resMultiplier | number | Payout multiplier (1.0-1.5x) |
| applicationStatus | "pending" | "approved" | "rejected" | Onboarding state |
| totalEarnings | number | Denormalized lifetime earnings |
revenueTransactions — Stores every RevenueCat webhook event with gross/net revenue breakdown and creator pool allocation.
creatorPayouts — Monthly payout records per creator with RES share, payout amount, and payment status tracking.
recipeEngagement — Daily aggregated engagement metrics (saves, cooks, shares, ratings) per recipe per creator with calculated RES score.
OneSignal Integration
OneSignal is initialized after Clerk authentication and synced with subscription state for targeted messaging:
Player tags
subscription_status, subscription_type, recipe_count, followed_creators, is_creator
In-app message triggers
recipe_limit_reached, ai_chat_limit_warning, creator_exclusive_available, paywall_viewed
Push segments
Free users approaching limits, lapsed subscribers, creator followers
The RevenueCat webhook handler syncs tier changes to OneSignal after every subscription event, enabling real-time audience segmentation for conversion campaigns.