Setup
To implement the Topics API, you need to set up your development environment first. to perform the following setup steps:
Use the latest Android Privacy Sandbox SDK to get the most up-to-date version of the privacy-preserving APIs.
Add the following to your manifest:
Permission: Include the
ACCESS_ADSERVICES_TOPICS
permission to allow your app to access the Topics API:<uses-permission android:name="android.permission.ACCESS_ADSERVICES_TOPICS" />
Ad Services Configuration: Reference an Ad Services configuration file 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 theallowAllToAccess
attribute to grant access to all SDKs, or theallowSdksToAccess
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>
Enroll your ad tech with the Privacy Sandbox to call Topics API in your SDK. For testing locally, you can disable Topics enrollment check with the following commands:
adb shell setprop debug.adservices.disable_topics_enrollment_check true
Enable access to the Topics API. By default, the Topics API is disabled. You need to enable it using ADB commands:
adb shell device_config put adservices ppapi_app_signature_allow_list \"\*\"
adb shell setprop debug.adservices.disable_topics_enrollment_check true
Kick off your implementation by forking our Java or Kotlin version of the sample app to familiarize yourself with how to retrieve topics on a device.
Request a set of topics
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 (@NonNull GetTopicsRequest getTopicsRequest,
@NonNull Executor executor,
@NonNull OutcomeReceiver<GetTopicsResponse, Exception> callback)
To use this method, initialize the TopicsManager
object and the parameters
necessary to receive topics data. GetTopicsRequest
passes needed information
to retrieve Topics API data, including a flag to indicate whether the caller is
going to act as an observer or not. When not acting as an observer, the
getTopics
call returns a topic from the previous epoch, but won't
influence topics data for the following one. 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()
val shouldRecordObservation = false
val mTopicsRequestBuilder: GetTopicsRequest.Builder = GetTopicsRequest.Builder()
mTopicsRequestBuilder.setAdsSdkName(baseContext.packageName)
mTopicsRequestBuilder.setShouldRecordObservation(shouldRecordObservation)
mTopicsManager.getTopics(mTopicsRequestBuilder.build(), 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();
boolean shouldRecordObservation = false;
GetTopicsRequest.Builder mTopicsRequestBuilder = new GetTopicsRequest.Builder();
mTopicsRequestBuilder.setAdsSdkName(getBaseContext().getPackageName());
mTopicsRequestBuilder.setShouldRecordObservation(shouldRecordObservation);
mTopicsManager.getTopics(mTopicsRequestBuilder.build(), 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");
}
};
Once your setup is ready, you can make a call to receive a
GetTopicsResponse
as a result from the getTopics()
method:
Kotlin
mTopicsManager.getTopics(mTopicsRequestBuilder.build(), mExecutor,
mCallback as OutcomeReceiver<GetTopicsResponse, java.lang.Exception>)
Java
mTopicsManager.getTopics(mTopicsRequestBuilder.build(), mExecutor, mCallback);
This 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. This Android Debug Bridge shell command shortens the epoch length to 5 minutes:
adb shell device_config put adservices topics_epoch_job_period_ms 300000
You can confirm the topics_epoch_job_period_ms
value with get
:
adb shell device_config get 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
In addition to using the sample app, there is a colab that
you can use to test different combinations of app info against the topics
classifier. Use this colab to view the kinds of results your app is likely to
get when calling getTopics
.
Encryption details
With the introduction of encryption, calls to GetTopics()
will now generate a
response with a list of EncryptedTopic
objects. Decrypting these results will
result in an object with the same JSON format of the previous Topic
object.
Topics API supports one shot implementation of HPKE (Hybrid Public Key Encryption). We expect the enrolled caller to host a 32-bit public key on the public encryption URL endpoint provided during enrollment. These keys are expected to be Base64 encoded.
EncryptedTopic
object's have 3 fields. The list of returned topics can be
obtained by using the corresponding private key for the public key.
For development purposes, you can test the Topics API encryption by disabling the enrollment check. This would force the API to use the test public key for encrypting your responses. You can decrypt the encrypted topics using the corresponding private key.
Limitations
For a list of in-progress capabilities for the Topics API, refer to the release notes.
Report 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.
Next steps
Control & transparency
Topics on Android overview
See also
Check out our resources to better understand the Topics API on Android.
- Check out Topics sample apps, collab and walkthrough videos.
- See how users and developers can control the API.
- Check out the support resources to ask questions, engage and share feedback.