# Monetization

> Set up in-app purchases, subscriptions, and payment processing for Flutter apps using RevenueCat or Lemon Squeezy. Use this skill when the user asks about monetization, subscriptions, in-app purchases, paywalls, entitlements, offerings, RevenueCat setup, Lemon Squeezy integration, pricing models, or payment processing for mobile apps. Also triggers on: 'add subscriptions', 'paywall', 'premium features', 'free trial', 'freemium model', or 'how to charge users'.

- Skill: `dojocodinglabs/monetization` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add dojocodinglabs/monetization`
- Raw SKILL.md: https://api.skillmd.com/api/skills/dojocodinglabs/monetization/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: dojocodinglabs (https://skillmd.com/u/dojocodinglabs)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/dojocodinglabs/monetization

---


# Monetization: Subscriptions & In-App Purchases

This skill covers payment integration for Flutter apps, from choosing a provider to implementing paywalls and managing entitlements.

## Provider Decision

| Feature | RevenueCat | Lemon Squeezy |
|---------|-----------|---------------|
| **Best for** | Mobile-first subscriptions | Web + mobile hybrid products |
| **Platforms** | iOS, Android, Amazon, Web | Web-first, mobile via webhooks |
| **Flutter SDK** | Official (`purchases_flutter`) | No Flutter SDK (REST API + webhooks) |
| **Paywall UI** | Built-in (`purchases_ui_flutter`) | Build your own |
| **Store compliance** | Handles StoreKit + Play Billing | You handle store integration |
| **Pricing** | Free tier (up to $2.5k MTR), then 1-2.5% | 5% + 50c per transaction |
| **Merchant of record** | No (you handle taxes) | Yes (they handle taxes globally) |
| **Ideal use case** | App Store/Play Store subscriptions | Digital products, SaaS, one-time purchases |

**Quick decision:**
- Selling subscriptions through App Store / Play Store → **RevenueCat**
- Selling digital products, licenses, or SaaS outside stores → **Lemon Squeezy**
- Both → RevenueCat for mobile + Lemon Squeezy for web/backend

## RevenueCat Setup

Read `references/revenuecat.md` for complete implementation guide.

### Architecture Overview

```
Flutter App
  └─ purchases_flutter SDK
      └─ RevenueCat Backend
          ├─ Apple StoreKit (iOS subscriptions)
          ├─ Google Play Billing (Android subscriptions)
          └─ Amazon Appstore (optional)
```

RevenueCat acts as a **single source of truth** for subscription state across platforms. It handles:
- Receipt validation
- Subscription status tracking
- Cross-platform purchase syncing
- Webhook delivery to your backend
- Analytics and churn metrics

### Quick Start

1. Create RevenueCat account at [app.revenuecat.com](https://app.revenuecat.com)
2. Create project, add app (iOS + Android)
3. Configure store credentials:
   - iOS: App Store Connect Shared Secret + In-App Purchase Key
   - Android: Google Play service account JSON
4. Create Products in each store (App Store Connect + Google Play Console)
5. Create Entitlements in RevenueCat (e.g., "premium")
6. Create Offerings with Packages (monthly, annual, lifetime)
7. Integrate SDK in Flutter app

### Essential Code

**Initialize SDK** (call once at app start):
```dart
import 'package:purchases_flutter/purchases_flutter.dart';

Future<void> initRevenueCat() async {
  await Purchases.setLogLevel(LogLevel.debug); // Remove in production
  final config = PurchasesConfiguration('your_revenuecat_api_key')
    ..appUserID = null; // Anonymous until user logs in
  await Purchases.configure(config);
}
```

**Check subscription status:**
```dart
Future<bool> isPremium() async {
  final customerInfo = await Purchases.getCustomerInfo();
  return customerInfo.entitlements.active.containsKey('premium');
}
```

**Show paywall (using RevenueCat UI):**
```dart
import 'package:purchases_ui_flutter/purchases_ui_flutter.dart';

Future<void> showPaywall() async {
  final result = await RevenueCatUI.presentPaywall(
    displayCloseButton: true,
  );
  if (result == PaywallResult.purchased) {
    // Grant access
  }
}
```

**Purchase a package:**
```dart
Future<void> purchase(Package package) async {
  try {
    final result = await Purchases.purchase(
      PurchaseParams.package(package),
    );
    if (result.customerInfo.entitlements.active.containsKey('premium')) {
      // Success
    }
  } on PlatformException catch (e) {
    final code = PurchasesErrorHelper.getErrorCode(e);
    if (code == PurchasesErrorCode.purchaseCancelledError) {
      // User cancelled, don't show error
    }
  }
}
```

## Lemon Squeezy Integration

Read `references/lemonsqueezy.md` for API details.

### Architecture Overview

```
Flutter App
  └─ WebView or deep link to checkout
      └─ Lemon Squeezy (handles payment + taxes)
          └─ Webhook to your backend
              └─ Backend updates user entitlements
                  └─ Flutter app checks entitlements
```

Lemon Squeezy is a **merchant of record** — they handle global tax compliance, invoicing, and payment processing. You receive payouts minus their fee.

### When to Use Lemon Squeezy Over RevenueCat

- Selling access to APIs, web dashboards, or digital content
- Need global tax compliance without handling it yourself
- Want a checkout experience outside of App Store/Play Store
- Selling one-time purchases (not just subscriptions)
- Apple/Google's 30% commission is too high for your margins

### Integration Pattern

Since there's no Flutter SDK, integrate via:

1. **Checkout URL** — open in WebView or external browser
2. **Webhooks** — receive payment events on your backend
3. **License validation** — verify purchase in your app via API

```dart
// Open Lemon Squeezy checkout
import 'package:url_launcher/url_launcher.dart';

Future<void> openCheckout(String productId) async {
  final url = 'https://your-store.lemonsqueezy.com/checkout/buy/$productId'
      '?checkout[custom][user_id]=user_123';
  await launchUrl(Uri.parse(url), mode: LaunchMode.externalApplication);
}
```

## Pricing Strategy

### Common Mobile Pricing Models

| Model | Example | Revenue pattern |
|-------|---------|----------------|
| Freemium | Free core + premium features | Recurring (subscriptions) |
| Free trial | 7-day trial → paid | High conversion if value is clear |
| One-time purchase | Unlock all features | Spiky, no recurring |
| Consumable | Credits, tokens | Variable, engagement-dependent |
| Tiered | Basic / Pro / Enterprise | Segmented by usage |

### Pricing Best Practices for Stores

- **Offer annual plans** — higher LTV, lower churn. Typical discount: 15-30% vs monthly
- **Free trial > freemium** for subscription apps (Apple and Google both support trial periods natively)
- **Price anchoring** — show annual price first, monthly price looks expensive by comparison
- **Localized pricing** — adjust prices by market purchasing power
- **Introductory offers** — Apple and Google support discounted first periods

### Store Commission

| Store | Commission | Reduced rate |
|-------|-----------|-------------|
| Apple App Store | 30% | 15% (< $1M/year revenue via Small Business Program) |
| Google Play Store | 30% | 15% (first $1M/year) |
| Amazon Appstore | 30% | 20% (some categories) |

## Entitlement Architecture

Design entitlements to be **platform-agnostic** and **forward-compatible**:

```dart
// Good: abstract entitlement
enum AppEntitlement { premium, proPlan, teamPlan }

// Bad: tied to specific product
enum AppEntitlement { monthlySubscription, annualSubscription }
```

A user with "premium" entitlement might have:
- Monthly subscription via Google Play
- Annual subscription via App Store
- Lifetime purchase via promotion
- Free access via team plan

RevenueCat maps all of these to the same entitlement. Your app only checks `entitlements.active.containsKey('premium')`.

