Unity Integration
Learn how to integrate Stash Pay into your Unity project for iOS and Android platforms. Follow this guide to install the Unity SDK, configure deep links, and display the Stash checkout in your game.
Use the Stash Pay Unity integration to add checkout to your iOS and Android projects. This guide shows you how to install the Unity SDK, configure deep links, and display the Stash checkout in your game.
Before you begin
This guide applies to both iOS and Android Unity projects. The integration process is identical for both platforms, and the Unity SDK handles platform-specific tasks automatically.
Before integrating Stash Pay into your Unity project, ensure you are familiar with how the Stash Pay system works, including the end-to-end checkout flow. You should already know how to generate checkout links and handle purchase verification securely on your game server before proceeding with Unity integration.
We recommend reviewing the following articles first:
- High-level flow: Overview of the checkout flow and steps to obtain your API key.
- Integrating Stash Pay: How to generate a checkout link and handle webhook events for integration.
Your game server must integrate with the Stash Pay API to request a checkout URL or ID on behalf of the player.
Unity SDK Requirements
- Unity 2022.3 and above recommended.
- iOS 12+ / Android 11+
Set up
Install the Stash Unity SDK before implementing the checkout flow.
Download the Unity SDK
Go to the Stash Unity SDK repository and download or clone the Stash.Popup folder.
Import into Unity
Copy the Stash.Popup folder into your Unity project's Assets directory.
Verify installation
Verify that the Stash.Popup namespace is available in your scripts.
A reference implementation is included in a sample scene within the Stash.Popup package.
Configure deeplinks
Configuring deeplinks is highly recommended for a seamless payment experience even though it is not strictly required for in-app checkout with Stash Pay. Deeplink support enables Stash Pay to redirect players back into your game after a browser-based checkout or when certain payment methods open external pages by necessity.
To set up deeplinking:
- Follow the Unity Deep Linking guide to configure your preferred deeplink schema in your Unity project.
- Register and set up the same deeplink schema in Stash Studio so that Stash Pay can redirect players to your game when necessary.
This approach ensures that whenever Stash needs to return a user from an external checkout flow, they are brought directly back into your app with the correct context.
Using In-app Checkout
Stash Pay native purchase dialog inside Unity game.
Call StashPayCard.Instance.OpenCheckout() to present the Stash Pay checkout using a native card dialog. The Stash SDK automatically
detects the platform (iOS or Android) and device type (phone or tablet), choosing the best experience and layout
for the user.
using StashPopup;
public class MyStore : MonoBehaviour
{
void PurchaseItem(string checkoutUrl)
{
// checkoutUrl is a Stash Pay URL generated on your game backend.
StashPayCard.Instance.OpenCheckout(
checkoutUrl,
dismissCallback: OnCheckoutDismissed,
successCallback: OnPaymentSuccess,
failureCallback: OnPaymentFailure
);
}
void OnCheckoutDismissed()
{
// User closed the dialog, do nothing or handle accordingly.
}
void OnPaymentSuccess()
{
// Payment was completed
// Trigger purchase validation on the server.
VerifyAndGrantPurchase();
}
void OnPaymentFailure()
{
// Payment failed - show error to user
ShowErrorMessage("Payment could not be processed");
}
}Always verify purchases on your backend. Never trust client-side callbacks alone.
Using Browser Mode
Stash Popup also supports launching the checkout in the system browser using SFSafariViewController on iOS or Chrome Custom Tabs on Android, instead of showing it within the in-game popup. You can enable this behavior directly in your code, or dynamically manage it for specific user segments via settings in Stash Studio.
When using browser mode, the successCallback and failureCallback are not available. Purchases are completed externally and users return to your game via a deep link after finishing the transaction.
void OpenInBrowser(string url)
{
// Enable browser mode
StashPayCard.Instance.ForceWebBasedCheckout = true;
// Opens in Safari/Chrome instead of card
// successCallback and failureCallback are not available for the browser mode.
StashPayCard.Instance.OpenCheckout(url, OnDismiss);
// Restore default mode
StashPayCard.Instance.ForceWebBasedCheckout = false;
}Unity Editor Testing
The plugin includes a Unity editor extension that allows you to test Stash Pay checkout directly in the Unity Editor without building to a device.
When you call OpenCheckout() in your scene, the extension automatically intercepts these calls and displays the flow in a window within Unity editor. This enables you to interact with the Stash Pay UI, complete purchases, and verify callback events directly in the editor.
Currently Windows and macOS versions of Unity are supported starting from Unity 2022.3.

Callback Behavior and Edge Cases
When Callbacks Fire
Understanding when callbacks are available and when they fire is crucial for proper integration:
| Mode | Success Callback | Failure Callback | Dismiss Callback |
|---|---|---|---|
| Stash Pay Dialog | ✅ Fires on successful payment | ✅ Fires on payment failure | ✅ Fires when user closes dialog |
| Browser Mode | ❌ Not available | ❌ Not available | ✅ Fires when browser closes |
Important: Browser mode (SFSafariViewController/Chrome Custom Tabs) does not support success or failure callbacks. Always verify purchases server-side using webhooks when using browser mode.
Handling Callback Failures
If your success callback doesn't fire, implement fallback verification:
public class PurchaseManager : MonoBehaviour
{
private string currentOrderId;
void PurchaseItem(string checkoutUrl)
{
// Store order ID for verification
currentOrderId = ExtractOrderId(checkoutUrl);
StashPayCard.Instance.OpenCheckout(
checkoutUrl,
dismissCallback: OnCheckoutDismissed,
successCallback: OnPaymentSuccess,
failureCallback: OnPaymentFailure
);
// Start a coroutine to verify purchase after timeout
StartCoroutine(VerifyPurchaseAfterDelay(5.0f));
}
void OnPaymentSuccess()
{
// Callback fired - verify on server
VerifyPurchaseOnServer(currentOrderId);
}
IEnumerator VerifyPurchaseAfterDelay(float delay)
{
yield return new WaitForSeconds(delay);
// If callback hasn't fired, verify anyway
// This handles cases where callback fails but purchase succeeded
VerifyPurchaseOnServer(currentOrderId);
}
void VerifyPurchaseOnServer(string orderId)
{
// Query your server to verify purchase
// Server should check webhooks or query Stash API
StartCoroutine(CheckPurchaseStatus(orderId));
}
}App Backgrounding During Checkout
If the app is backgrounded during checkout (user switches apps, receives a call, etc.), handle the return gracefully:
void OnApplicationPause(bool pauseStatus)
{
if (pauseStatus)
{
// App is being backgrounded
// Save checkout state if needed
SaveCheckoutState();
}
else
{
// App resumed - check for completed purchases
// This handles cases where purchase completed while app was backgrounded
CheckForPendingPurchases();
}
}
void OnEnable()
{
// Listen for deep link returns
Application.deepLinkActivated += OnDeepLinkActivated;
}
void OnDeepLinkActivated(string url)
{
// User returned via deep link after browser checkout
if (url.Contains("purchase") || url.Contains("checkout"))
{
// Verify purchase on server
VerifyPurchaseOnServer(ExtractOrderIdFromDeepLink(url));
}
}
void CheckForPendingPurchases()
{
// Query server for any purchases that completed while app was backgrounded
// This ensures users get their items even if callbacks were missed
StartCoroutine(QueryPendingPurchases());
}Deep Link Returns After Backgrounding
When using browser mode, users return via deep link after completing purchase. Handle this scenario:
void OnDeepLinkActivated(string url)
{
// Parse deep link URL
var uri = new Uri(url);
var queryParams = System.Web.HttpUtility.ParseQueryString(uri.Query);
// Check if this is a purchase return
if (queryParams["purchase"] != null || queryParams["orderId"] != null)
{
var orderId = queryParams["orderId"] ?? queryParams["purchase"];
// Always verify on server - don't trust deep link parameters
VerifyPurchaseOnServer(orderId);
}
}Low-RAM Device Considerations
On devices with limited memory, consider these optimizations:
Use Browser Mode for Lower Memory Footprint
Browser mode uses less memory as the browser runs in a separate process. Consider using browser mode on low-RAM devices:
void PurchaseItem(string checkoutUrl)
{
// Check available memory
long availableMemory = SystemInfo.systemMemorySize;
if (availableMemory < 2048) // Less than 2GB RAM
{
// Use browser mode for lower memory usage
StashPayCard.Instance.ForceWebBasedCheckout = true;
}
StashPayCard.Instance.OpenCheckout(checkoutUrl, OnDismiss);
}Release Resources Before Checkout
Free up memory before opening checkout to prevent memory pressure:
void PurchaseItem(string checkoutUrl)
{
// Release unnecessary resources
Resources.UnloadUnusedAssets();
System.GC.Collect();
// Small delay to allow cleanup
StartCoroutine(OpenCheckoutAfterCleanup(checkoutUrl));
}
IEnumerator OpenCheckoutAfterCleanup(string checkoutUrl)
{
yield return new WaitForSeconds(0.1f);
StashPayCard.Instance.OpenCheckout(checkoutUrl, OnDismiss);
}Handle Memory Warnings
Implement memory warning handlers to gracefully handle system pressure:
void OnApplicationFocus(bool hasFocus)
{
if (!hasFocus)
{
// App lost focus - may be due to memory pressure
// Save state and prepare for potential termination
SaveCheckoutState();
}
}Best Practices Summary
- Always verify server-side - Never grant items based solely on client callbacks
- Handle callback failures - Implement timeout-based verification as fallback
- Support app backgrounding - Check for purchases when app resumes
- Use webhooks as source of truth - Client callbacks are for UX only
- Test edge cases - Background the app, kill the app, test on low-RAM devices
For more detailed troubleshooting, see the Troubleshooting Guide.
How is this guide?
Presentation Options (Android)
Learn the three ways to present Stash Pay in your Android games - system browser, Chrome Custom Tabs, or fully integrated Stash Dialog. Understand the recommended approaches for different regions.
Troubleshooting
Common issues and solutions when integrating Stash Pay mobile SDK, including callback handling, purchase verification, and edge cases.