Create Remote Config

Create Remote Configs to manage your onboarding flows, paywall UI, or pricing settings, avoiding extra app releases

The Remote Config feature helps you change your onboarding flows, paywall UI, or pricing settings without additional app releases. Moreover, it enables you to rapidly iterate with your monetization experiments

1. Select your app context to configure

As a first step, name your remote configuration and select a context (part of your application) you'd like to manage remotely. Examples of app contexts you may configure with us:

  • main_paywall: to set up settings for different user segments for your main paywall.
  • main_paywall_products: to manage only products remotely.
  • onboarding: to set up the entire user onboarding journey.
  • onboarding_step_2: to configure only specific steps of the user onboarding flow.
  • [your_key]: to set up any part of your user's monetization experience.

2. Add attributes for your configuration

Qonversion Remote Config provides you with flexible in-app values using which you can set up any behavior and appearance of your app. The core of these in-app values is a plain JSON file consisting of key-value data. We support the following data types:

  • String.
    • Use this option to validate pricing, communication, or visual hypothesis.
    • Examples: native.subs.full.v4.w.8.99.trial.7d, Unlock Fast and Secure Browsing, #3076FF, etc.
  • Number.
    • Use this option, for example, to show only a subset of your onboarding screens.
    • Examples: 2, 5, 23, etc.
  • Boolean.
    • Use this option to turn on or off some features.
    • Examples: true, false
  • Json.
    • Use this option to validate advanced changes in your app's behavior.
    • Examples: {"banner_text": "Choose your plan", "product_top": "native.subs.full.v4.w.8.99.trial.7d", "product_bottom": "subs.month.17.99", "skip_onboarding": true}.

Integrate changes into your app

📘

Configuration source

Qonversion Remote Configs and Experiments share single methods to get configurations. You can distinguish the source of the result received by looking at the source field. Learn more about fields available.

To receive the configuration with the Context key set, call the following Qonversion remoteConfig method.

Qonversion.shared().remoteConfig(contextKey: "my_context_key") { remoteConfig, error in
    // Use remoteConfig here
}
[[Qonversion sharedInstance] remoteConfig:@"my_context_key" completion:^(QONRemoteConfig * _Nullable remoteConfig, NSError * _Nullable error) {
    // Use remoteConfig here                           
}];
Qonversion.shared.remoteConfig("my_context_key", object : QonversionRemoteConfigCallback {
    override fun onSuccess(remoteConfig: QRemoteConfig) {
        // Use remoteConfig here                             
    }

    override fun onError(error: QonversionError) {
        // Handle error here
    }
})
Qonversion.getSharedInstance().remoteConfig("my_context_key", new QonversionRemoteConfigCallback() {
    @Override
    public void onSuccess(@NonNull QRemoteConfig remoteConfig) {
        // Use remoteConfig here
    }

    @Override
    public void onError(@NonNull QonversionError error) {
        // Handle error here
    }
});
const remoteConfig = await Qonversion.getSharedInstance().remoteConfig('my_context_key');
final remoteConfig = await Qonversion.getSharedInstance().remoteConfig(contextKey: "my_context_key");
Qonversion.GetSharedInstance().RemoteConfig("my_context_key", (remoteConfig, error) =>
{
    // Use remoteConfig here
});
const remoteConfig = await Qonversion.getSharedInstance().remoteConfig('my_context_key');
const remoteConfig = await Qonversion.getSharedInstance().remoteConfig('my_context_key');

In case you're using configurations with empty Context key, call the same method with no arguments added:

Qonversion.shared().remoteConfig { remoteConfig, error in
    // Use remoteConfig here
}
[[Qonversion sharedInstance] remoteConfig:^(QONRemoteConfig * _Nullable remoteConfig, NSError * _Nullable error) {
    // Use remoteConfig here                           
}];
Qonversion.shared.remoteConfig(object : QonversionRemoteConfigCallback {
    override fun onSuccess(remoteConfig: QRemoteConfig) {
        // Use remoteConfig here                             
    }

    override fun onError(error: QonversionError) {
        // Handle error here
    }
})
Qonversion.getSharedInstance().remoteConfig(new QonversionRemoteConfigCallback() {
    @Override
    public void onSuccess(@NonNull QRemoteConfig remoteConfig) {
        // Use remoteConfig here
    }

    @Override
    public void onError(@NonNull QonversionError error) {
        // Handle error here
    }
});
const remoteConfig = await Qonversion.getSharedInstance().remoteConfig();
final remoteConfig = await Qonversion.getSharedInstance().remoteConfig();
Qonversion.GetSharedInstance().RemoteConfig((remoteConfig, error) =>
{
    // Use remoteConfig here
});
const remoteConfig = await Qonversion.getSharedInstance().remoteConfig();
const remoteConfig = await Qonversion.getSharedInstance().remoteConfig();

If necessary, you can also request a list of remote configs for all the context keys, including the empty one.

Qonversion.shared().remoteConfigList { remoteConfigList, error in
  // Use remoteConfigList here
}
[[Qonversion sharedInstance] remoteConfigList:^(QONRemoteConfigList * _Nullable remoteConfigList, NSError * _Nullable error) {
  // Use remoteConfigList here
}]
Qonversion.shared.remoteConfigList(object : QonversionRemoteConfigListCallback {
    override fun onSuccess(remoteConfigList: QRemoteConfigList) {
        // Use remoteConfigList here
    }

    override fun onError(error: QonversionError) {
        // Handle error here
    }
})
Qonversion.getSharedInstance().remoteConfigList(new QonversionRemoteConfigListCallback() {
    @Override
    public void onSuccess(@NonNull QRemoteConfigList remoteConfigList) {
      // Use remoteConfigList here
    }

    @Override
    public void onError(@NonNull QonversionError error) {
      // Handle error here
    }
});
const remoteConfigList = await Qonversion.getSharedInstance().remoteConfigList();
final remoteConfigList = await Qonversion.getSharedInstance().remoteConfigList();
Qonversion.GetSharedInstance().RemoteConfigList((remoteConfigList, error) =>
{
    // Use remoteConfigList here
});
const remoteConfigList = await Qonversion.getSharedInstance().remoteConfigList();
const remoteConfigList = await Qonversion.getSharedInstance().remoteConfigList();

If you need remote configs for a specific set of context keys, just use the following method.

Qonversion.shared().remoteConfigList(
  contextKeys: ["my_context_key", "another_context_key"],
  includeEmptyContextKey: true // to include remote config without context key
) { remoteConfigList, error in
  // Use remoteConfigList here
}
[[Qonversion sharedInstance] remoteConfigList:@[@"my_context_key", @"another_context_key"]
                       includeEmptyContextKey:YES // to include remote config without context key
 																	 completion:^(QONRemoteConfigList * _Nullable remoteConfigList, NSError * _Nullable error) {
  // Use remoteConfigList here
}
Qonversion.shared.remoteConfigList(
    listOf("my_context_key", "another_context_key"),
    true, // to include remote config without context key
    object : QonversionRemoteConfigListCallback {
        override fun onSuccess(remoteConfigList: QRemoteConfigList) {
            // Use remoteConfigList here
        }

        override fun onError(error: QonversionError) {
            // Handle error here
        }
	  }
)
Qonversion.getSharedInstance().remoteConfigList(
    Arrays.asList("my_context_key", "another_context_key"),
    true, // to include remote config without context key
    new QonversionRemoteConfigListCallback() {
        @Override
        public void onSuccess(@NonNull QRemoteConfigList remoteConfigList) {
            // Use remoteConfigList here
        }

        @Override
        public void onError(@NonNull QonversionError error) {
            // Handle error here
        }
		}
);
const remoteConfigList = await Qonversion.getSharedInstance().remoteConfigListForContextKeys(
  ['my_context_key', 'another_context_key'],
  true // to include remote config without context key
);
final remoteConfigList = await Qonversion.getSharedInstance().remoteConfigListForContextKeys(
  ["my_context_key", "another_context_key"],
  true // to include remote config without context key
);
Qonversion.GetSharedInstance().RemoteConfigList(
  new string[] {"my_context_key", "another_context_key"},
  true, // to include remote config without context key
  (remoteConfigList, error) =>
{
    // Use remoteConfigList here
});
const remoteConfigList = await Qonversion.getSharedInstance().remoteConfigListForContextKeys(
  ['my_context_key', 'another_context_key'],
  true // to include remote config without context key
);
const remoteConfigList = await Qonversion.getSharedInstance().remoteConfigListForContextKeys(
  ['my_context_key', 'another_context_key'],
  true // to include remote config without context key
);

RemoteConfigList fields description

FieldDescription
remoteConfigsThe list of requested remote configs
remoteConfigForContextKeyFunction for requesting specific remote config from the above list by the context key
remoteConfigForEmptyContextKeyFunction for requesting the remote config from the above list with empy context key

RemoteConfig fields description

FieldDescription
payloadJSON payload you have configured using the Qonversion dashboard.
experimentObject (Experiment) with the experiment's information.
sourceSource (RemoteConfigurationSource) of the configuration.

Experiment description

FieldDescription
identifier/idExperiment's identifier.
nameExperiment's name. The same as you set in Qonversion. You can use it for analytical purposes.
groupExperiment's group (ExperimentGroup) the user has been assigned to.

ExperimentGroup description

FieldDescription
identifier/idExperiment group's identifier.
nameExperiment group's name. The same as you set in Qonversion. You can use it for analytical purposes.
typeType of the experiment's group. Either control or treatment.

RemoteConfigurationSource description

FieldDescription
identifier/idEither experiment's or remote config's ID.
nameEither experiment's or remote config's name.
assignmentTypeHow the current payload was assigned to the user. Either automatically or manually.
typeOne of the following: experiment control group, experiment treatment group, remote configuration.
contextKeyContext key assigned to either experiment or remote config.

Please, note:

  • If you're using the Qonversion Experiments feature, the remoteConfigobject will also contain experiment-related fields.
  • Qonversion assigns eligible users to launched experiments once the remoteConfig is called. We also recommend paying attention to the Segmentation rules for the configuration.

Test changes before launch

📘

Please, note, the guide below allows you to test only configurations created through the Remote Config dashboard section. To test configurations from the Experiments section, please, follow the test experimental changes before launch guide.

We highly recommend testing if your app works properly with the changes you want to roll out to your users. You can do so by following the following steps:

  1. Copy the ID for your remote config
  1. Pass the values to Qonversion SDK by using the attachUserToRemoteConfiguration method
Qonversion.shared().attachUser(toRemoteConfiguration: "your_remote_configuration_id") { success, error in
     // handle result
}
[[Qonversion sharedInstance] attachUserToRemoteConfiguration:@"your_remote_configuration_id" completion:^(BOOL success, NSError * _Nullable error) {
    // handle result
}];
Qonversion.shared.attachUserToRemoteConfiguration("your_remote_configuration_id", object : QonversionRemoteConfigurationAttachCallback {
    override fun onSuccess() {
        // handle success
    }

    override fun onError(error: QonversionError) {
        // handle error
    }
})
Qonversion.getSharedInstance().attachUserToRemoteConfiguration("your_remote_configuration_id", new QonversionRemoteConfigurationAttachCallback() {
    @Override
    public void onSuccess() {
        // handle success
    }

    @Override
    public void onError(@NonNull QonversionError error) {
        // handle error
    }
});
await Qonversion.getSharedInstance().attachUserToRemoteConfiguration("your_remote_configuration_id");
await Qonversion.getSharedInstance().attachUserToRemoteConfiguration("your_remote_configuration_id");
Qonversion.GetSharedInstance().AttachUserToRemoteConfiguration("your_remote_configuration_id", (success, error) =>
{
    // handle result
});
await Qonversion.getSharedInstance().attachUserToRemoteConfiguration("your_remote_configuration_id");
await Qonversion.getSharedInstance().attachUserToRemoteConfiguration("your_remote_configuration_id");
  • In case your user has already been attached to another configuration, use the detachUserFromRemoteConfiguration method.
Qonversion.shared().detachUser(fromRemoteConfiguration: "attached_remote_configuration_id") { success, error in  
    // handle result  
}
[[Qonversion sharedInstance] detachUserFromRemoteConfiguration:@"attached_remote_configuration_id" completion:^(BOOL success, NSError * _Nullable error) {
    // handle result
}];
Qonversion.shared.detachUserFromRemoteConfiguration("attached_remote_configuration_id", object : QonversionRemoteConfigurationAttachCallback {
    override fun onSuccess() {
        // handle success
    }

    override fun onError(error: QonversionError) {
        // handle error
    }
})
Qonversion.getSharedInstance().detachUserFromRemoteConfiguration("attached_remote_configuration_id", new QonversionRemoteConfigurationAttachCallback() {
    @Override
    public void onSuccess() {
        // handle success
    }

    @Override
    public void onError(@NonNull QonversionError error) {
        // handle error
    }
});
await Qonversion.getSharedInstance().detachUserFromRemoteConfiguration("attached_remote_configuration_id");
await Qonversion.getSharedInstance().detachUserFromRemoteConfiguration("attached_remote_configuration_id");
Qonversion.GetSharedInstance().DetachUserFromRemoteConfiguration("attached_remote_configuration_id", (success, error) =>
{
    // handle result
});
await Qonversion.getSharedInstance().detachUserFromRemoteConfiguration("attached_remote_configuration_id");
await Qonversion.getSharedInstance().detachUserFromRemoteConfiguration("attached_remote_configuration_id");
  1. Call the Qonversion remoteConfig method. Now Qonversion SDK returns data associated with previously set remote config.
  2. Validate your app logic without launching the configuration.

🚧

Pay attention before release

Do not forget to remove the usage of the attachUserToRemoteConfiguration method before your app release. Otherwise, all your users may be exposed to only one remote config.

2. Segment users

Qonversion Remote Config has flexible options to target a desired user segment.

Segment users by:

  • App install date
    • Use this option to assign the configuration only to new app installs.
  • App version
    • Use this option to assign the configuration only for users with the app version with the new features implemented.
  • Country
    • Use this option to run new behavior only in selected countries.
  • Store
    • Use this option to target only a specific store (Apple App Store or Google Play).
  • User's active subscription
    • User this option to target only users with/without any active subscriptions or having a specific one.

3. Launch the configuration

Once you have added all the necessary properties to your in-app configuration, validated changes in your app, and assigned desired segmentation rules, the only thing left is to click the Create button to move the configuration from Draft to Active state.