In-App Purchase Integration: from website to Flutter app
This guide explains how to prepare native in-app purchases for a Wrapply app: store products, product IDs, purchase calls, restore flow and backend receipt validation.
In-app purchase bridge commands
When the in-app purchase module is enabled, the generated app exposes real JavaScript commands inside the WebView. Your website calls these commands, then your backend should verify and unlock the paid feature.
| Command | Use | Payload | Typical response |
|---|---|---|---|
window.Wrapply.iap.getProducts(payload) | Read products configured in Google Play or App Store | { productIds: ['premium_monthly'] } | { ok, available, products, notFoundIds } |
window.Wrapply.iap.purchase(payload) | Start a native purchase flow | { productId, consumable, applicationUserName } | { ok, purchaseStarted, product } |
window.Wrapply.iap.restorePurchases(payload) | Restore non-consumable purchases or subscriptions | { applicationUserName } | { ok, restoreStarted, latestPurchases } |
window.Wrapply.iap.getStatus(payload) | Check if store billing is available and read latest events | {} | { ok, available, latestPurchases } |
Required store setup
Create the products in Google Play Console and App Store Connect using the same product IDs used by the website. Test on real devices and validate receipts server-side before unlocking subscriptions, credits or premium content.
if (window.Wrapply?.__nativeBridgeReady) return callback(window.Wrapply);
window.addEventListener('wrapplyNativeBridgeReady', () => callback(window.Wrapply), { once: true });
}
onWrapplyReady(async (Wrapply) => {
if (!Wrapply.iap) return;
const products = await Wrapply.iap.getProducts({ productIds: ['premium_monthly', 'credits_10'] });
console.log(products);
});
if (!window.Wrapply?.iap) return showWebCheckoutFallback();
const result = await window.Wrapply.iap.purchase({
productId: 'premium_monthly',
consumable: false,
applicationUserName: currentUser.id
});
await fetch('/api/iap/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(result)
});
}
if (!window.Wrapply?.iap) return;
const restored = await window.Wrapply.iap.restorePurchases({
applicationUserName: currentUser.id
});
await fetch('/api/iap/restore', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(restored)
});
}
Integration examples
Use the same bridge pattern in plain JavaScript, React, Vue, Angular, PHP/Laravel, WordPress or jQuery. The important part is to wait for the native bridge before calling it.
JavaScript
if (!window.Wrapply?.iap) return;
const result = await window.Wrapply.iap.purchase({
productId: 'premium_monthly',
consumable: false,
applicationUserName: currentUser.id
});
await fetch('/api/wrapply-event', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(result)
});
}
React hook
export function useWrapplyBridge() {
const [ready, setReady] = useState(false);
useEffect(() => {
if (window.Wrapply?.__nativeBridgeReady) return setReady(true);
const onReady = () => setReady(true);
window.addEventListener('wrapplyNativeBridgeReady', onReady);
return () => window.removeEventListener('wrapplyNativeBridgeReady', onReady);
}, []);
return { ready, Wrapply: ready ? window.Wrapply : null };
}
Vue composable
export function useWrapplyBridge() {
const ready = ref(false);
onMounted(() => {
if (window.Wrapply?.__nativeBridgeReady) ready.value = true;
else window.addEventListener('wrapplyNativeBridgeReady', () => ready.value = true, { once: true });
});
return { ready };
}
Angular service
export class WrapplyBridgeService {
async callNative(payload = {}) {
if (!window.Wrapply?.iap) return { ok: false, error: 'Bridge unavailable' };
return window.Wrapply.iap.getStatus(payload);
}
}
jQuery
if (!window.Wrapply?.iap) return;
const result = await window.Wrapply.iap.getStatus({});
$('#wrapply-output').text(JSON.stringify(result, null, 2));
});
CMS / backend template
<script>
window.addEventListener('wrapplyNativeBridgeReady', function () {
document.body.classList.add('wrapply-native-app');
});
</script>
When native in-app purchase may be required
Store rules are especially important when the app gives access to digital value consumed inside the app. Physical goods, real-world services and some external business flows are different cases, but digital subscriptions and premium features often need native billing.
Premium plans, paid memberships, recurring access or paid account upgrades.
Courses, files, templates, AI credits, unlockable features or downloadable digital assets.
Features consumed inside the app after payment.
If the website checkout is shown inside the app, store review may ask for a native purchase flow instead.
Recommended architecture
The clean approach is to keep the website and backend as the source of truth, then add a native purchase layer in Flutter and synchronize purchase status with your existing user account system.
User signs in
The Flutter app identifies the same user used by your website, usually through Firebase Auth, your existing API token, OAuth or a custom login endpoint.
App loads products
The app requests product identifiers configured in Google Play Console and App Store Connect.
User purchases natively
Flutter starts the native billing flow with Google Play Billing or StoreKit through a Flutter package.
Backend validates receipt
The purchase token or receipt is sent to your backend, where it is verified server-side with Google or Apple.
Backend unlocks entitlement
Your system updates the user subscription, premium flag, credit balance or access level.
Website and app stay in sync
The web app reads the same entitlement state, so access is coherent across mobile app and website.
Flutter source-code implementation
From the Wrapply source code you can add native purchase logic using a package such as in_app_purchase.
The exact implementation depends on your backend, login system, product catalog and subscription model.
Create matching product identifiers in Google Play Console and App Store Connect, then map them in Flutter.
Add a Dart service that loads products, starts checkout, listens for purchase updates and handles restore purchases.
Create an HTTPS endpoint such as
/iap/verify that receives user ID, platform and purchase token.Store the validated entitlement in your database and expose it to both the app and website.
Flutter purchase completed
→ send purchase token to backend
→ backend validates with Google/Apple
→ backend updates user entitlement
→ app reloads premium state
Sync with your existing system
The goal is not to create a second disconnected payment system. The native purchase should update the same account, subscription or access model that your website already uses.
Connect purchases to your existing user ID, not only to a device.
Do not trust only client-side purchase status for premium access.
Use Google and Apple subscription notifications when recurring subscription status changes.
Let users restore purchases after reinstalling the app or changing device.
Your website should read entitlement status from the backend so app and web stay aligned.
If users already paid on the website, define how existing paid accounts map to app access.
What Wrapply can provide
Wrapply generates the app foundation and can provide Flutter source code. In-app purchase integration is a custom source-code and backend task because every business has different products, accounts and access rules.
Start from the generated Flutter project instead of rebuilding the mobile app from zero.
Define which product IDs, backend endpoints and entitlement states are needed.
Add purchase screens, restore flow, validation calls and app-side premium state.
Prepare notes for store review and align the payment flow with app submission requirements.
FAQ
Can I keep Stripe on my website?
For physical goods or real-world services, external payment flows may be acceptable. For digital products consumed in the app, stores may require native in-app purchase. Your exact case must be reviewed before publishing.
Is this included in the standard APK or AAB?
No. Native purchase integration requires source-code work, store product setup and backend synchronization.
Can the mobile app and website share the same subscription?
Yes, if your backend validates native purchases and updates the same user entitlement used by the website.
Ready to plan a compliant app payment flow?
Start with your website URL and source-code package, then evaluate whether native in-app purchase integration is needed for Google Play or App Store approval.