Topics API developer guide

Provide feedback

The Topics API infers coarse-grained interest signals on-device based on a user's app usage. These signals, called topics, are shared with advertisers to support interest-based advertising without tracking individual users across apps. Learn more about the Topics API in the design proposal.

Setup

Ensure that you are using the Android Privacy Sandbox Developer Preview SDK, as this is the only version of the SDK which includes the privacy- preserving APIs. You will need to include a permission and create an ad services configuration for your app to use the Topics API, as shown below:

<uses-permission android:name="android.permission.ACCESS_ADSERVICES_TOPICS" />

Reference an ad services configuration in the <application> element of your manifest:

<property android:name="android.adservices.AD_SERVICES_CONFIG"
   android:resource="@xml/ad_services_config" />

Specify the ad services XML resource referenced in the manifest, such as res/xml/ad_services_config.xml. Use either the allowAllToAccess attribute to grant access to all SDKs, or the allowSdksToAccess attribute to grant access to individual SDKs. Learn more about Ad Services permissions and SDK access control.

<ad-services-config>
    <topics allowAllToAccess="true" />
</ad-services-config>

Additionally, you must enable access to the Topics API (disabled by default) with this adb command.

adb shell device_config put adservices ppapi_app_allow_list \"*\"

The primary functionality of the Topics API resides in the getTopics() method inside of the TopicsManager object, as shown in this example:

Kotlin

fun getTopics(
        getTopicsRequest: GetTopicsRequest?,
        executor: Executor?,
        callback: OutcomeReceiver<GetTopicsResponse?, Exception?>?
    ) { }

Java

public void getTopics (GetTopicsRequest getTopicsRequest, Executor executor,
    OutcomeReceiver<GetTopicsResponse, Exception> callback)

To use this method, initialize the TopicsManager object and the parameters necessary to receive topics data. To initialize parameters, create a GetTopicsRequest, an Executor, and an OutcomeReceiver for the callback. GetTopicsRequest passes needed information to retrieve topics data, Executor allows getTopics() to execute off of the UI thread, and the OutcomeReceiver callback handles the result asynchronously. For example:

Kotlin

private fun topicGetter() {
val mContext = baseContext
val mTopicsManager = mContext.getSystemService(TopicsManager::class.java)
val mExecutor: Executor = Executors.newCachedThreadPool()
mTopicsManager.getTopics(GetTopicsRequest.create(), mExecutor,
    mCallback as OutcomeReceiver<GetTopicsResponse, Exception>)
}

private var mCallback: OutcomeReceiver<GetTopicsResponse, java.lang.Exception> =
object : OutcomeReceiver<GetTopicsResponse, java.lang.Exception> {
    override fun onResult(result: GetTopicsResponse) {
        // handle successful result
        val topicsResult = result.topics
        for (i in topicsResult.indices) {
            Log.i("Topic", topicsResult[i].getTopicID().toString())
        }
        if (topicsResult.size == 0) {
            Log.i("Topic", "Returned Empty")
        }
    }

    override fun onError(error: java.lang.Exception) {
        // handle error
        Log.i("Topic", "Error, did not return successfully")
    }
}

Java

public void TopicGetter() {
    @NonNull Context mContext = getBaseContext();
    TopicsManager mTopicsManager = mContext.getSystemService(TopicsManager.class);
    Executor mExecutor = Executors.newCachedThreadPool();
    mTopicsManager.getTopics(GetTopicsRequest.create(),mExecutor,mCallback);
}

OutcomeReceiver mCallback = new OutcomeReceiver<GetTopicsResponse, Exception>() {
    @Override
    public void onResult(@NonNull GetTopicsResponse result) {
        //Handle Successful Result
        List<Topic> topicsResult = result.getTopics();
        for (int i = 0; i < topicsResult.size(); i++) {
            Log.i("Topic", topicsResult.get(i).getTopicID().toString());
        }
        if (topicsResult.size() == 0) {
            Log.i("Topic", "Returned Empty");
        }
    }

    @Override
    public void onError(@NonNull Exception error) {
        // Handle error
        Log.i("Topic", "Experienced an error, and did not return successfully");

    }
};

Request a set of topics

Once your setup is ready, you can make a call to receive a GetTopicsResponse as a result from the getTopics() method:

Kotlin

mTopicsManager.getTopics(getTopicsRequest.build(), mExecutor,
        mCallback as OutcomeReceiver<GetTopicsResponse, java.lang.Exception>)

Java

mTopicsManager.getTopics(getTopicsRequest.build(), mExecutor, mCallback);

The above invocation will provide a list of Topics objects containing ID values that correspond to topics in the open source taxonomy that are relevant to the user, or a relevant error. The topics will resemble this example:

/Internet & Telecom/Text & Instant Messaging

Refer to the taxonomy for a list of possible topics that can be returned. This taxonomy is open source and suggested changes can be filed using the feedback button at the top of this page.

Testing

The Topics API provides relevant and fresh topics based on app usage. This early version gives a preview of the API behaviors, and we will improve the quality of topics over future releases.

To get the fullest experience, we recommend a testing environment with multiple apps where you call getTopics() to see how topics are selected. The SDK Runtime and Privacy Preserving APIs Repository on GitHub contains a set of individual Android Studio projects to help you get started, including samples that demonstrate how to initialize and call the Topics API.

The topics calculation takes place at the end of an "epoch." By default, each epoch is 7 days long, but you can modify this interval to get a result more quickly using the following Android Debug Bridge shell command:

# Shortens the epoch length to 5 minutes.
adb shell setprop debug.adservices.topics_epoch_job_period_ms 300000

You can confirm the topics_epoch_job_period_ms value with getprop:

adb shell getprop debug.adservices.topics_epoch_job_period_ms

To manually trigger epoch computation, execute the following command:

adb shell cmd jobscheduler run -f com.google.android.adservices.api 2

Limitations

For a list of in-progress capabilities for the Topics API, refer to the release notes.

Reporting bugs and issues

Your feedback is a crucial part of the Privacy Sandbox on Android! Let us know of any issues you find or ideas for improving Privacy Sandbox on Android.