The Despia In-App Subscription SDK enables secure in-app subscriptions across iOS, Android, and web platforms. It provides a seamless way to implement subscription-based features in your mobile applications with enhanced security features and native validation through Apple StoreKit and Google Billing Center.
Important: Make sure to publish a new version via TestFlight to test and use In-App Subscriptions successfully using our SDK.
Key Features
-
Server-side webhooks for subscription status updates
-
Native validation through Apple/Google payment systems
-
Real-time transaction verification
-
Automatic receipt validation
-
Support for subscription management
-
Cross-platform compatibility (iOS, Android, Web)
Prerequisites
Before implementing in-app subscriptions:
-
Published Despia mobile application
-
Apple Developer account or Google Play Developer account
-
Configured bank account in respective app stores
-
Completed tax forms and business information
-
Subscription Product IDs set up in App Store Connect/Google Play Console
Basic Implementation
1. Initialize Subscription Purchase
Single Product ID (iOS and Android)
If your subscription product bundle ID is the same for both iOS and Android:
const product_id = "yoursubscriptionid"; // Your Subscription Product ID
const expired_url = "your_expired_url"; // URL to redirect when subscription expires
const baseUrl = 'inapppurchase://?package=' + product_id;
const finalDeeplink = navigator.userAgent === "despia-iphone" ||
navigator.userAgent === "despia-ipad"
? `${baseUrl}&successful_url=""`
: `${baseUrl}&successful_url=""&expired_url=${expired_url}`;
window.despia = finalDeeplink;
Different Product IDs (Platform-Specific)
If you need to use different subscription product IDs for iOS and Android:
// Example for different subscription product IDs on iOS and Android
let product_id = "yourdefaultsubscriptionid"; // Default subscription ID
// Check for iOS devices
if (navigator.userAgent.includes("despia-iphone") || navigator.userAgent.includes("despia-ipad")) {
product_id = "your.ios.subscriptionid"; // Use iOS subscription ID
}
// Check for Android devices
else if (navigator.userAgent.includes("despia-android")) {
product_id = "your.android.subscriptionid"; // Use Android subscription ID
}
const expired_url = "your_expired_url"; // URL to redirect when subscription expires
const baseUrl = 'inapppurchase://?package=' + product_id;
const finalDeeplink = navigator.userAgent === "despia-iphone" ||
navigator.userAgent === "despia-ipad"
? `${baseUrl}&successful_url=""`
: `${baseUrl}&successful_url=""&expired_url=${expired_url}`;
window.despia = finalDeeplink;
2. Variable Tracker Implementation
The VariableTracker is a crucial component that helps your application detect when Despia injects subscription-related variables into your application's window object.
-
Despia injects variables into your application after a subscription is completed
-
These variables contain essential transaction data (planID, transactionID, receipts)
-
VariableTracker reliably monitors when these variables become available
-
More robust than callbacks or global functions as it continues checking until variables are found
-
Works even if variables are injected after your tracking code has already executed
-
Persists within the current session until the variables are detected
class VariableTracker {
constructor(variables, onReady) {
this.variables = variables;
this.onReady = onReady;
this.triggered = false;
this.processing = false;
// Create tracker element
this.tracker = document.createElement('div');
this.tracker.style.display = 'none';
document.body.appendChild(this.tracker);
// Setup observer with debounce
let timeout;
this.observer = new MutationObserver(() => {
clearTimeout(timeout);
timeout = setTimeout(() => this.check(), 100);
});
// Start observing and checking
this.observer.observe(this.tracker, { attributes: true });
this.check();
this.interval = setInterval(() => this.check(), 1000);
}
check() {
if (this.processing || this.triggered) return;
this.processing = true;
try {
const values = {};
const allSet = this.variables.every(name => {
const val = window[name];
// Check for undefined, "n/a" string, or null values
if (val === undefined || val === "n/a" || val === null) return false;
values[name] = val;
return true;
});
if (allSet && !this.triggered) {
this.triggered = true;
this.cleanup();
this.onReady(values);
}
} catch (err) {
console.error("Error during check:", err);
}
this.processing = false;
}
cleanup() {
this.observer.disconnect();
clearInterval(this.interval);
this.tracker.remove();
}
}
3. Track Subscription Variables
Use the VariableTracker to monitor for specific subscription-related variables that Despia will inject into your app:
new VariableTracker(
['planID', 'transactionID', 'subreceipts'],
values => {
// If using JavaScript simply use the object below as needed.
console.log("Subscription Success", {
plan: values.planID,
transaction: values.transactionID,
receipt: values.subreceipts
});
// EXAMPLES FOR SECURE SUBSCRIPTION VALIDATION (for NoCode/LowCode Tools)
// ---------- WEWEB ----------
// WEWEB example using wwWorkflow to handle callback natively
// 1. Create a Native WeWeb Global Worklfow to receive following paramaters:
// A. plan
// B. transaction
// C. receipt
// 2. Add Logic to that Workflow to send those parameters to your backend for secure validation.
// 3. Call your Workflow from exactly this line of code here:
wwLib.wwWorkflow.executeGlobal('YOUR WEWEB WORKFLOW ID', {
plan: values.planID,
transaction: values.transactionID,
receipt: values.subreceipts
});
// ---------- WIZED ----------
// WIZED example using Wized's JS API
v.inappsubscription = {
plan: values.planID,
transaction: values.transactionID,
receipt: values.subreceipts
}
// Create a request (API Call) that will send "v.inappsubscription" to your server for validation.
const result = await Wized.requests.execute('REQUEST NAME TO VALIDATE SUBSCRIPTION');
console.log(result); // Or set result as variable if needed
// ---------- NORDCRAFT / TODDLE ----------
// For Nordcraft / Toddle - simply install the "Despia" Package and listen for the event callback.
// Clone the package from here: https://toddle.dev/projects/despia_package/branches/main
// Or run following after registering an "onCallback" Event in your Custom Action:
ctx.triggerActionEvent("onCallback", {
plan: values.planID,
transaction: values.transactionID,
receipt: values.subreceipts
});
}
);
Note: To restore previous subscriptions when a user reinstalls your app or uses it on a new device, refer to our Restore In-App Subscription documentation.
Subscription Flow
Initial Subscription
-
User triggers subscription through your UI
-
SDK initiates native subscription flow
-
Returns transaction data including receipt and ID
Validation
-
SDK automatically validates subscription with platform (client-side)
-
Returns base64 encoded receipt data + transaction id + bundle
-
Server can verify this data with Apple/Google API
Success Handling
-
Receive transaction ID and receipt
-
Send to your server with user authentication
-
Update user access/permissions
Make sure to validate the subscription data via your server on the backend using Apple's / Google's Official APIs - server side handling of subscription data is critical!
Security Best Practices
Backend Verification (Important)
Always verify subscriptions on your backend server to prevent fraud:
When your frontend receives transaction data from the VariableTracker, send the complete object to your backend
Your backend should then verify the subscription with the platform's API:
For Apple App Store:
-
Use Apple's App Store Server API to verify receipts
-
Call the Get Transaction Info endpoint
-
Refer to Apple's latest documentation for the most current verification process
For Google Play Store:
-
Use Google's Android Publisher API to verify purchases
-
Call the Purchases.products: get endpoint
-
Refer to Google's latest documentation for the most current
Only grant access to subscribed content/features after successful backend verification!
Example Frontend Code:
If you're using a no-code/low-code tool, please refer to the examples above. Below is a sample JavaScript implementation showing both front-end and server-side validation.
new VariableTracker(
['planID', 'transactionID', 'subreceipts'],
values => {
// Send complete subscription data to your backend
fetch('https://your-backend.com/verify-subscription', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_AUTH_TOKEN' // Include user authentication
},
body: JSON.stringify({
planId: values.planID,
transactionId: values.transactionID,
receipt: values.subreceipts,
platform: navigator.userAgent.includes("despia-iphone") ||
navigator.userAgent.includes("despia-ipad") ? "ios" : "android"
})
})
.then(response => response.json())
.then(data => {
if (data.verified === true) {
// Grant access to subscribed content
console.log("Subscription verified on backend");
} else {
// Handle verification failure
console.error("Subscription verification failed");
}
})
.catch(error => {
console.error("Error verifying subscription:", error);
});
}
);
Receipt Validation
-
Always validate receipts server-side
-
Use Apple/Google APIs for verification
-
Store transaction IDs for reference
User Authentication
-
Link subscriptions to authenticated users
-
Include device ID or auth token with validation
-
Prevent unauthorized access sharing
Webhook Handling
-
Implement secure webhook endpoints
-
Verify webhook authenticity
-
Process subscription updates in real-time
Testing Tips
Sandbox Testing
-
Use subscription products with shorter billing periods for testing
-
Create test accounts in App Store/Play Console
-
Verify webhook functionality in test environment
Common Issues
-
Ensure bank account is linked in developer console
-
Verify product IDs match exactly
-
Check user agent detection for platform-specific code
If you need assistance implementing the SDK or have questions, contact our support team at support@despia.com