Qonversion

The Qonversion Inc. Developer Hub

Welcome to the Qonversion Inc. developer hub. You'll find comprehensive guides and documentation to help you start working with Qonversion Inc. as quickly as possible, as well as support if you get stuck. Let's jump right in!

Get Started    

Quick Start

Quick start guide walks you through setting up and using Qonversion

This quick start guide will help you install and set up Qonversion SDK to manage your in-app purchases and user access. Please note, if you want to use Qonversion for analytics and integrations only, and do not want to change anything in your existing in-app purchase flow, you can jump to the Observer Mode guide.

1. Create a project and register your app

Navigate to your Qonversion account and click the New Project option from the dropdown menu. Provide all of the required information to set up the project. (Check the creating a project guide if needed). One app in Qonversion supports iOS, Android, and web app.

2. Configure Products & Permissions (Entitlements)

3. Configure Offerings

An offering is a group of products that you can offer to a user on a given paywall based on your business logic. For example, you can offer one set of products on a paywall immediately after onboarding and another set of products with discounts later on if a user has not converted.

Qonversion offerings are not required to use Qonversion's Infrastructure Mode, but they enable the following features:

  • Run A/B tests
  • Change products offered to your users without app release
  • Store products and experiment results in one place with aggregated data on them

Learn more about Qonversion Offerings here.

4. Install the SDKs

iOS SDK
Android SDK
Flutter SDK
React Native SDK
Unity

5. Using the SDKs

Launching

Import the Qonversion SDK in your module that is responsible for launching third-party dependencies:

import Qonverison
#import "Qonversion.h"
import com.qonversion.android.sdk.Qonversion;
import com.qonversion.android.sdk.Qonversion
import 'package:qonversion_flutter/qonversion_flutter.dart';
import Qonversion from 'react-native-qonversion';
using QonversionUnity;

Initialize the SDK:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
  
    Qonversion.launch(withKey: "projectKey")
    return true
}
#import "Qonversion.h"
  
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [Qonversion launchWithKey:@"projectKey"];
    
    return YES;
}
public class App extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        Qonversion.launch(this, "projectKey", false);
    }
}
public class App : Application {
    override fun onCreate() {
        super.onCreate()
        Qonversion.launch(this, "projectKey", false)
    }
}
QLaunchResult _qLaunchResult;

@override
void initState() {
  super.initState();
  
  _launchQonversion();
}

Future<String> _launchQonversion() async {
  _qLaunchResult = await Qonversion.launch(
      'projectKey',
      isObserveMode: true,
    );
}
Qonversion.launchWithKey('projectKey', false);
private void Start()
{
    Qonversion.Launch("projectKey", false);
}

Set User ID (Optional)

To match user events from Qonversion to the same users on other platforms, you need to set the same user ID on both of them:

Qonversion.setUserID("yourSideUserId")
[Qonversion setUserID:@"yourSideUserId"];
Qonversion.setUserID("yourSideUserID");
Qonversion.setUserID("yourSideUserID")
Qonversion.setUserId('yourSideUserId');
Qonversion.setUserId('yourSideUserID');
Qonversion.SetUserID("yourSideUserId");

Learn more about User ID here.

Display products

To get the list of products available for purchase, use the following method:

Qonversion.products { productsList, error in
    let product = productsList["main"]
    if product?.type == .trial {
    
    }
}
[Qonversion products:^(NSDictionary<NSString *,QNProduct *> * _Nonnull productsList, NSError * _Nullable error) {
  if (error) {
    // Handle error
  }
  QNProduct *product = productsList[@"main"];
  if (product && product.type == QNProductTypeTrial) {

  }
}];
Qonversion.products(new QonversionProductsCallback() {
            @Override
            public void onSuccess(@NotNull Map<String, QProduct> productsList) {
                // handle available products here
            }

            @Override
            public void onError(@NotNull QonversionError error) {
                // handle error here
            }
});
Qonversion.products(callback = object: QonversionProductsCallback {
            override fun onSuccess(products: Map<String, QProduct>) {
                // handle available products here
            }

            override fun onError(error: QonversionError) {
                // handle error here
            }
})
final Map<String, QProduct> products = await Qonversion.products();
const products: Map<string, Product> = await Qonversion.products();
Qonversion.Products((products, error) =>
{
   if (error == null)
   {
       // Display products
   }
   else
   {
       // Handle the error  
       Debug.Log("Error" + error.ToString());
   }
});

Learn more about displaying products here.

Make purchases

After a user selects the product to be purchased, you can make a purchase as follows:

Qonversion.purchase("main") { (permissions, error, isCancelled) in
  
  if let premium: Qonversion.Permission = permissions["premium"], premium.isActive {
    // Flow for success state
  }
}
[Qonversion purchase:@"main" completion:^(NSDictionary<NSString *,QNPermission *> * _Nonnull permissions,
                                          NSError * _Nullable error,
                                          BOOL cancelled) {
  QNPermission *premiumPermission = permissions[@"premium"];
  
  if (premiumPermission && premiumPermission.isActive) {
    // Flow for success state
  }
}];
Qonversion.purchase(this, "main", new QonversionPermissionsCallback() {
            @Override
            public void onSuccess(@NotNull Map<String, QPermission> permissions) {
                QPermission premiumPermission = permissions.get("premium");

                if (premiumPermission != null && premiumPermission.isActive()) {
                    // handle active permission here
                }
            }

            @Override
            public void onError(@NotNull QonversionError error) {
                // handle error here
            }
});
Qonversion.purchase(this, "main", callback = object: QonversionPermissionsCallback {
            override fun onSuccess(permissions: Map<String, QPermission>) {
                val premiumPermission = permissions["premium"]
                if (premiumPermission != null && premiumPermission.isActive()) {
                    // handle active permission here
                }
            }

            override fun onError(error: QonversionError) {
                // handle error here
            }
})
try {
  final Map<String, QPermission> purchaseResult = await Qonversion.purchase('main');
} on QPurchaseException catch (e) {
    // handle error here
}
try {
  const permissions: Map<string, Permission> = await Qonversion.purchase('main');
} catch (e) {
  console.log(e);
}
Qonversion.Purchase("main", (permissions, error) =>
{
      if (error == null)
      {
          if (permissions.TryGetValue("premium", out Permission premium) && premium.IsActive)
          {
             // Handle the active permission here
          }
      }
      else
      {
        // Handle the error  
        Debug.Log("Error" + error.ToString());
      }
});

Where "main" is the Qonversion Product Identifier created in the Product Center.
Learn more about purchasing products here.

Check subscription status and user permissions (entitlements)

To check user permissions (entitlements) to the premium content, as well as to get the in-app subscription status, use checkPermissions method:

🚧

Note please that the permission object will be available only in case the user made any purchase. In case there were no purchases you will receive an empty result.

Qonversion.checkPermissions { (permissions, error) in
  if let error = error {
    // handle error
    return
  }
  
  if let premium: Qonversion.Permission = permissions["premium"], premium.isActive {
    switch premium.renewState {
       case .willRenew, .nonRenewable:
         // .willRenew is the state of an auto-renewable subscription 
         // .nonRenewable is the state of consumable/non-consumable IAPs that could unlock lifetime access
         break
       case .billingIssue:
         // Grace period: permission is active, but there was some billing issue.
         // Prompt the user to update the payment method.
         break
       case .cancelled:
         // The user has turned off auto-renewal for the subscription, but the subscription has not expired yet.
         // Prompt the user to resubscribe with a special offer.
         break
       default: break
    }
  }
}
[Qonversion checkPermissions:^(NSDictionary<NSString *,QNPermission *> * _Nonnull permissions,
                               NSError * _Nullable error) {
  
  QNPermission *premiumPermission = permissions[@"premium"];
  if (premiumPermission && premiumPermission.isActive) {
    switch (premiumPermission.renewState) {
      case QNPermissionRenewStateWillRenew:
      case QNPermissionRenewStateNonRenewable:
        // QNPermissionRenewStateWillRenew is state for auto-renewable purchases
        // QNPermissionRenewStateNonRenewable is state for in-app purchases that unlock the permission lifetime
        break;
      case QNPermissionRenewStateBillingIssue:
        // Grace period: permission is active, but there was some billing issue.
        // Prompt the user to update the payment method.
        break;
      case QNPermissionRenewStateCancelled:
        // The user canceled the subscription, but the subscription has not expired yet.
        // Prompt the user to resubscribe with some special offer.
        break;
      default:
        break;
    }
  }
}];
Qonversion.checkPermissions(new QonversionPermissionsCallback() {
            @Override
            public void onSuccess(@NotNull Map<String, QPermission> permissions) {
                QPermission premiumPermission = permissions.get("premium");

                if (premiumPermission != null && premiumPermission.isActive()) {
                    switch (premiumPermission.getRenewState()) {
                        case NonRenewable:
                        case WillRenew:
                            // WillRenew is the state of an auto-renewable subscription
                            // NonRenewable is the state of consumable/non-consumable IAPs that could unlock lifetime access
                            break;
                        case BillingIssue:
                            // Prompt the user to update the payment method.
                            break;
                        case Canceled:
                            // The user has turned off auto-renewal for the subscription, but the subscription has not expired yet.
                            // Prompt the user to resubscribe with a special offer.
                            break;
                        default: break;
                }
            }

            @Override
            public void onError(@NotNull QonversionError error) {
                // handle error here
            }
});
Qonversion.checkPermissions(object: QonversionPermissionsCallback {
            override fun onSuccess(permissions: Map<String, QPermission>) {
                val premiumPermission = permissions["premium"]
                if (premiumPermission != null && premiumPermission.isActive()) {
                    // handle active permission here

                    // also you can check renew state if needed
                    // for example to check if user has canceled subscription and offer him a discount
                    when (premiumPermission.renewState) {
                        QProductRenewState.NonRenewable,
                        QProductRenewState.WillRenew ->
                            // WillRenew is the state of an auto-renewable subscription
                            // NonRenewable is the state of consumable/non-consumable IAPs that could unlock lifetime access
                        QProductRenewState.BillingIssue ->
                        // Prompt the user to update the payment method.
                        QProductRenewState.Canceled ->
                        // The user has turned off auto-renewal for the subscription, but the subscription has not expired yet.
                        // Prompt the user to resubscribe with a special offer.
                    }
                }
            }

            override fun onError(error: QonversionError) {
                // handle error here
            }
})
final Map<String, QPermission>> permissions = await Qonversion.checkPermissions();
final main = permissions['main'];
if (main != null && main.isActive) {
  switch (main.renewState) {
    case QProductRenewState.willRenew:
    case QProductRenewState.nonRenewable:
      // .willRenew is the state of an auto-renewable subscription 
      // .nonRenewable is the state of consumable/non-consumable IAPs that could unlock lifetime access
      break;
    case QProductRenewState.billingIssue:
      // Grace period: permission is active, but there was some billing issue.
      // Prompt the user to update the payment method.
      break;
    case QProductRenewState.canceled:
      // The user has turned off auto-renewal for the subscription, but the subscription has not expired yet.
      // Prompt the user to resubscribe with a special offer.
      break;
    default: 
      break;
  }
}
const permissions: Map<string, Permission> = await Qonversion.checkPermissions();
    
const premiumPermission = permissions.get('premium');
if (mainPermission != null) {
  switch (premiumPermission.renewState) {
    case RenewState.NON_RENEWABLE:
      // NON_RENEWABLE is the state of consumable/non-consumable IAPs that could unlock lifetime access
      break;
    case RenewState.WILL_RENEW:
      // WILL_RENEW is the state of an auto-renewable subscription 
      break;
    case RenewState.CANCELED:
      // The user has turned off auto-renewal for the subscription, but the subscription has not expired yet.
      // Prompt the user to resubscribe with a special offer.
      break;
    case RenewState.BILLING_ISSUE:
      // Grace period: permission is active, but there was some billing issue.
      // Prompt the user to update the payment method.
      break;
  }
}
Qonversion.CheckPermissions((permissions, error) =>
{
      if (error == null)
      {
           if (permissions.TryGetValue("premium", out Permission premium) && premium.IsActive)
            {
                switch(premium.RenewState)
                {
                    case QProductRenewState.WillRenew:
                    case QProductRenewState.NonRenewable:
                        // .willRenew is the state of an auto-renewable subscription 
                        // .nonRenewable is the state of consumable/non-consumable IAPs that could unlock lifetime access
                        break;
                    case QProductRenewState.BillingIssue:
                        // Grace period: permission is active, but there was some billing issue.
                        // Prompt the user to update the payment method.
                        break;
                    case QProductRenewState.Canceled:
                        // The user has turned off auto-renewal for the subscription, but the subscription has not expired yet.
                        // Prompt the user to resubscribe with a special offer.
                        break;
                    default:
                        break;
                }
            }
      }
      else
      {
        // Handle the error  
        Debug.Log("Error" + error.ToString());
      }
});

Learn more about checking a subscription state and permissions here.

Restore previous purchase

To restore user's previous purchases use the restore method:

Qonversion.restore { [weak self] (permissions, error) in
  if let error = error {
    // Handle error
  }
  
  if let permission: Qonversion.Permission = permissions["plus"], permission.isActive {
    // Restored and permission is active 
  }
}
[Qonversion restoreWithCompletion:^(NSDictionary<NSString *,QNPermission *> * _Nonnull result, NSError * _Nullable error) {
  if (error) {
    // Handle error
  }
  QNPermission *permission = result[@"active"];
  if (permission && permission.isActive) {
    // Restored and permission is active
  }
}];
Qonversion.restore(new QonversionPermissionsCallback() {
            @Override
            public void onSuccess(@NotNull Map<String, QPermission> permissions) {
                QPermission premiumPermission = permissions.get("premium");

                if (premiumPermission != null && premiumPermission.isActive()) {
                    // handle active permission here
                }
            }

            @Override
            public void onError(@NotNull QonversionError error) {
                // handle error here
            }
});
Qonversion.restore(object : QonversionPermissionsCallback {
            override fun onSuccess(permissions: Map<String, QPermission>) {
                val premiumPermission = permissions["premium"]
                if (premiumPermission != null && premiumPermission.isActive()) {
                    // handle active permission here
                }
            }

            override fun onError(error: QonversionError) {
                // handle error here
            }
})
final Map<String, QPermission>> permissions = await Qonversion.restore();
try {
  const permissions: Map<string, Permission> = await Qonversion.restore();
 } catch (e) {
  console.log(e);
}
Qonversion.Restore((permissions, error) =>
{
      if (error == null)
      {
         // Handle permissions here
      }
      else
      {
        // Handle the error  
        Debug.Log("Error" + error.ToString());
      }
});

Next Steps

→ Check out the Sample Apps
→ Learn the details of Qonversion SDKs
→ Tips on testing
Troubleshooting
Migrating In-App Subscriptions

Updated 8 days ago


Quick Start


Quick start guide walks you through setting up and using Qonversion

Suggested Edits are limited on API Reference Pages

You can only suggest edits to Markdown body content, but not to the API spec.