A minimal and production-ready React Native Expo boilerplate for integrating Dodo Payments. This boilerplate helps you quickly set up a clean payment flow with in-app browser support and deep links.
- Complete Payment Flow - Ready-to-use checkout UI with payment result handling
- In-App Browser Integration - Payment checkout via
expo-web-browser - Deep Linking - Automatic callback routing for payment results (
yourapp://payment/result) - Reusable Components - Modular payment UI components (ProductCard, FeatureList, StatusIcon)
- Demo Backend Server - Express.js example server for checkout session creation
- TypeScript Support - Fully typed with minimal, focused types
- Dark Mode - Theme support for light and dark modes
- Haptic Feedback - Native vibration feedback for better UX
- Easy Customization - Centralized config for products, pricing, and features
Before you begin:
- Node.js v18+
- Expo CLI (
npm install -g expo-cli) - Dodo Payments Account - Sign up
# Clone and install
git clone https://github.com/dodopayments/expo-boilerplate.git
cd expo-boilerplate
npm install
# Install server dependencies
cd server
npm install
cd ..App Environment:
# Copy example config
cp .env.example .envEdit .env:
# Your backend URL (e.g., http://localhost:3000 for local development)
EXPO_PUBLIC_BACKEND_URL=http://localhost:3000Server Environment:
# In the server directory
cp .env.example .envEdit server/.env:
# Dodo Payments API Key
DODOPAYMENTS_API_KEY=your_api_key_here
# Environment (defaults to test_mode)
DODOPAYMENTS_ENVIRONMENT=test_mode
# Return URL
# Must match your app's scheme in app.json
DODOPAYMENTS_RETURN_URL=yourapp://payment/result
# Server Port (defaults to 3000)
PORT=3000The demo server has hardcoded values for simplicity. In production, you'll replace this with your own backend that includes authentication, database integration, and proper customer/product management.
Edit app.json to match your app (update all "dodoexpo" references with your app's scheme and identifiers):
{
"expo": {
"name": "Your App Name",
"slug": "your-app-slug",
"scheme": "yourapp",
"ios": {
"bundleIdentifier": "com.yourcompany.app"
},
"android": {
"package": "com.yourcompany.app"
}
}
}Important: The scheme is used for deep linking back to your app after payment. It must match the DODOPAYMENTS_RETURN_URL in your server .env file.
Edit config/product.ts to update your premium plan:
export const HEADER_CONFIG = {
title: 'Your Plan Name',
subtitle: 'Your subtitle',
};
export const PRODUCT_CONFIG = {
price: '$19.99',
period: '/month',
badge: 'MOST POPULAR',
description: 'Your description',
features: [
'Feature 1',
'Feature 2',
'Feature 3',
],
buttonText: 'Subscribe Now',
disclaimer: 'Cancel anytime. No hidden fees.',
};Terminal 1 - Start Backend:
cd server
npm run devTerminal 2 - Start Expo:
npm start # Start dev server
npm run ios # iOS simulator
npm run android # Android emulatorYour backend needs one endpoint to create checkout sessions:
The included server/server.js provides a simple working example.
Note: This is a minimal demo server. In production, you should:
- Add authentication to verify users
- Get customer info from your database
- Store product IDs in environment variables
- Add proper error handling
- Implement webhooks for payment verification
Response Format:
{
"checkout_url": "https://checkout.dodopayments.com/session/xxx",
"session_id": "session_xxx"
}For more examples, see Dodo Payments Checkout Session Docs.
app/
├── (tabs)/
│ ├── index.tsx # Premium plan card + checkout button
│ └── profile.tsx # Profile placeholder
├── payment/
│ └── result.tsx # Payment result screen
└── _layout.tsx # Root layout with deep linking
components/
├── payments/ # Payment-specific components
│ ├── ProductCard.tsx # Complete product card
│ ├── FeatureList.tsx # Feature list with checkmarks
│ ├── PricingDisplay.tsx # Price and period display
│ ├── StatusIcon.tsx # Payment status icon
│ ├── PaymentButton.tsx # Reusable payment button
│ └── LoadingOverlay.tsx # Loading overlay
├── themed-text.tsx # Theme-aware text component
└── themed-view.tsx # Theme-aware view component
config/
├── env.ts # Environment configuration
└── product.ts # Product details configuration
services/
└── dodo-payments.ts # Payment service
types/
└── dodo-payments.ts # TypeScript types
server/
├── server.js # Demo Express server
├── package.json # Server dependencies
└── .env.example # Server environment template
The app handles payment results via deep links:
yourapp://payment/result?status=succeeded
yourapp://payment/result?status=active
yourapp://payment/result?status=failed&message=Card%20declined
Edit config/product.ts to customize all product details in one place:
export const PRODUCT_CONFIG = {
price: '$29.99', // Change price
period: '/year', // Change period
badge: 'BEST VALUE', // Change badge
description: 'Your text', // Change description
features: [ // Add/remove features
'Feature 1',
'Feature 2',
],
buttonText: 'Get Started', // Change button text
disclaimer: 'Your disclaimer', // Change disclaimer
};All changes automatically update the UI!
Want to offer multiple pricing tiers? You can easily create multiple product cards:
// In config/product.ts
export const PLANS = {
basic: { price: '$5.00', ... },
premium: { price: '$10.00', ... },
pro: { price: '$20.00', ... },
};
// In app/(tabs)/index.tsx
{Object.values(PLANS).map(plan => (
<ProductCard key={plan.price} {...plan} onCheckout={handleCheckout} />
))}Edit constants/theme.ts to update app-wide colors:
export const Colors = {
light: {
text: '#11181C',
background: '#fff',
tint: '#0a7ea4',
},
dark: {
text: '#ECEDEE',
background: '#151718',
tint: '#fff',
},
};Use these test cards from Dodo Payments:
- Success:
4242 4242 4242 4242 - Decline:
4000 0000 0000 0002
- Start the backend server:
cd server && npm run dev - Start Expo:
npm start - Tap "Subscribe Now" in the app
- Complete checkout with test card
- Get redirected back with result
| Issue | Solution |
|---|---|
| Backend not connecting | Check EXPO_PUBLIC_BACKEND_URL in .env. Ensure server is running on correct port. |
| Deep links not working | Verify scheme in app.json matches your return URL. Rebuild app: expo run:ios or expo run:android |
| Payment browser won't open | Check server logs for errors. Ensure API key is set in server .env |
| Env variables not loading | Restart Expo with cache clear: npm start -- -c |
| Server errors | Check server .env has DODOPAYMENTS_API_KEY set |
# Install EAS CLI
npm install -g eas-cli
# Login to Expo
eas login
# Configure EAS (first time only)
eas build:configure
# Build for iOS
eas build --platform ios
# Build for Android
eas build --platform android- Update
.envwith production backend URL - Replace the demo server with your own backend that includes:
- Authentication and user management
- Database integration for customer data
- Product management
- Webhook handling
- Proper error handling and logging
Deploy your backend to:
- Railway
- Heroku
- AWS/GCP/Azure
Make sure to set all environment variables in your hosting platform.
- Customize
config/product.tswith your product details - Set up your backend with proper authentication
- Get Dodo Payments API keys from dashboard
- Test thoroughly with test mode
- Add subscription management to profile screen
- Implement webhooks for server-side payment verification
- Deploy using
eas build
- Never store API keys in the mobile app
- Always create checkout sessions server-side
- Always verify payments server-side using webhooks
- Always authenticate users before creating checkout sessions
- Use environment variables for all sensitive data