As you read through the Privacy Sandbox on Android documentation, use the Developer Preview or Beta button to select the program version that you're working with, as instructions may vary.
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. Important: Select the SDK Extensions Release or Developer Preview button to choose the program version that you're working with, as instructions may vary.
Setup
Use the latest Android Privacy Sandbox SDK, to get the most up-to-date version of the privacy-preserving APIs. You need to include a permission and create an Ad Services configuration in your manifest for your app to use the Topics API:
<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 these adb commands.
adb shell device_config put adservices ppapi_app_signature_allow_list \"\*\"
adb shell setprop debug.adservices.disable_topics_enrollment_check true
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");
}
};
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(mTopicsRequestBuilder.build(), mExecutor,
mCallback as OutcomeReceiver<GetTopicsResponse, java.lang.Exception>)
Java
mTopicsManager.getTopics(mTopicsRequestBuilder.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. 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
.
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.
Recommended for you
- Note: link text is displayed when JavaScript is off
- Protected Audience API on Android developer guide
- Release notes
- Configure AdServices {:#configure-adservices}