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 Qonversion
#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)
    }
}
Qonversion.launch('projectKey', isObserveMode: false);
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

Use the offerings method to get the wrapper object Offerings. You can request the specific offering using its ID:

Qonversion.offerings { (offerings, error) in
  if let offering = offerings?.offering(forIdentifier: "discount") {
    // offering is available
  }
}
[Qonversion offerings:^(QNOfferings * _Nullable offerings, NSError * _Nullable error) {
  QNOffering *offering = [offerings offeringForIdentifier:@"discount"];
  if (offering) {
    // offering is available
  }
}];
Qonversion.offerings(new QonversionOfferingsCallback() {
    @Override
    public void onSuccess(@NotNull QOfferings offerings) {
        QOffering offering = offerings.offeringForID("discount");
        if (offering != null) {
            // offering is available
        }
    }
    @Override
    public void onError(@NotNull QonversionError error) {
        // handle error here
    }
});
Qonversion.offerings(object: QonversionOfferingsCallback {
    override fun onSuccess(offerings: QOfferings) {
        val offering = offerings.offeringForID("discount")
        if (offering != null) {
            // offering is available
        }
    }
    override fun onError(error: QonversionError) {
        // handle error here
    }
})
try {
  final QOfferings offerings = await Qonversion.offerings();
  final QOffering discount = offerings.offeringForIdentifier("discount");
  if (discount != null) {
    // Offering is available
    // Display products
  }
} catch (e) {
  print(e);
}
try {
  const offerings = await Qonversion.offerings();
  const specialOffering = offerings.offeringForIdentifier('discount');
  if (specialOffering != null) {
    // offering is available
  }
} catch (e) {
  // handle error here
}
Qonversion.Offerings((offerings, error) =>
{
   if (error == null)
   {
        var discount = offerings.OfferingForID("discount");
        if (discount != null)
        {
           // Offering is available
           // Display products
        }
   }
   else
   {
       // Handle the error  
       Debug.Log("Error" + error.ToString());
   }
});

The products are listed in the same order as they were added to the Qonversion Offerings settings. Learn more about displaying products here.

Make purchases

When Products and Permissions are set, you can start making purchases with purchaseProduct for iOS and purchase for Android:

Qonversion.purchaseProduct(product) { (permissions, error, isCancelled) in
  
  if let premium: Qonversion.Permission = permissions["premium"], premium.isActive {
    // Flow for success state
  }
}
[Qonversion purchaseProduct:product 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, product, 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, product, 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> permissions = await Qonversion.purchaseProduct(product);
} on QPurchaseException catch (e) {
  print(e);
}
// purchaseProduct method and A/B testing is not yet available on React Native.
// You can use purchase method and Qonversion product ID:
try {
  const permissions: Map<string, Permission> = await Qonversion.purchase('main');
} catch (e) {
  if (e.userCanceled) {
    // purchase canceled by the user
  }
  console.log(e);
}
Qonversion.PurchaseProduct(product, (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 "product" is the Qonversion Product 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
            }
})
try {
  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;
    }
  }
} catch (e) {
  print(e);
}
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
            }
})
try {
  final Map<String, QPermission> permissions = await Qonversion.restore();
} catch (e) {
  print(e);
}
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


Did this page help you?