> For the complete documentation index, see [llms.txt](https://docs.sfbx.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.sfbx.io/configuration/step-3-notice-implementation-web-app-tv/android/unified-sdk/step-3-integration.md).

# Step 3: Integration

***

## How to use AppConsent

### 1. Get your AppKey

On AppConsent configuration interface [https://app.appconsent.io](< https://app.appconsent.io>),  create your unified SDK source.

<figure><img src="/files/MoGc4k3kexUz4EUXOfQg" alt=""><figcaption></figcaption></figure>

Then  create your notice and retrieve your generated **YOUR\_APP\_KEY**&#x20;

<figure><img src="/files/ETbXFzlfMoR29FVrzSmm" alt=""><figcaption></figcaption></figure>

### 2. Initialize AppConsent & use it

The second step is to initialize the SDK and wait for it to be started before using it.

{% hint style="success" %}
**TIP**

We recommend you do this in the **Application** class, Custom **ContentProvider**, **Splashscreen**, or your "**android.intent.category.LAUNCHER**" activity.
{% endhint %}

#### **Why timing your consent prompt matters**

First impressions are critical. Users who encounter a consent dialog before experiencing any value from your app are significantly more likely to dismiss it — or abandon the app entirely.

By initializing the SDK early in the background while strategically delaying the CMP display, you ensure that when the consent prompt appears, users are already engaged. This small timing shift can have a measurable impact on positive consent rates, ad revenue, and long-term retention.

The goal is simple : make consent feel like a natural step in the experience, not a barrier to it.

#### **Technical implementation**

The SDK must be initialized as early as possible in your app's lifecycle. On startup, it bootstraps a WebView and initializes its JavaScript engine — a process that takes time. The earlier you trigger this, the sooner the SDK will be ready.

Initialization does not mean the SDK is immediately usable. You must wait for the `onCmpReady` callback before interacting with it. Only at that point can you safely call `getInstance()` and display the CMP.

{% hint style="info" %}
**INFO**

Even if your ad provider registers with the user consent update events and this is transparent to you, some providers may not work correctly with this solution. For this reason, we recommend that you initialize your provider's SDK only when consent has been given, to ensure that your ads are in accordance with user consent. Think to update it each time the user updates his consent too, thank to callbacks
{% endhint %}

{% hint style="info" %}
**INFO**

In the example below, the code focuses on using the SDK **exclusively**.\
The potential **imports** and **visual elements** in these examples are therefore not present, as they are strongly linked to the Android structure and project, which are independent of the SDK.
{% endhint %}

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

```kotlin
class MyApplication : Application() {

    override fun onCreate() {
        super.onCreate()
        SFBX.initialize(
            configuration = Configuration(appkey = "YOUR-APP-KEY"),
            onCmpReady = { appconsent ->
                Log.d(TAG, "Appconsent ready: $appconsent")
            },
            onCmpOnError = { error ->
                Log.e(TAG, "Appconsent init failed", error)
            },
        )
    }
}

class MyActivity : Activity() {
    override fun onCreate() {
        super.onCreate()
        try {
            SFBX.getInstance().presentNotice(
                context = context,
                onCmpDisplayed = {
                    Log.d(TAG, "CMP displayed")
                },
                onCmpNotDisplayed = { error ->
                    Log.d(TAG, "CMP not displayed: $error")
                },
                onCmpClosed = { error ->
                    Log.d(TAG, "CMP closed: $error")
                },
            )
        } catch (error: AppconsentExceptions) {
            Log.w(TAG, "SDK not initialized yet", error)
        }
    }
}
```

{% endtab %}

{% tab title="Java" %}

```java
public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        SFBX.initialize(
                new Configuration("YOUR-APP-KEY"),
                appconsent -> Unit.INSTANCE,          // onCmpReady
                error -> {                            // onCmpOnError (initialize never throws)
                    Log.e(TAG, "Appconsent init failed", error);
                    return Unit.INSTANCE;
                }
        );
    }
}

public class MyActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        try {
            SFBX.getInstance().presentNotice(
                    context,
                    () -> Unit.INSTANCE,    // onCmpDisplayed
                    error -> Unit.INSTANCE, // onCmpNotDisplayed (error may be non-null)
                    error -> Unit.INSTANCE  // onCmpClosed (error non-null on failure)
            );
        } catch (AppconsentExceptions error) {
            Log.w(TAG, "SDK not initialized yet", error);
        }
    }
}
```

{% endtab %}
{% endtabs %}

#### **Best Practices**

Waiting for the right moment to display the CMP is just as important as initializing the SDK early. Here are a few recommended triggers :

* **Before the first ad load** — ensures consent is collected before any ad request is made, keeping you compliant by design.
* **After the onboarding flow** — the user has already experienced value, making them more likely to engage positively with the consent prompt.
* **At a natural pause in the user journey** — such as between two screens or after a key action, where an interruption feels least disruptive.

{% hint style="danger" %}
Avoid displaying the CMP on the very first screen of your app. Users who haven't yet experienced any value are significantly more likely to dismiss or ignore the prompt.
{% endhint %}

### 3. Suggest CMP to your users

It is also advisable to provide your users with an entry allowing them to view and modify their consent, such as a configuration screen.

{% hint style="info" %}
**INFO**

In the example below, the code focuses on using the SDK **exclusively**.\
The potential **imports** and **visual elements** in these examples are therefore not present, as they are strongly linked to the Android structure and project, which are independent of the SDK.
{% endhint %}

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

```kotlin
class SecondActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_second)

        findViewById<View>(R.id.button_display_privacy_policy).setOnClickListener {
            try {
                SFBX.getInstance()
            } catch (e: Exception) {
                null
            }?.displayLayer2(
                this@SecondActivity,
                onCmpDisplayed = {
                    // The CMP is currently being displayed to the user.
                },
                onCmpNotDisplayed = { appconsentExceptions ->
                    // The CMP did not display for some reason.
                },
                onCmpClosed = { appconsentExceptions ->
                    // The CMP screen has been closed.
                },
            )
        }
    }
}
```

{% endtab %}

{% tab title="Java" %}

```java
public class SecondActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        findViewById(R.id.button_display_privacy_policy).setOnClickListener(v -> {
            try {
                SFBX.getInstance().displayLayer2(
                    this,
                    () -> {
                        // The CMP is currently being displayed to the user.
                        return Unit.INSTANCE;
                    },
                    (appconsentExceptions) -> {
                        // The CMP did not display for some reason.
                        return Unit.INSTANCE;
                    },
                    (appconsentExceptions) -> {
                        // The CMP screen has been closed.
                        return Unit.INSTANCE;
                    }
                );
            } catch (AppconsentExceptions e) {
                // Something goes wrong and the SDK returns a known exception
            }
        });
    }
}
```

{% endtab %}
{% endtabs %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.sfbx.io/configuration/step-3-notice-implementation-web-app-tv/android/unified-sdk/step-3-integration.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
