# Description of A/B testing on the SDK side

{% hint style="danger" %}
**This integration manual is only for SDK versions below 2.6.0 / Unity 3.10.0.**&#x20;

If you are using SDK 2.6.0 / Unity 3.10.0 and higher, please refer to the [updated integration manual](https://docs.devtodev.com/integration/integration-of-sdk-v2/remote-configuration/rc-integration).
{% endhint %}

## Step 1&#x20;

Some operations can take a while because the SDK operates asynchronously. These operations are:&#x20;

### **A/B test configuration.**

After you’ve created an A/B test in the web interface, the SDK will receive its configuration via the network. Use the  **`remoteConfigWaiting`** property in the **`DTDRemoteConfig`** class to set the maximum time allowed for waiting for the A/B test configuration.

{% hint style="info" %}
`remoteConfigWaiting`is set in seconds
{% endhint %}

By default, the **`remoteConfigWaiting`** value is equal to null. This means that the test configuration waiting time is unlimited. The limitation is important in case the test that you are about to execute can influence your app functioning.

Example: *`DTDRemoteConfig.remoteConfigWaiting = 10`*&#x20;

In this case, the SDK will wait for the A/B test configuration for 10 seconds. If it won’t receive the config during the allocated time, it will notify the developer by using the `onReceived(result: DTDRemoteConfigReceiveResult)` method with **Failure** value and disable the A/B testing until the next SDK initialization.

### Waiting for an A/B test group.

After the SDK finds a test, it will wait for a suitable group to include the user into and start the experiment.

{% hint style="info" %}
By default, waiting time (`groupDefinitionWaiting`) is 10 seconds.
{% endhint %}

You can change this value up or down.

Example: `DTDRemoteConfig.groupDefinitionWaiting = 15`

In this case, the SDK will wait for a group for no more than 15 seconds. If It can't find a suitable test for 15 seconds, it will be cancelled and its activation will be impossible. After the next SDK initialization (app restart), the user will have another chance to participate in the test.

{% hint style="warning" %}
The `DTDRemoteConfig.remoteConfigWaiting` and `DTDRemoteConfig.groupDefinitionWaiting`values can be set only prior to SDK initialization!
{% endhint %}

## Step 2

In the `DTDRemoteConfig` class you need to set the default variables and their values using the `DTDRemoteConfig.defaults` property.

{% hint style="info" %}
The variable values in the `defaults` property do not change on the SDK side.
{% endhint %}

After setting up `DTDRemoteConfig.defaults`, you can receive the variable values by using the `DTDRemoteConfig.config` property.

{% hint style="warning" %}
When working with A/B tests, always use the `config` property to receive the actual variables and their values!
{% endhint %}

{% hint style="info" %}
If for some reasons, the device can not be included in the test (no network or network problems, devtodev did not assign it to a group, incorrect SDK implementation, etc.)  `DTDRemoteConfig.config` will return default values. Using this approach, you can always shape the desirable UI and the business logic of the app.
{% endhint %}

## **Step 3**

{% tabs fullWidth="true" %}
{% tab title="iOS+macOS (Swift)" %}
To work with A/B testing, use the `DTDAnalytics.initializeWithAbTest` initialization method.

{% hint style="info" %}
If you used `DTDAnalytics.initialize` previously, you need to replace it with `DTDAnalytics.initializeWithAbTest` as the SDK initialization method.&#x20;
{% endhint %}

The `DTDRemoteConfigListener` interface is added to the  `initializeWithAbTest` method. It implements three methods:

* `onReceived(result: DTDRemoteConfigReceiveResult)` &#x20;
* `onPrepareToChange()`&#x20;
* `onChanged(result: DTDRemoteConfigChangeResult, error: Error?)`

{% hint style="warning" %}
The `DTDRemoteConfigListener`methods are not called in the main thread - you need to keep this in mind when interacting with UI elements of the app. Also, do not execute operations that block the thread in the `DTDRemoteConfigListener` methods, because this will disable the SDK operation (see examples).
{% endhint %}
{% endtab %}

{% tab title="iOS+macOS (Objective-C)" %}
To work with A/B testing, use the `[DTDAnalytics applicationKey:* abConfigListener:*]` initialization method.

{% hint style="info" %}
If you used `[DTDAnalytics applicationKey:*]` previously, you need to replace it with \[DTDAnalytics applicationKey:\* abConfigListener:\*] as the SDK initialization method.&#x20;
{% endhint %}

The `DTDRemoteConfigListener` interface is added to the  `[DTDAnalytics applicationKey:* abConfigListener:*]` method. It implements three methods:

* `-(void)onReceivedResult:(enum DTDRemoteConfigReceiveResult)result`
* `-(void)onPrepareToChange`
* `-(void)onChangedResult:(enum DTDRemoteConfigChangeResult)result error:(NSError *)error`

{% hint style="warning" %}
The `DTDRemoteConfigListener`methods are not called in the main thread - you need to keep this in mind when interacting with UI elements of the app. Also, do not execute operations that block the thread in the `DTDRemoteConfigListener` methods, because this will disable the SDK operation (see examples).
{% endhint %}
{% endtab %}

{% tab title="Android (Kotlin)" %}
To work with A/B testing, use the `DTDAnalytics.initializeWithAbTest` initialization method.

{% hint style="info" %}
If you used `DTDAnalytics.initialize` previously, you need to replace it with `DTDAnalytics.initializeWithAbTest` as the SDK initialization method.&#x20;
{% endhint %}

The `IRemoteConfigListener` interface is added to the  `initializeWithAbTest` method. It implements three methods:

* `onReceived(result: DTDRemoteConfigReceiveResult)`&#x20;
* `onPrepareToChange()`&#x20;
* `onChanged(result: DTDRemoteConfigChangeResult, ex: Exception?)`

{% hint style="warning" %}
The `DTDRemoteConfigListener`methods are not called in the main thread - you need to keep this in mind when interacting with UI elements of the app. Also, do not execute operations that block the thread in the `DTDRemoteConfigListener` methods, because this will disable the SDK operation (see examples).
{% endhint %}
{% endtab %}

{% tab title=" Android (Java)" %}
To work with A/B testing, use the `DTDAnalytics.INSTANCE.initializeWithAbTest` initialization method.

{% hint style="info" %}
If you used `DTDAnalytics.INSTANCE.initialize` previously, you need to replace it with `DTDAnalytics.INSTANCE.initializeWithAbTest` as the SDK initialization method.&#x20;
{% endhint %}

The `IRemoteConfigListener` interface is added to the  `initializeWithAbTest` method. It implements three methods:

* `void onReceived(@NonNull DTDRemoteConfigReceiveResult result)`&#x20;
* `void onPrepareToChange()`&#x20;
* `void onChanged(@NonNull DTDRemoteConfigChangeResult result, @Nullable Exception ex)`

{% hint style="warning" %}
The `DTDRemoteConfigListener`methods are not called in the main thread - you need to keep this in mind when interacting with UI elements of the app. Also, do not execute operations that block the thread in the `DTDRemoteConfigListener` methods, because this will disable the SDK operation (see examples).
{% endhint %}
{% endtab %}

{% tab title="Unity" %}
To work with A/B testing, use the `DTDAnalytics.InitializeWithAbTests` initialization method.

{% hint style="info" %}
If you used `DTDAnalytics.Initialize` previously, you need to replace it with `DTDAnalytics.InitializeWithAbTests` as the SDK initialization method.&#x20;
{% endhint %}

The `DTDRemoteConfigListener` interface is added to the  `InitializeWithAbTests` method. It implements three methods:

* `OnReceived(DTDRemoteConfigReceiveResult result)` &#x20;
* `OnPrepareToChange()`&#x20;
* `OnChanged(DTDRemoteConfigChangeResult result, string exceptionMessage = null)`

{% hint style="warning" %}
The `DTDRemoteConfigListener`methods are not called in the main thread - you need to keep this in mind when interacting with UI elements of the app. Also, do not execute operations that block the thread in the `DTDRemoteConfigListener` methods, because this will disable the SDK operation (see examples).
{% endhint %}
{% endtab %}

{% tab title=".NET + UWP" %}
To work with A/B testing, use the `DTDAnalytics.InitializeWithAbTests` initialization method.

{% hint style="info" %}
If you used `DTDAnalytics.Initialize` previously, you need to replace it with `DTDAnalytics.InitializeWithAbTests` as the SDK initialization method.&#x20;
{% endhint %}

The `IDTDRemoteConfigListener` interface is added to the  `InitializeWithAbTests` method. It implements three methods:

* `OnReceived(DTDRemoteConfigReceiveResult result)`
* `OnPrepareToChange()`
* `OnChanged(DTDRemoteConfigChangeResult result, string error)`

{% hint style="warning" %}
The `DTDRemoteConfigListener`methods are not called in the main thread - you need to keep this in mind when interacting with UI elements of the app. Also, do not execute operations that block the thread in the `DTDRemoteConfigListener` methods, because this will disable the SDK operation (see examples).
{% endhint %}
{% endtab %}

{% tab title="Web" %}
{% hint style="warning" %}
**Known Limitations: A/B Testing in Restricted Browser Environments**

When running the A/B testing module in an iframe, certain browsers with strict privacy settings (e.g., Safari, Firefox, Brave) may block access to storage mechanisms such as cookies or `localStorage`. This limitation prevents the proper functioning of A/B tests in these environments. SDK is checking the possibility of accessing storage and will turn off the A/B testing for such a user/device if that's the case.
{% endhint %}

To work with A/B testing, use the `devtodev.initializeWithAbTest` initialization method.

If you used `devtodev.initialize` previously, you need to replace it with `devtodev.initializeWithAbTest` as the SDK initialization method.

The `initializeWithAbTest` method as a third parameter takes an object with 3 `Callable` as arguments, to work with A/B tests it is necessary to implement:

* `onReceived(result: DTDRemoteConfigReceiveResult)`
* `onPrepareToChange()`
* `onChanged(result: DTDRemoteConfigChangeResult, error: String)`

```javascript
window.devtodev.initializeWithAbTest(
    appKey, 
    {
        userId: userId,
        logLevel: logLevel,
        trackingAvailability: true,
    },
    {
        onReceived: function(result) {
            console.log('onReceived callback', result)
        },
        onPrepareToChange: function() {
            console.log('onPrepareToChange callback')
        },
        onChanged: function(result, error) {
            console.log('onChanged callback', result, error)
        }
    }
)
```

{% endtab %}

{% tab title="Unreal" %}
To work with A/B testing, use the `UDTDAnalyticsBPLibrary::InitializeWithAbTest` initialization method.

<figure><img src="https://2105883905-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnGcP_ZeRJ1ipj9O8dF%2Fuploads%2F7DW10lw6jykQbmQ3HQZK%2F%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA%20%D1%8D%D0%BA%D1%80%D0%B0%D0%BD%D0%B0%202023-06-27%20%D0%B2%2014.00.30.png?alt=media&#x26;token=8ea33f91-6a11-4bf5-966a-fa6a1e51cbf1" alt="" width="310"><figcaption><p>Blueprint</p></figcaption></figure>

{% hint style="info" %}
If you used `UDTDAnalyticsBPLibrary::Initialize` previously, you need to replace it with `UDTDAnalyticsBPLibrary::InitializeWithAbTest` as the SDK initialization method.&#x20;
{% endhint %}

Implements three delegate methods:

* `onRemoteConfigReceive(EDTDRemoteConfigReceiveResult result)`
* `onRemoteConfigPrepareToChange()`&#x20;
* `onRemoteConfigChange(EDTDRemoteConfigChangeResult result, FString error)`

<figure><img src="https://2105883905-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnGcP_ZeRJ1ipj9O8dF%2Fuploads%2FSM4UOld5z97VHe4JlutR%2F%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA%20%D1%8D%D0%BA%D1%80%D0%B0%D0%BD%D0%B0%202023-06-27%20%D0%B2%2018.26.19.png?alt=media&#x26;token=40da8c9e-7a20-40ac-ae07-7aae97b23a58" alt="" width="375"><figcaption><p>Blueprint</p></figcaption></figure>

```cpp
DECLARE_DELEGATE(FDTDRemoteConfigPrepareToChangeDelegate);
DECLARE_DELEGATE_OneParam(FDTDRemoteConfigReceiveResultDelegate, EDTDRemoteConfigReceiveResult);
DECLARE_DELEGATE_TwoParams(FDTDRemoteConfigChangeResultDelegate, EDTDRemoteConfigChangeResult, const FString&);
```

{% endtab %}

{% tab title="Godot" %}
To work with A/B testing, use the `DTDAnalytics.InitializeWithAbTest` initialization method.

{% hint style="info" %}
If you used `DTDAnalytics.initialize` previously, you need to replace it with `DTDAnalytics.initializeWithAbTest` as the SDK initialization method.&#x20;
{% endhint %}

The `InitializeWithAbTest` method takes 3 `Callable` as arguments, to work with A/B tests it is necessary to implement:

* `onRemoteConfigReceive(result: GDDTDRemoteConfigReceiveResult.ReceiveResult)`
* `onRemoteConfigPrepareToChange()`
* `onRemoteConfigChange(result: GDDTDRemoteConfigChangeResult.ChangeResult, error: String)`
  {% endtab %}
  {% endtabs %}

## **Step 4**

Methods implementation for working with A/B tests. When suitable conditions for the test occur, the following chain of events gets initiated:

* Calling `onReceived` method
* Calling  `onPrepareToChange` method
* Calling  `onChanged` method

### **OnReceived**

The `onReceived`  method is triggered every time when the SDK loads A/B test configuration. The `result` argument returns the following:

* ***Success*** if the configuration was loaded in the time provided. Time is set by the user in `DTDRemoteConfig.remoteConfigWaiting.`
* ***Failure*** if the config wasn’t received during the provided time defined by the user in `DTDRemoteConfig.remoteConfigWaiting`.
* **Empty** if the configuration was loaded in the time provided, but the list of experiments is empty. Time is set by the user in `DTDRemoteConfig.remoteConfigWaiting`.&#x20;

{% hint style="warning" %}
If the `DTDRemoteConfig.remoteConfigWaiting`’s default value is equal to null, the `OnReceived` method and `DTDRemoteConfigReceiveResult.Success` are called when the config is received. The time of the OnReceived call depends on the network speed.
{% endhint %}

### OnPrepareToChange

The `onPrepareToChange()` method is designed to notify the developer that the configuration of the A/B tests will be changed (the test is found or canceled, switch to a user who is not participating in the experiment, etc. (see Some features in the behavior of interfaces)).

{% hint style="info" %}
SDK asynchronous behavior causes a gap in time between the moment the suitable conditions for the test occur and its possible activation. You need to keep this in mind when changing the app’s UI and UX and pause the user’s interaction with the app until it comes into action:
{% endhint %}

* `onChanged` (see `onChanged` description) and a decision on test participation with a new config is made (see `applyConfig` description).
* A timer on the developer’s side. The timer defines the time allocated for new config waiting. After the time has run out, waiting for the config should be canceled.

See the implementation example (Scenario 1)

After calling onPrepareToChange, the SDK executes an asynchronous request for entering the test. That will result in calling onChanged.

{% hint style="info" %}
In case of disruption of the Internet connection or loss of focus, the test will be considered canceled until the next app launch.
{% endhint %}

### onChanged

The `onChanged` method is triggered in one of the following cases:

* The DevToDev server offers to enroll in a test. \
  &#x20;`onChanged()` with `DTDRemoteConfigChangeResult.success` is called
* The DevToDev server refuses to execute the test.\
  `onChanged()` with `DTDRemoteConfigChangeResult.failure` is called
* The device has no internet connection.\
  `onChanged()` with `DTDRemoteConfigChangeResult.failure` is called
* If the offer is received after the 30 second waiting time has expired\
  `onChanged()` with `DTDRemoteConfigChangeResult.failure` is called
* The test was previously activated (during the initialization)\
  `onChanged()` with `DTDRemoteConfigChangeResult.success` is called

If the `onChanged` method is triggered with `status == DTDRemoteConfigChangeResult.success` value, the possible options are:

* Accept the configuration by calling the `DTDRemoteConfig.applyConfig()` method\
  If the configuration is accepted, the default parameters and group parameters (issued by the server) will overlap. After that, the parameters of the new configuration will be available in `DTDRemoteConfig.config` (you can use them to change the behavior or the interface of the app).
* Refuse enrollment in the test `DTDRemoteConfig.resetConfig()`\
  If the test enrollment is refused or the time for decision making is up, the SDK will temporarily flag the test and it will become unavailable until the next initialization. After the next initialization, the test will be available for participation when its requirements are fulfilled.

In the cases where `status` == `DTDRemoteConfigChangeResult.failure`, the `DTDRemoteConfig.applyConfig()` method will be triggered and the default configuration will stay in place.

## Examples of SDK integration intended for working with A/B tests

{% tabs fullWidth="true" %}
{% tab title="iOS+macOS (Swift)" %}
Set the default values `DTDRemoteConfig.defaults` = `["button_color": "green", "button_size": "8"]`

Variable names have to be the same as in the ‘Group settings’ section of the web interface (see ‘web’ above). When the SDK gets included in the A/B test, the devtodev server automatically assigns it to a group.

{% hint style="warning" %}
SDK will not use new variable values that are not set in DTDRemoteConfig.defaults
{% endhint %}

Example of the `DTDRemoteConfig.config`value variants:

<table><thead><tr><th width="172">Key/Value</th><th width="150">defaults</th><th width="150"> Control Group</th><th width="150"> Group A</th><th> Group B</th></tr></thead><tbody><tr><td>button_color</td><td>green</td><td>green</td><td>blue</td><td>gray</td></tr><tr><td>button_size</td><td>8</td><td>8</td><td>12</td><td>14</td></tr></tbody></table>

Example of SDK initialization that includes A/B testing:

```swift
import UIKit
import DTDAnalytics

@main
class AppDelegate: UIResponder, UIApplicationDelegate, DTDRemoteConfigListener {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Config timeout, optional
        DTDRemoteConfig.remoteConfigWaiting = 10.0
        // Group timeout, optional
        DTDRemoteConfig.groupDefinitionWaiting = 15.0
        // Implementation defaults params
        DTDRemoteConfig.defaults = ["button_color": "green",
                                    "button_size": "8"]
        // Initialize SDK with ab test
        DTDAnalytics.initializeWithAbTest(applicationKey: "App ID",
                                          abConfigListener: self)
        return true
    }

    // The method is called when the configuration has been received
    func onReceived(result: DTDRemoteConfigReceiveResult) {
        print("Configuration received, result \(result)")
    }

    // Called when experiment is found
    func onPrepareToChange() {
        print("Experiment found")
    }

    // Called when SDK receives config
    func onChanged(result: DTDRemoteConfigChangeResult, error: Error?) {
        print("DTDRemoteConfigChangeResult: \(result)")
        if let error = error {
            print("DTDRemoteConfigError: \(error.localizedDescription)")
        }
        DTDRemoteConfig.applyConfig()
        // Use here or notify config listeners that actualConfig is ready
        let btnColorRemoteValue = DTDRemoteConfig.config["button_color"].stringValue
        let btnSizeRemoteValue = DTDRemoteConfig.config["button_size"].stringValue
        print("button color: \(btnColorRemoteValue)")
        print("button size: \(btnSizeRemoteValue)")
    }
}
```

{% endtab %}

{% tab title="iOS+macOS (Objective-c)" %}
Set the default values `DTDRemoteConfig.defaults` = `@{"button_color": @"green", @"button_size": @"8"}`

Variable names have to be the same as in the ‘Group settings’ section of the web interface (see ‘web’ above). When the SDK gets included in the A/B test, the devtodev server automatically assigns it to a group.

{% hint style="warning" %}
SDK will not use new variable values that are not set in DTDRemoteConfig.defaults
{% endhint %}

Example of the `DTDRemoteConfig.config`value variants:

<table><thead><tr><th width="172">Key/Value</th><th width="150">defaults</th><th width="150"> Control Group</th><th width="150"> Group A</th><th> Group B</th></tr></thead><tbody><tr><td>button_color</td><td>green</td><td>green</td><td>blue</td><td>gray</td></tr><tr><td>button_size</td><td>8</td><td>8</td><td>12</td><td>14</td></tr></tbody></table>

Example of SDK initialization that includes A/B testing:

{% code fullWidth="true" %}

```objectivec
#import "AppDelegate.h"
#import "DTDAnalytics/DTDAnalytics-Swift.h"

@interface AppDelegate () <DTDRemoteConfigListener>

@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Config timeout, optional
    DTDRemoteConfig.remoteConfigWaiting = 10.0;
    // Group timeout, optional
    DTDRemoteConfig.groupDefinitionWaiting = 15.0;
    // Implementation defaults params
    DTDRemoteConfig.defaults = @{@"button_color": @"green",
                                 @"button_size": @"8"};
    [DTDAnalytics applicationKey:@"App ID" abConfigListener:self];
    return YES;
}

// The method is called when the configuration has been received
- (void)onReceivedResult:(enum DTDRemoteConfigReceiveResult)result {
    NSLog(@"Configuration received, result %ld", (long)result);
}

// Called when experiment is found
- (void)onPrepareToChange {
    NSLog(@"Experiment found");
}

- (void)onChangedResult:(enum DTDRemoteConfigChangeResult)result error:(NSError *)error {
    NSLog(@"DTDRemoteConfigChangeResult: %ld", (long)result);
    if (error) {
        NSLog(@"DTDRemoteConfigError: %@", error.localizedDescription);
    }
    [DTDRemoteConfig applyConfig];
    // Use here or notify config listeners that actualConfig is ready
    NSString *btnColorRemoteValue = DTDRemoteConfig.config[@"button_color"].stringValue;
    NSString *btnSizeRemoteValue = DTDRemoteConfig.config[@"button_size"].stringValue;
    NSLog(@"button color: %@", btnColorRemoteValue);
    NSLog(@"button size: %@", btnSizeRemoteValue);
}
@end
```

{% endcode %}
{% endtab %}

{% tab title="Android (Kotlin)" %}
Set the default values `DTDRemoteConfig.defaults` = `mapOf("button_color" to "green", "button_size" to "8")`

Variable names have to be the same as in the ‘Group settings’ section of the web interface (see ‘web’ above). When the SDK gets included in the A/B test, the devtodev server automatically assigns it to a group.

{% hint style="warning" %}
SDK will not use new variable values that are not set in DTDRemoteConfig.defaults
{% endhint %}

Example of the `DTDRemoteConfig.config`value variants:

<table><thead><tr><th width="172">Key/Value</th><th width="150">defaults</th><th width="150"> Control Group</th><th width="150"> Group A</th><th> Group B</th></tr></thead><tbody><tr><td>button_color</td><td>green</td><td>green</td><td>blue</td><td>gray</td></tr><tr><td>button_size</td><td>8</td><td>8</td><td>12</td><td>14</td></tr></tbody></table>

Example of SDK initialization that includes A/B testing:

<pre class="language-kotlin"><code class="lang-kotlin">class MainActivity : AppCompatActivity(), DTDRemoteConfigListener {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        // Config timeout, optional
        DTDRemoteConfig.remoteConfigWaiting = 10.0
        // Group timeout, optional
        DTDRemoteConfig.groupDefinitionWaiting = 15.0
        // Implementation defaults params
        DTDRemoteConfig.defaults = mapOf("button_color" to "green", "button_size" to "8")
        // Initialize SDK with ab test
        DTDAnalytics.initializeWithAbTest(appKey = "App ID", context = this, abConfigListener = this)
    } 
    
    /**
     * The method is called when the configuration has been received
     */
    override fun onReceived(result: DTDRemoteConfigReceiveResult) {
       Log.d("D2D", "Configuration received") 
    }
    
    /**
     * Called when experiment is found
     */
    override fun onPrepareToChange() {
       Log.d("D2D", "Experiment found") 
    }

    /**
     * called when SDK receives config
     */
<strong>    override fun onChanged(result: DTDRemoteConfigChangeResult, ex: Exception?) {
</strong>        Log.d("D2D", "DTDRemoteConfigChangeResult: ${result.name}")
        ex?.let {
            Log.d("D2D", "DTDRemoteConfigErr: ${ex.message}")
        }
        DTDRemoteConfig.applyConfig()
        // Use here or notify config listeners that actualConfig is ready
        val btnColorRemoteValue = DTDRemoteConfig.config["button_color"].stringValue
<strong>        val btnSizeRemoteValue = DTDRemoteConfig.config["button_size"].stringValue
</strong><strong>        Log.d("D2D", "button color: $btnColorRemoteValue")
</strong><strong>        Log.d("D2D", "button size: $btnSizeRemoteValue")
</strong><strong>    }
</strong>}
</code></pre>

{% endtab %}

{% tab title="Android (Java)" %}
Set the default values:

```java
HashMap<String, Object> map = new HashMap<>();
map.put("button_color", "green");
map.put("button_size", "8");
DTDRemoteConfig.INSTANCE.setDefaults(map);
```

Variable names have to be the same as in the ‘Group settings’ section of the web interface (see ‘web’ above). When the SDK gets included in the A/B test, the devtodev server automatically assigns it to a group.

{% hint style="warning" %}
SDK will not use new variable values that are not set in DTDRemoteConfig.defaults
{% endhint %}

Example of the `DTDRemoteConfig.config`value variants:

<table><thead><tr><th width="172">Key/Value</th><th width="150">defaults</th><th width="150"> Control Group</th><th width="150"> Group A</th><th> Group B</th></tr></thead><tbody><tr><td>button_color</td><td>green</td><td>green</td><td>blue</td><td>gray</td></tr><tr><td>button_size</td><td>8</td><td>8</td><td>12</td><td>14</td></tr></tbody></table>

Example of SDK initialization that includes A/B testing:

{% code fullWidth="true" %}

```java
public class MainActivityJava extends AppCompatActivity implements DTDRemoteConfigListener {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Config timeout, optional
        DTDRemoteConfig.INSTANCE.setRemoteConfigWaiting(10.0);
        // Group timeout, optional
        DTDRemoteConfig.INSTANCE.setGroupDefinitionWaiting(15.0);
        // Implementation defaults params
        HashMap<String, Object> map = new HashMap<>();
        map.put("button_color", "green");
        map.put("button_size", "8");
        // Initialize SDK with ab test
        DTDRemoteConfig.INSTANCE.setDefaults(map);
    }

    @Override
    public void onReceived(@NonNull DTDRemoteConfigReceiveResult result) {
        Log.d("D2D", "Configuration received");
    }

    @Override
    public void onPrepareToChange() {
        Log.d("D2D", "Experiment found");
    }

    @Override
    public void onChanged(@NonNull DTDRemoteConfigChangeResult result, @Nullable Exception ex) {
        Log.d("D2D", "DTDRemoteConfigChangeResult: " + result.name());
        if (ex != null) {
            Log.d("D2D", "DTDRemoteConfigErr: " + ex);
        }

        DTDRemoteConfig.INSTANCE.applyConfig();
        // Use here or notify config listeners that actualConfig is ready
        String btnColorRemoteValue = DTDRemoteConfig.INSTANCE.getConfig().get("button_color").getStringValue();
        String btnSizeRemoteValue = DTDRemoteConfig.INSTANCE.getConfig().get("button_size").getStringValue();
        Log.d("D2D", "button color: " + btnColorRemoteValue);
        Log.d("D2D", "button size: " + btnSizeRemoteValue);
    }
}
```

{% endcode %}
{% endtab %}

{% tab title="Unity" %}
Set the default values:

```csharp
DTDRemoteConfig.Defaults = new Dictionary<string, object>
{
   {"button_color", "green"},
   {"button_size", 8}
};
```

Variable names have to be the same as in the ‘Group settings’ section of the web interface (see ‘web’ above). When the SDK gets included in the A/B test, the devtodev server automatically assigns it to a group.

{% hint style="warning" %}
SDK will not use new variable values that are not set in DTDRemoteConfig.Defaults
{% endhint %}

Example of the `DTDRemoteConfig.Config` value variants:

<table><thead><tr><th width="172">Key/Value</th><th width="150">defaults</th><th width="150"> Control Group</th><th width="150"> Group A</th><th> Group B</th></tr></thead><tbody><tr><td>button_color</td><td>green</td><td>green</td><td>blue</td><td>gray</td></tr><tr><td>button_size</td><td>8</td><td>8</td><td>12</td><td>14</td></tr></tbody></table>

Example of SDK initialization that includes A/B testing:

```csharp
using System.Collections.Generic;
using DevToDev.Analytics;
using DevToDev.Analytics.ABTest;
using UnityEngine;

namespace AbTesting
{
    public class Example : MonoBehaviour, IDTDRemoteConfigListener
    {
        private void Start()
        {
            DontDestroyOnLoad(this);
            // Config timeout, optional
            DTDRemoteConfig.RemoteConfigWaiting = 10.0;
            // Group timeout, optional
            DTDRemoteConfig.GroupDefinitionWaiting = 15.0;
            // Implementation defaults params
            DTDRemoteConfig.Defaults = new Dictionary<string, object>
            {
                {"button_color", "green"},
                {"button_size", 8}
            };

            // Initialize SDK with ab test
            DTDAnalytics.InitializeWithAbTests("App ID", this);
        }

        // The method is called when the configuration has been received
        public void OnReceived(DTDRemoteConfigReceiveResult result)
        {
            Debug.Log($"Configuration received, result {result}");
        }
        
        // Called when experiment is found
        public void OnPrepareToChange()
        {
            Debug.Log("Experiment found");
        }

        // Called when SDK receives config
        public void OnChanged(DTDRemoteConfigChangeResult result, string exceptionText = null)
        {
            Debug.Log($"DTDRemoteConfigChangeResult: {result}");
            if (exceptionText != null)
            {
                Debug.Log($"DTDRemoteConfigError: {exceptionText}");
            }

            // Use here or notify config listeners that actualConfig is ready
            DTDRemoteConfig.ApplyConfig();
            var buttonColorRemoteValue = DTDRemoteConfig.Config["button_color"].StringValue();
            var buttonSizeRemoteValue = DTDRemoteConfig.Config["button_size"].IntValue();
            Debug.Log($"button color: {buttonColorRemoteValue}");
            Debug.Log($"button size: {buttonSizeRemoteValue}");
        }
    }
}

```

{% endtab %}

{% tab title=".NET + UWP" %}
Set the default values:

```csharp
DTDRemoteConfig.Defaults = new Dictionary<string, object> 
{
  ["button_color"] = "green",
  ["button_size"] = 8
};
```

Variable names have to be the same as in the ‘Group settings’ section of the web interface (see ‘web’ above). When the SDK gets included in the A/B test, the devtodev server automatically assigns it to a group.

{% hint style="warning" %}
SDK will not use new variable values that are not set in DTDRemoteConfig.Defaults
{% endhint %}

Example of the `DTDRemoteConfig.Config` value variants:

<table><thead><tr><th width="172">Key/Value</th><th width="150">defaults</th><th width="150"> Control Group</th><th width="150"> Group A</th><th> Group B</th></tr></thead><tbody><tr><td>button_color</td><td>green</td><td>green</td><td>blue</td><td>gray</td></tr><tr><td>button_size</td><td>8</td><td>8</td><td>12</td><td>14</td></tr></tbody></table>

Example of SDK initialization that includes A/B testing:

```csharp
using DevToDev.Analytics;
using System.Collections.Generic;
using System.Diagnostics;

class MyRemoteConfigListener : IDTDRemoteConfigListener
{
    /**
     * The method is called when the configuration has been received
     */
    public void OnReceived(DTDRemoteConfigReceiveResult result)
    {
      Debug.WriteLine("Configuration has been received!");
    }
    
    /**
     * Called when experiment is found
     */
    public void OnPrepareToChange()
    {
      Debug.WriteLine("Experiment was found!");
    }
    
    /**
     * Called when SDK receives config
     */
    public void OnChanged(DTDRemoteConfigChangeResult result, string error)
    {
      Debug.WriteLine($"Result: {result}");
      if (result == DTDRemoteConfigChangeResult.Failure)
      {
        Debug.WriteLine($"Error: {error}");
      }
      
      DTDRemoteConfig.ApplyConfig();
      DTDRemoteConfig.ApplyConfig();
      var buttonColorRemoteValue = DTDRemoteConfig.Config["button_color"].StringValue;
      var buttonSizeRemoteValue = DTDRemoteConfig.Config["button_size"].IntValue;
      Debug.WriteLine($"button color: {buttonColorRemoteValue}");
      Debug.WriteLine($"button size: {buttonSizeRemoteValue}");
      // Use here or notify config listeners that config is ready
    }
}
  
public static class Program
{
    public static void Main(string[] args)
    {
        // Config timeout, optional
        DTDRemoteConfig.RemoteConfigWaiting = 10;
        
        // Group timeout, optional
        DTDRemoteConfig.GroupDefinitionWaiting = 15;
        
        // Implementation defaults params
        DTDRemoteConfig.Defaults = new Dictionary<string, object> 
        {
          ["button_color"] = "green",
          ["button_size"] = 8
        };
        
        // Create listener
        var listener = new MyRemoteConfigListener();
        
        // Initialize SDK with ab test
        DTDAnalytics.InitializeWithAbTest("App ID", listener);
    }
}
```

{% endtab %}

{% tab title="Web" %}
Set the default values `DTDRemoteConfig.SetDefaults()`

Variable names have to be the same as in the ‘Group settings’ section of the web interface (see ‘web’ above). When the SDK gets included in the A/B test, the devtodev server automatically assigns it to a group.

SDK will not use new variable values that are not set in DTDRemoteConfig.defaults

Example of the `DTDRemoteConfig` value variants:

| **Key/Value** | **defaults** | **Control Group** | **Group A** | **Group B** |
| ------------- | ------------ | ----------------- | ----------- | ----------- |
| button\_color | green        | green             | blue        | gray        |
| button\_size  | 8            | 8                 | 12          | 14          |

Example of SDK initialization that includes A/B testing:

```javascript
window.devtodev.remoteConfig.defaults = {
   button_color: 'green',
   button_size:  8
}
window.devtodev.initializeWithAbTest(
    "App ID", 
    {
        userId: userId,
        logLevel: logLevel,
        trackingAvailability: trackingAvailability,
    },
    {
        onReceived: function(result) {
            console.log('onReceived callback', result)
        },
        onPrepareToChange: function() {
            console.log('onPrepareToChange callback')
        },
        onChanged: function(result, error) {
            console.log('onChanged callback', result, error)
            window.devtodev.remoteConfig.applyConfig()
            var config = window.devtodev.remoteConfig.config // DTDRemoteConfigCollection
            var buttonSizeRemoteValue =  window.devtodev.remoteConfig.config["button_size"].intValue;
            var buttonColorRemoteValue = window.devtodev.remoteConfig.config["button_color"].stringValue;
            console.log("button color: ", buttonColorRemoteValue);
            console.log("button size: ", buttonSizeRemoteValue);
        }
    }
)
```

{% endtab %}

{% tab title="Unreal" %}
Set the default values:

<figure><img src="https://2105883905-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnGcP_ZeRJ1ipj9O8dF%2Fuploads%2FOpYwTx5U76LEEbryqd64%2F%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA%20%D1%8D%D0%BA%D1%80%D0%B0%D0%BD%D0%B0%202023-06-28%20%D0%B2%2012.51.53.png?alt=media&#x26;token=efc4c201-b419-4520-a049-aac409adb3a7" alt="" width="375"><figcaption><p>Blueprint</p></figcaption></figure>

```
// Implementation defaults params
FDTDRemoteConfigDefaults defaults;
defaults.StringDefaults.Add("button_color", "green");
defaults.IntegerDefaults.Add("button_size", 8);
```

Variable names have to be the same as in the ‘Group settings’ section of the web interface (see ‘web’ above). When the SDK gets included in the A/B test, the devtodev server automatically assigns it to a group.

{% hint style="warning" %}
SDK will not use new variable values that are not set in DTDRemoteConfig.defaults
{% endhint %}

Example of the `DTDRemoteConfig.config`value variants:

<table><thead><tr><th width="172">Key/Value</th><th width="150">defaults</th><th width="150"> Control Group</th><th width="150"> Group A</th><th> Group B</th></tr></thead><tbody><tr><td>button_color</td><td>green</td><td>green</td><td>blue</td><td>gray</td></tr><tr><td>button_size</td><td>8</td><td>8</td><td>12</td><td>14</td></tr></tbody></table>

Example of SDK initialization that includes A/B testing:

<figure><img src="https://2105883905-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnGcP_ZeRJ1ipj9O8dF%2Fuploads%2FxLmzooNkQMrEpcqkk1K3%2F%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA%20%D1%8D%D0%BA%D1%80%D0%B0%D0%BD%D0%B0%202023-06-27%20%D0%B2%2019.19.12.png?alt=media&#x26;token=5c767e5c-bf73-47ab-b498-f39adde81742" alt="" width="375"><figcaption><p>Blueprint</p></figcaption></figure>

```cpp
#include "DTDAnalytics/Public/DTDAnalyticsBPLibrary.h"
#include "DTDAnalytics/Public/DTDRemoteConfigBPLibrary.h"

UDTDAnalyticsBPLibrary::SetLogLevel(EDTDLogLevel::Debug);

// Config timeout, optional
UDTDRemoteConfigBPLibrary::SetRemoteConfigWaiting(10.0f);
// Group timeout, optional
UDTDRemoteConfigBPLibrary::SetGroupDefinitionWaiting(15.0f);

// Implementation defaults params
FDTDRemoteConfigDefaults defaults;
defaults.StringDefaults.Add("button_color", "green");
defaults.IntegerDefaults.Add("button_size", 8);

UDTDRemoteConfigBPLibrary::SetDefaults(defaults);

// The method is called when the configuration has been received
const auto onConfigReceive = new FDTDRemoteConfigReceiveResultDelegate();
onConfigReceive->BindLambda([=](EDTDRemoteConfigReceiveResult result)
{	
	UE_LOG(LogTemp, Warning, TEXT("Configuration received, result %s"), *UEnum::GetValueAsString(result));
});

// Called when experiment is found
const auto onPrepareToChange = new FDTDRemoteConfigPrepareToChangeDelegate();
onPrepareToChange->BindLambda([=]()
{
	UE_LOG(LogTemp, Warning, TEXT("Experiment found"));
});

// Called when SDK receives config
const auto onConfigChange = new FDTDRemoteConfigChangeResultDelegate();
onConfigChange->BindLambda([=](EDTDRemoteConfigChangeResult result, const FString& error)
{
	UE_LOG(LogTemp, Warning, TEXT("DTDRemoteConfigChangeResult: %s"), *UEnum::GetValueAsString(result));
	if (!error.IsEmpty()) {
		UE_LOG(LogTemp, Warning, TEXT("DTDRemoteConfigError: %s"), *error);
	}

	// Use here or notify config listeners that actualConfig is ready
	UDTDRemoteConfigBPLibrary::ApplyConfig();

	FString ButtonColorRemoteValue = UDTDRemoteConfigBPLibrary::GetRemoteConfigValue("button_color").StringValue;
        int32 buttonSizeRemoteValue = UDTDRemoteConfigBPLibrary::GetRemoteConfigValue("button_size").IntegerValue;
	UE_LOG(LogTemp, Warning, TEXT("button color: : %s"), *ButtonColorRemoteValue);
	UE_LOG(LogTemp, Warning, TEXT("button size:: %d"), buttonSizeRemoteValue);
});

// Initialize SDK with ab test
UDTDAnalyticsBPLibrary::InitializeWithAbTest("App ID", *onConfigChange, *onPrepareToChange, *onConfigReceive);
```

{% endtab %}

{% tab title="Godot" %}
Set the default values `DTDRemoteConfig.SetDefaults()`

Variable names have to be the same as in the ‘Group settings’ section of the web interface (see ‘web’ above). When the SDK gets included in the A/B test, the devtodev server automatically assigns it to a group.

{% hint style="warning" %}
SDK will not use new variable values that are not set in DTDRemoteConfig.defaults
{% endhint %}

Example of the `DTDRemoteConfig` value variants:

<table><thead><tr><th width="172">Key/Value</th><th width="150">defaults</th><th width="150"> Control Group</th><th width="150"> Group A</th><th> Group B</th></tr></thead><tbody><tr><td>button_color</td><td>green</td><td>green</td><td>blue</td><td>gray</td></tr><tr><td>button_size</td><td>8</td><td>8</td><td>12</td><td>14</td></tr></tbody></table>

Example of SDK initialization that includes A/B testing:

<pre class="language-gdscript"><code class="lang-gdscript">func _ready():
    	# Config timeout, optional
	DTDRemoteConfig.SetRemoteConfigWaiting(10)
	# Group timeout, optional
	DTDRemoteConfig.SetGroupDefinitionWaiting(10)
    	# Implementation defaults params
	var defaults = GDDTDRemoteConfigDefaults.new()
	defaults.AddStringValue("button_color", "green")
	defaults.AddIntegerValue("button_size", 8)
	DTDRemoteConfig.SetDefaults(defaults)
    	# Initialize SDK with ab test
	DTDAnalytics.SetLogLevel(GDDTDLogLevel.Debug)
	DTDAnalytics.InitializeWithConfigWithAbTest(
		"appKey",
		onRemoteConfigChange,
		onRemoteConfigPrepareToChange,
		onRemoteConfigReceive)

# The method is called when the configuration has been received
func onRemoteConfigReceive(result: GDDTDRemoteConfigReceiveResult.ReceiveResult):
	match result:
		GDDTDRemoteConfigReceiveResult.ReceiveResult.Failure:
			print("onRemoteConfigReceive result = Failure")
			
		GDDTDRemoteConfigReceiveResult.ReceiveResult.Success:
			print("onRemoteConfigReceive result = Success")
			
		GDDTDRemoteConfigReceiveResult.ReceiveResult.Empty:
			print("onRemoteConfigReceive result = Empty")
			
		_:
			print("onRemoteConfigReceive result = Unknown")
<strong>
</strong><strong># Called when experiment is found		
</strong>func onRemoteConfigPrepareToChange():
	print("Experiment found")
			
# Called when SDK receives config
func onRemoteConfigChange(result: GDDTDRemoteConfigChangeResult.ChangeResult, error: String):
	if !error.is_empty(): 
		print("error = " + error)
		
	match result:
		GDDTDRemoteConfigChangeResult.ChangeResult.Failure:
			print("onRemoteConfigChange result = Failure")	
			
		GDDTDRemoteConfigChangeResult.ChangeResult.Success:
			
			print("onRemoteConfigChange result = Success")
		_: 
			print("onRemoteConfigChange result = Unknown")
			
	DTDRemoteConfig.ApplyConfig()
	
	# Use here or notify config listeners that actualConfig is ready
	var btnColorRemoteValue = DTDRemoteConfig.GetRemoteConfigValue("button_color").GetStringValue()
	var btnSizeRemoteValue = DTDRemoteConfig.GetRemoteConfigValue("button_size").GetStringValue()
	print("button color: " + btnColorRemoteValue)
	print("button size: " + btnSizeRemoteValue)
</code></pre>

{% endtab %}
{% endtabs %}

## Some features of A/B testing

When the SDK finds a suitable test(s), it calls the `onPrepareToChange` method and reports it. Then the SDK starts a timer for 30 seconds and sends a request to the devtodev server. The server returns an experiment number and information about a group. Or the server answers that the user can not participate in the test. This process takes some time. The request and answer can take as little as milliseconds, or much longer (30 seconds maximum) if, for example, the device’s internet connection is bad. Below, you can find several use cases that may help you to solve this problem if your app’s interface is sensitive to waiting for the config from devtodev.

## **Description of external interfaces**

### **DTDRemoteConfig**

When working with this class, the SDK provides synchronization of threads that aims at providing safe operation taking into account the asynchrony of the SDK.

{% tabs fullWidth="true" %}
{% tab title="iOS+macOS (Swift)" %}

| Property                            | Description                                                                                                                                                                                                                   |
| ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `remoteConfigWaiting: Double`       | <p>Wait time for A/B test configuration. </p><p></p><p>Default value - 0.0 (measured in seconds)</p>                                                                                                                          |
| `groupDefinitionWaiting: Double`    | <p>Wait time for test group. </p><p></p><p>Default value - 10.0 (measured in seconds)</p>                                                                                                                                     |
| `defaults: [String, Any]`           | Variables and their default values                                                                                                                                                                                            |
| `config: DTDRemoteConfigCollection` | <p>Wrapper for remote parameters in the form of a collection. It allows access to the configuration values by using the subscripting syntaxis. </p><p></p><p>Actual variables and their values for working with A/B tests</p> |
| `applyConfig()`                     | It applies the A/B testing configuration. After the call, the default parameters get matched with the group parameters.                                                                                                       |
| `resetConfig()`                     | It cancels a suitable or running test                                                                                                                                                                                         |
| `cacheTestExperiment()`             | A debug method for saving a test experiment after restarting the application                                                                                                                                                  |
| {% endtab %}                        |                                                                                                                                                                                                                               |

{% tab title="iOS+macOS (Objective-C)" %}

| Property                                | Description                                                                                                                                                                                                                   |
| --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `remoteConfigWaiting: double`           | <p>Wait time for A/B test configuration. </p><p></p><p>Default value - 0.0 (measured in seconds)</p>                                                                                                                          |
| `groupDefinitionWaiting: double`        | <p>Wait time for test group. </p><p></p><p>Default value - 10.0 (measured in seconds)</p>                                                                                                                                     |
| `defaults: NSDictionary<NSString *,id>` | Variables and their default values                                                                                                                                                                                            |
| `config: DTDRemoteConfigCollection`     | <p>Wrapper for remote parameters in the form of a collection. It allows access to the configuration values by using the subscripting syntaxis. </p><p></p><p>Actual variables and their values for working with A/B tests</p> |
| `(void) applyConfig`                    | It applies the A/B testing configuration. After the call, the default parameters get matched with the group parameters.                                                                                                       |
| `(void) resetConfig`                    | It cancels a suitable or running test                                                                                                                                                                                         |
| `(void) cacheTestExperiment`            | A debug method for saving a test experiment after restarting the application                                                                                                                                                  |
| {% endtab %}                            |                                                                                                                                                                                                                               |

{% tab title="Android (Kotlin)" %}

| Property                            | Description                                                                                                                                                                                                                   |
| ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `remoteConfigWaiting: Double`       | <p>Wait time for A/B test configuration. </p><p></p><p>Default value - 0.0 (measured in seconds)</p>                                                                                                                          |
| `groupDefinitionWaiting: Double`    | <p>Wait time for test group. </p><p></p><p>Default value - 10.0 (measured in seconds)</p>                                                                                                                                     |
| `defaults: Map<String, Any>`        | Variables and their default values                                                                                                                                                                                            |
| `config: DTDRemoteConfigCollection` | <p>Wrapper for remote parameters in the form of a collection. It allows access to the configuration values by using the subscripting syntaxis. </p><p></p><p>Actual variables and their values for working with A/B tests</p> |
| `applyConfig()`                     | It applies the A/B testing configuration. After the call, the default parameters get matched with the group parameters.                                                                                                       |
| `resetConfig()`                     | It cancels a suitable or running test                                                                                                                                                                                         |
| `cacheTestExperiment()`             | A debug method for saving a test experiment after restarting the application                                                                                                                                                  |
| {% endtab %}                        |                                                                                                                                                                                                                               |

{% tab title="Android (Java)" %}

<table><thead><tr><th width="362">Property</th><th>Description</th></tr></thead><tbody><tr><td><code>setRemoteConfigWaiting</code>()</td><td><p>Wait time for A/B test configuration. </p><p></p><p>Default value - 0.0 (measured in seconds)</p></td></tr><tr><td><code>getRemoteConfigWaiting</code>()</td><td><p>Wait time for test group. </p><p></p></td></tr><tr><td><code>setGroupDefinitionWaiting</code>()</td><td><p>Wait time for test group.</p><p></p><p>Default value - 10.0 (measured in seconds)</p></td></tr><tr><td><code>getGroupDefinitionWaiting</code>()</td><td>Get time for test group.</td></tr><tr><td><code>setDefaults(Map&#x3C;String, ? extends Object></code>)</td><td>Set map of variables and their default values</td></tr><tr><td><code>Map&#x3C;String,Object> getDefaults()</code></td><td>Get map of variables and their default values</td></tr><tr><td><code>DTDRemoteConfigCollection getConfig()</code></td><td><p>Wrapper for remote parameters in the form of a collection. It allows access to the configuration values by using the subscripting syntaxis.</p><p></p><p>Actual variables and their values for working with A/B tests</p></td></tr><tr><td><code>applyConfig()</code></td><td>It applies the A/B testing configuration. After the call, the default parameters get matched with the group parameters.</td></tr><tr><td><code>resetConfig()</code></td><td>It cancels a suitable or running test</td></tr><tr><td><code>cacheTestExperiment()</code></td><td>A debug method for saving a test experiment after restarting the application</td></tr></tbody></table>
{% endtab %}

{% tab title="Unity" %}

| Property                                                        | Description                                                                                                                                                                                                                   |
| --------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `double RemoteConfigWaiting {get;set;}`                         | <p>Wait time for A/B test configuration. </p><p></p><p>Default value - 0.0 (measured in seconds)</p>                                                                                                                          |
| `double GroupDefinitionWaiting {get;set}`                       | <p>Wait time for test group. </p><p></p><p>Default value - 10.0 (measured in seconds)</p>                                                                                                                                     |
| `Dictionary<string, object> DTDRemoteConfig.Defaults {get;set}` | Variables and their default values                                                                                                                                                                                            |
| `DTDRemoteConfigCollection DTDRemoteConfig.Config`              | <p>Wrapper for remote parameters in the form of a collection. It allows access to the configuration values by using the subscripting syntaxis. </p><p></p><p>Actual variables and their values for working with A/B tests</p> |
| `void ApplyConfig()`                                            | It applies the A/B testing configuration. After the call, the default parameters get matched with the group parameters.                                                                                                       |
| `void ResetConfig()`                                            | It cancels a suitable or running test                                                                                                                                                                                         |
| `void CacheTestExperiment()`                                    | A debug method for saving a test experiment after restarting the application                                                                                                                                                  |
| {% endtab %}                                                    |                                                                                                                                                                                                                               |

{% tab title=".Net + UWP" %}

| Property                                | Description                                                                                                                                                                                                                   |
| --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `RemoteConfigWaiting: double`           | <p>Wait time for A/B test configuration. </p><p></p><p>Default value - 0.0 (measured in seconds)</p>                                                                                                                          |
| `GroupDefinitionWaiting: double`        | <p>Wait time for test group. </p><p></p><p>Default value - 10.0 (measured in seconds)</p>                                                                                                                                     |
| `Defaults: IDictionary<String, object>` | Variables and their default values                                                                                                                                                                                            |
| Config: DTDRemoteConfigCollection       | <p>Wrapper for remote parameters in the form of a collection. It allows access to the configuration values by using the subscripting syntaxis. </p><p></p><p>Actual variables and their values for working with A/B tests</p> |
| `ApplyConfig()`                         | It applies the A/B testing configuration. After the call, the default parameters get matched with the group parameters.                                                                                                       |
| `ResetConfig()`                         | It cancels a suitable or running test                                                                                                                                                                                         |
| `CacheTestExperiment()`                 | A debug method for saving a test experiment after restarting the application                                                                                                                                                  |
| {% endtab %}                            |                                                                                                                                                                                                                               |

{% tab title="Web" %}

<table><thead><tr><th width="233.17578125">Property</th><th>Description</th></tr></thead><tbody><tr><td><code>remoteConfigWaiting</code></td><td><p>Wait time for A/B test configuration.</p><p>Default value - 0 (measured in seconds)</p></td></tr><tr><td><code>groupDefinitionWaiting</code></td><td><p>Wait time for test group.</p><p>Default value - 15 (measured in seconds)</p></td></tr><tr><td><code>defaults</code></td><td>Variables and their default values</td></tr><tr><td><code>config</code></td><td><p>Wrapper for remote parameters in the form of a collection. It allows access to the configuration values by using the subscripting syntaxis.</p><p>Actual variables and their values for working with A/B tests</p></td></tr><tr><td><code>applyConfig()</code></td><td>It applies the A/B testing configuration. After the call, the default parameters get matched with the group parameters.</td></tr><tr><td><code>resetConfig()</code></td><td>It cancels a suitable or running test</td></tr><tr><td><code>cacheTestExperiment()</code></td><td>A debug method for saving a test experiment after restarting the application</td></tr></tbody></table>
{% endtab %}

{% tab title="Unreal" %}

<table><thead><tr><th width="362">Property</th><th>Description</th></tr></thead><tbody><tr><td><code>SetRemoteConfigWaiting(float value)</code></td><td><p>Wait time for A/B test configuration. </p><p></p><p>Default value - 0.0 (measured in seconds)</p></td></tr><tr><td><code>float GetRemoteConfigWaiting()</code></td><td><p>Wait time for test group. </p><p></p></td></tr><tr><td><code>SetGroupDefinitionWaiting(float value)</code></td><td><p>Wait time for test group.</p><p></p><p>Default value - 10.0 (measured in seconds)</p></td></tr><tr><td><code>GetGroupDefinitionWaiting()</code></td><td>Get time for test group.</td></tr><tr><td><code>SetDefaults(const FDTDRemoteConfigDefaults&#x26; defaults)</code></td><td>Set USTRUCT with variables and their default values</td></tr><tr><td><code>TMap&#x3C;FString, FDTDRemoteConfigValue> GetConfig()</code></td><td>Actual variables and their values for working with A/B tests</td></tr><tr><td><code>FDTDRemoteConfigValue GetRemoteConfigValue(const FString&#x26; key)</code></td><td>Return actual value for variable key</td></tr><tr><td><code>bool HasKey(const FString&#x26; key)</code></td><td>Verify if there are any values associated with the variable key in the remote configuration.</td></tr><tr><td><code>ApplyConfig()</code></td><td>It applies the A/B testing configuration. After the call, the default parameters get matched with the group parameters.</td></tr><tr><td><code>ResetConfig()</code></td><td>It cancels a suitable or running test</td></tr><tr><td><code>CacheTestExperiment()</code></td><td>A debug method for saving a test experiment after restarting the application</td></tr></tbody></table>
{% endtab %}

{% tab title="Godot" %}

<table><thead><tr><th width="368">Property</th><th>Description</th></tr></thead><tbody><tr><td><code>void SetRemoteConfigWaiting(int value)</code></td><td><p>Wait time for A/B test configuration. </p><p></p><p>Default value - 0 (measured in seconds)</p></td></tr><tr><td><code>int GetRemoteConfigWaiting()</code></td><td><p>Wait time for test group. </p><p></p></td></tr><tr><td><code>void SetGroupDefinitionWaiting(int value)</code></td><td><p>Wait time for test group.</p><p></p><p>Default value - 10 (measured in seconds)</p></td></tr><tr><td><code>int GetGroupDefinitionWaiting()</code></td><td>Get time for test group.</td></tr><tr><td><code>void SetDefaults(defaults: GDDTDRemoteConfigDefaults)</code></td><td>Set <code>GDDTDRemoteConfigDefaults</code> with variables and their default values</td></tr><tr><td><code>GDDTDRemoteConfigValue GetRemoteConfigValue(key: String)</code></td><td>Return actual value for variable key</td></tr><tr><td><code>bool HasKey(key: String)</code></td><td>Verify if there are any values associated with the variable key in the remote configuration.</td></tr><tr><td><code>void ApplyConfig()</code></td><td>It applies the A/B testing configuration. After the call, the default parameters get matched with the group parameters.</td></tr><tr><td><code>void ResetConfig()</code></td><td>It cancels a suitable or running test</td></tr><tr><td><code>void CacheTestExperiment()</code></td><td>A debug method for saving a test experiment after restarting the application</td></tr></tbody></table>
{% endtab %}
{% endtabs %}

### DTDRemoteConfigCollection

Wrapper for remote parameters collection. Enables access to configuration values by using subscripting syntax.

{% tabs %}
{% tab title="Web" %}

<table><thead><tr><th width="183.40234375">Method</th><th></th></tr></thead><tbody><tr><td><code>hasKey(key)</code></td><td>Return true if current configuration has value for a key.</td></tr><tr><td><code>values</code></td><td>Returns the plain object of the current configuration with key/values pairs</td></tr></tbody></table>
{% endtab %}

{% tab title="All other SDKs" %}

| Method                |                                                           |
| --------------------- | --------------------------------------------------------- |
| `hasKey(key: String)` | Return true if current configuration has value for a key. |
| {% endtab %}          |                                                           |
| {% endtabs %}         |                                                           |

### DTDRemoteConfigValue

Wrapper for working with remote configuration variables. It represents a method for data source identification, as well as methods for presenting values in the form of various data types.

| type                            | Description                                            |
| ------------------------------- | ------------------------------------------------------ |
| `DTDRemoteConfigSource.Default` | The variable is set by default.                        |
| `DTDRemoteConfigSource.Remote`  | The variable is set by the test group.                 |
| `DTDRemoteConfigSource.Empty`   | The variable is not found in the remote configuration. |

{% tabs fullWidth="true" %}
{% tab title="iOS+macOS (Swift)" %}

| Property       | type    | Description                           |
| -------------- | ------- | ------------------------------------- |
| `stringValue`  | String? | Gets the value as an optional string. |
| `floatValue`   | Float   | Gets the value as a Float.            |
| `doubleValue`  | Double  | Gets the value as a Double.           |
| `Int32Value`   | Int32   | Gets the value as an Int32.           |
| `Int64Value`   | Int64   | Gets the value as an Int64.           |
| `integerValue` | Int     | Gets the value as an Int.             |
| `boolValue`    | Bool    | Gets the value as a Bool.             |
| {% endtab %}   |         |                                       |

{% tab title="iOS+macOS (Objective-C)" %}

| Property       | type      | Description                           |
| -------------- | --------- | ------------------------------------- |
| `stringValue`  | NSString  | Gets the value as an optional string. |
| `floatValue`   | float     | Gets the value as a Float.            |
| `doubleValue`  | double    | Gets the value as a Double.           |
| `Int32Value`   | long      | Gets the value as an long.            |
| `Int64Value`   | long long | Gets the value as an long long.       |
| `integerValue` | NSInteger | Gets the value as an NSInteger.       |
| `boolValue`    | BOOL      | Gets the value as a Bool.             |
| {% endtab %}   |           |                                       |

{% tab title="Android (Kotlin)" %}

| Property       | type    | Description                           |
| -------------- | ------- | ------------------------------------- |
| `stringValue`  | String? | Gets the value as an optional string. |
| `floatValue`   | Float   | Gets the value as a Float.            |
| `doubleValue`  | Double  | Gets the value as a Double.           |
| `intValue`     | Int     | Gets the value as an int.             |
| `longValue`    | Long    | Gets the value as an long.            |
| `booleanValue` | Boolean | Gets the value as a Bool.             |
| {% endtab %}   |         |                                       |

{% tab title="Android (Java)" %}

| Property          | type    | Description                           |
| ----------------- | ------- | ------------------------------------- |
| `getStringValue`  | String  | Gets the value as an optional string. |
| `getFloatValue`   | float   | Gets the value as a Float.            |
| `getDoubleValue`  | double  | Gets the value as a Double.           |
| `getIntValue`     | int     | Gets the value as an Int.             |
| `getLongValue`    | long    | Gets the value as an Long.            |
| `getBooleanValue` | Boolean | Gets the value as a Boolean.          |
| {% endtab %}      |         |                                       |

{% tab title="Unity" %}

| Property      | type   | Description                           |
| ------------- | ------ | ------------------------------------- |
| `StringValue` | string | Gets the value as an optional string. |
| `FloatValue`  | float  | Gets the value as a float.            |
| `DoubleValue` | double | Gets the value as a double.           |
| `LongValue`   | long   | Gets the value as an long.            |
| `IntValue`    | int    | Gets the value as an int.             |
| `BoolValue`   | bool   | Gets the value as a bool.             |
| {% endtab %}  |        |                                       |

{% tab title=".Net + UWP" %}

| Property      | type   | Description                           |
| ------------- | ------ | ------------------------------------- |
| `StringValue` | String | Gets the value as an optional string. |
| `FloatValue`  | float  | Gets the value as a float.            |
| `DoubleValue` | double | Gets the value as a double.           |
| `Int16Value`  | Int16  | Gets the value as an Int16            |
| `Int32Value`  | Int32  | Gets the value as an Int32            |
| `Int64Value`  | Int64  | Gets the value as an Int64            |
| `BoolValue`   | bool   | Gets the value as a bool.             |
| {% endtab %}  |        |                                       |

{% tab title="Web" %}

| Property      | Type    | Description                                                                                           |
| ------------- | ------- | ----------------------------------------------------------------------------------------------------- |
| `StringValue` | String  | Gets the value as an optional string.                                                                 |
| `FloatValue`  | Number  | Gets the value as a float number                                                                      |
| `DoubleValue` | Number  | Gets the value as a double number                                                                     |
| `LongValue`   | String  | <p>Gets the value as a long</p><p>NB: <code>can be simulated only via string in JavaScript</code></p> |
| `IntValue`    | Number  | Gets the value as a number                                                                            |
| `BoolValue`   | Boolean | Gets the value as a boolean                                                                           |
| {% endtab %}  |         |                                                                                                       |

{% tab title="Unreal" %}

<table><thead><tr><th width="197.66666666666666">Property</th><th>type</th><th>Description</th></tr></thead><tbody><tr><td><code>StringValue</code></td><td>FString</td><td>Gets the value as an string.</td></tr><tr><td><code>FloatValue</code></td><td>float</td><td>Gets the value as a float.</td></tr><tr><td><code>LongValue</code></td><td>int64</td><td>Gets the value as an long.</td></tr><tr><td><code>IntValue</code></td><td>int32</td><td>Gets the value as an int.</td></tr><tr><td><code>BoolValue</code></td><td>bool</td><td>Gets the value as a bool.</td></tr><tr><td><code>Source</code></td><td>EDTDRemoteConfigSource</td><td>Gets source of the value.</td></tr></tbody></table>
{% endtab %}

{% tab title="Godot" %}

<table><thead><tr><th width="197.66666666666666">Property</th><th>type</th><th>Description</th></tr></thead><tbody><tr><td><code>GetStringValue</code></td><td>String</td><td>Gets the value as an string.</td></tr><tr><td><code>GetFloatValue</code></td><td>float</td><td>Gets the value as a float.</td></tr><tr><td><code>GetIntValue</code></td><td>int</td><td>Gets the value as an int.</td></tr><tr><td><code>GetBoolValue</code></td><td>bool</td><td>Gets the value as a bool.</td></tr><tr><td><code>GetSource</code></td><td>GDDTDRemoteConfigSource.Source</td><td>Gets source of the value.</td></tr></tbody></table>
{% endtab %}
{% endtabs %}

### DTDRemoteConfigListener

{% hint style="warning" %}
Not applied to Web SDK
{% endhint %}

It implements methods that report the status of A/B tests.

{% tabs fullWidth="true" %}
{% tab title="iOS+macOS (Swift)" %}

<table><thead><tr><th width="338.4332022087659">Method</th><th>Description</th></tr></thead><tbody><tr><td><code>onReceived(result: DTDRemoteConfigReceiveResult)</code></td><td>It is triggered every time the SDK loads an A/B test configuration. If the remoteConfigWaiting has a default value (null), <code>onReceived</code> does not get called</td></tr><tr><td><code>onPrepareToChange()</code></td><td>It notifies the developer about coming changes in the A/B test configuration.</td></tr><tr><td><p><code>onChanged(result: DTDRemoteConfigChangeResult,</code> </p><p><code>error: Error?)</code></p></td><td>It notifies the developer that the configuration has changed. Or about the reason why the configuration could not change.</td></tr></tbody></table>
{% endtab %}

{% tab title="iOS+macOS (Objective-C)" %}

<table><thead><tr><th width="417.3913043478261">Method</th><th>Description</th></tr></thead><tbody><tr><td><p><code>-(void)onReceivedResult:</code></p><p><code>(enum DTDRemoteConfigReceiveResult)result</code></p></td><td>It is triggered every time the SDK loads an A/B test configuration. If the remoteConfigWaiting has a default value (null), <code>onReceived</code> does not get called</td></tr><tr><td><code>-(void)onPrepareToChange</code></td><td>It notifies the developer about coming changes in the A/B test configuration.</td></tr><tr><td><p><code>- (void)onChangedResult:</code></p><p><code>(enum DTDRemoteConfigChangeResult)result</code></p><p><code>error:(NSError *)error</code></p></td><td>It notifies the developer that the configuration has changed. Or about the reason why the configuration could not change.</td></tr></tbody></table>
{% endtab %}

{% tab title="Android (Kotlin)" %}

| Method                                                           | Description                                                                                                                                                 |
| ---------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `onReceived(result: DTDRemoteConfigReceiveResult)`               | It is triggered every time the SDK loads an A/B test configuration. If the remoteConfigWaiting has a default value (null), `onReceived` does not get called |
| `onPrepareToChange()`                                            | It notifies the developer about coming changes in the A/B test configuration.                                                                               |
| `onChanged(result: DTDRemoteConfigChangeResult, ex: Exception?)` | It notifies the developer that the configuration has changed. Or about the reason why the configuration could not change.                                   |
| {% endtab %}                                                     |                                                                                                                                                             |

{% tab title="Android (Java)" %}

<table><thead><tr><th width="355">Method</th><th>Description</th></tr></thead><tbody><tr><td><code>onReceived(DTDRemoteConfigReceiveResult result)</code></td><td>It is triggered every time the SDK loads an A/B test configuration. If the remoteConfigWaiting has a default value (null), <code>onReceived</code> does not get called</td></tr><tr><td><code>onPrepareToChange()</code></td><td>It notifies the developer about coming changes in the A/B test configuration.</td></tr><tr><td><code>onChanged( DTDRemoteConfigChangeResult result, Exception ex)</code></td><td>It notifies the developer that the configuration has changed. Or about the reason why the configuration could not change.</td></tr></tbody></table>
{% endtab %}

{% tab title="Unity" %}
**IDTDRemoteConfigListener**

<table><thead><tr><th width="338.4332022087659">Method</th><th>Description</th></tr></thead><tbody><tr><td><code>void OnReceived(DTDRemoteConfigReceiveResult result)</code>;</td><td>It is triggered every time the SDK loads an A/B test configuration. If the remoteConfigWaiting has a default value (null), <code>OnReceived</code> does not get called</td></tr><tr><td><code>void OnPrepareToChange();</code></td><td>It notifies the developer about coming changes in the A/B test configuration.</td></tr><tr><td><code>void OnChanged(DTDRemoteConfigChangeResult result, string exceptionText = null)</code>;</td><td>It notifies the developer that the configuration has changed. Or about the reason why the configuration could not change.</td></tr></tbody></table>
{% endtab %}

{% tab title=".Net + UWP" %}
**IDTDRemoteConfigListener**

<table><thead><tr><th width="338.4332022087659">Method</th><th>Description</th></tr></thead><tbody><tr><td><code>OnReceived(DTDRemoteConfigReceiveResult result)</code></td><td>It is triggered every time the SDK loads an A/B test configuration. If the remoteConfigWaiting has a default value (null), <code>OnReceived</code> does not get called</td></tr><tr><td><code>OnPrepareToChange()</code></td><td>It notifies the developer about coming changes in the A/B test configuration.</td></tr><tr><td><code>OnChanged(DTDRemoteConfigChangeResult result, string error)</code></td><td>It notifies the developer that the configuration has changed. Or about the reason why the configuration could not change.</td></tr></tbody></table>
{% endtab %}

{% tab title="Unreal" %}
**FDTDRemoteConfigReceiveResultDelegate**

It is triggered every time the SDK loads an A/B test configuration. If the remoteConfigWaiting has a default value (null), `OnReceived` does not get called

<figure><img src="https://2105883905-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnGcP_ZeRJ1ipj9O8dF%2Fuploads%2FvscptZ6qgsofbMydNXm5%2F%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA%20%D1%8D%D0%BA%D1%80%D0%B0%D0%BD%D0%B0%202023-06-28%20%D0%B2%2013.22.30.png?alt=media&#x26;token=3bac170f-4c8d-450a-92b1-371524beceab" alt="" width="375"><figcaption><p>Blueprint</p></figcaption></figure>

```
DECLARE_DELEGATE_OneParam(FDTDRemoteConfigReceiveResultDelegate, EDTDRemoteConfigReceiveResult);
```

**FDTDRemoteConfigPrepareToChangeDelegate**

It notifies the developer about coming changes in the A/B test configuration.

<figure><img src="https://2105883905-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnGcP_ZeRJ1ipj9O8dF%2Fuploads%2FqBvEDGujbESbaDNAIGia%2F%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA%20%D1%8D%D0%BA%D1%80%D0%B0%D0%BD%D0%B0%202023-06-28%20%D0%B2%2013.22.42.png?alt=media&#x26;token=4dee6fdb-2dfc-40f8-a84a-e60152876ed8" alt="" width="375"><figcaption><p>Blueprint</p></figcaption></figure>

```
DECLARE_DELEGATE(FDTDRemoteConfigPrepareToChangeDelegate);
```

**FDTDRemoteConfigChangeResultDelegate**

It notifies the developer that the configuration has changed. Or about the reason why the configuration could not change.

<figure><img src="https://2105883905-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LnGcP_ZeRJ1ipj9O8dF%2Fuploads%2FAPGEBW0Jz2OhG7HjHCfG%2F%D0%A1%D0%BD%D0%B8%D0%BC%D0%BE%D0%BA%20%D1%8D%D0%BA%D1%80%D0%B0%D0%BD%D0%B0%202023-06-28%20%D0%B2%2013.22.22.png?alt=media&#x26;token=7bf7ffe7-ba7f-4bfe-aa70-d126823ef970" alt="" width="375"><figcaption><p>Blueprint</p></figcaption></figure>

```
DECLARE_DELEGATE_TwoParams(FDTDRemoteConfigChangeResultDelegate, EDTDRemoteConfigChangeResult, const FString&);
```

{% endtab %}

{% tab title="Godot" %}

<table><thead><tr><th width="338.4332022087659">Method</th><th>Description</th></tr></thead><tbody><tr><td><code>onRemoteConfigReceive(result: GDDTDRemoteConfigReceiveResult.ReceiveResult):</code></td><td>It is triggered every time the SDK loads an A/B test configuration. If the remoteConfigWaiting has a default value (null), <code>onReceived</code> does not get called</td></tr><tr><td><code>onRemoteConfigPrepareToChange()</code></td><td>It notifies the developer about coming changes in the A/B test configuration.</td></tr><tr><td><code>onRemoteConfigChange(result: GDDTDRemoteConfigChangeResult.ChangeResult, error: String)</code></td><td>It notifies the developer that the configuration has changed. Or about the reason why the configuration could not change.</td></tr></tbody></table>
{% endtab %}
{% endtabs %}

### **DTDRemoteConfigReceiveResult**

It is triggered every time the SDK loads the configuration of A/B tests.

<table><thead><tr><th width="358.1573840725806">type</th><th>Description</th></tr></thead><tbody><tr><td><code>DTDRemoteConfigReceiveResult.Success</code></td><td>It is triggered when the configuration of the A/B test is received.</td></tr><tr><td><code>DTDRemoteConfigReceiveResult.Failure</code></td><td>It is triggered if the SDK did not manage to get the A/B test configurations for the time period set in remoteConfigWaiting.</td></tr><tr><td><code>DTDRemoteConfigReceiveResult.Empty</code></td><td>It is triggered when the configuration of the A/B test is received, but the list of experiments is empty.</td></tr></tbody></table>

### **DTDRemoteConfigChangeResult**

Notifies whether the configuration of the A/B test has been changed.

<table><thead><tr><th width="351.527920995396">type</th><th>Description</th></tr></thead><tbody><tr><td><code>DTDRemoteConfigReceiveResult.Success</code></td><td>Configuration is changed.</td></tr><tr><td><code>DTDRemoteConfigReceiveResult.Failure</code></td><td>Configuration change attempt failed.</td></tr></tbody></table>

Data options returned by the `configChanged` method signature

<table><thead><tr><th width="272.3333333333333">DTDRemoteConfigChangeResult</th><th>Exception message</th><th>Description</th></tr></thead><tbody><tr><td><code>DTDRemoteConfigChangeResult.Success</code></td><td>null</td><td>When receiving an offer from the backend.</td></tr><tr><td><code>DTDRemoteConfigChangeResult.Success</code></td><td>null</td><td>When launching the SDK with a previously started test.</td></tr><tr><td><code>DTDRemoteConfigChangeResult.Success</code></td><td>null</td><td>When replacing the user with another user who previously started the test.</td></tr><tr><td><code>DTDRemoteConfigChangeResult.Failure</code></td><td>[A/B-Test Module] The Server refused to conduct the test.</td><td>If the server refused to provide a test available for participation.</td></tr><tr><td><code>DTDRemoteConfigChangeResult.Failure</code></td><td>[A/B-Test Module] Offer from devtodev not received within the allotted N seconds.</td><td>The backend offer is returned after a deadline e.g. due to a bad internet connection.</td></tr><tr><td><code>DTDRemoteConfigChangeResult.Failure</code></td><td>[A/B-Test Module] Offer from devtodev not received within the allotted N seconds.</td><td>The SDK was unable to receive an offer from the backend within N seconds e.g, duea bad internet connection or network problems.</td></tr><tr><td><code>DTDRemoteConfigChangeResult.Failure</code></td><td>[A/B-Test Module] In the process of receiving an offer from the server, the user was changed. Offer has been canceled.</td><td>When replacing the user with another user at the time of receiving an offer.</td></tr><tr><td><code>DTDRemoteConfigChangeResult.Failure</code></td><td>[A/B-Test Module] Offer refused, because application went into the background.</td><td>If a suitable test is found but the user made the app go into the background before the offer was received.</td></tr></tbody></table>
