GDPR and CCPA compliance using APIs

  • Advertisers
  • Agencies
  • Ad Networks
  • Developers

Privacy regulations

This guide contains information on the implementation of AppsFlyer OpenGDPR APIs. The APIs enable app owners to comply with applicable data protection laws like CCPA and GDPR. 

A word from our lawyers: Nothing stated here is legal advice. It is provided only for your information and convenience. You should work closely with legal and other professional advisors to determine exactly how  GDPR, CCPA or any other laws may or may not apply to you.  The privacy relationship between you and AppsFlyer is governed by the AppsFlyer Services Privacy Policy   

In this article, references to privacy regulations includes, but is not limited to:

  • GDPR: The General Data Protection Regulation is the EU regulation relating to data protection and privacy for European Union citizens
  • CCPA: California Consumer Privacy Act 

The terms privacy regulations, GDPR and CCPA are used interchangeably in this article. 

The OpenGDPR initiative

To address and manage requests by Data Subjects submitted in accordance with privacy regulations, AppsFlyer, together with mParticle, Amplitude, and Braze, initiated the OpenGDPR protocol.

OpenGDPR is an open-source framework, facilitating cooperation between technology companies for the fair and transparent use of consumer data. It enables vendors to take data privacy actions across multiple systems that process and store customer data.

You can read more about the initiative here.

Definitions

GDPR Term AppsFlyer Term Description
Data Subject App User or End-user The App User about whom data is collected
Data Controller App Owner or Advertiser The App Owner determines the purpose and means by which the personal data is processed. 
Data Processor AppsFlyer and its partners AppsFlyer and its partners process personal data on behalf of the data controller

GDPR requirements

GDPR details the mandatory rights of the Data Subject, with which the Data Controller must comply. For API purposes these rights are translated into request types. The following details how AppsFlyer processes the different request types. 

Request type

(Right)

GDPR definition

Processing of the request by AppsFlyer 

Access

  • If requested, App Users have the right to know if, why, and for how long the App owner will process their data.
  • If data is shared with third parties, like AppsFlyer, App Users have the right to know who those third parties are.
  • The right to know what categories of data are being processed.
  • If there is automated processing, that has a significant effect on them.
The App Owners receive a copy of the App Users' processed personal data.

 Portability

The App User needs to receive all of their personal data in a structured, commonly used and machine-readable format, such as a CSV file.

The App Owner receives a copy of the App User's processed personal data.

Rectification

Allows App Users to correct their data if they see it is inaccurate or untruthful. App Owners have to erase or correct inaccurate or incomplete data.

  • AppsFlyer deletes the App User's data recorded prior to the date of the rectification request.
  • Data received thereafter is recorded by AppsFlyer.

Erasure

The right of erasure forces App Owners to remove personal data within one month of receiving the request.

The data is deleted

AppsFlyer GDPR Requests API

Compliance of the GDPR requirements described in this document are achieved using AppsFlyer GDPR Requests API

  1. GDPR Request: Perform one of the above request types: access, portability, erasure, rectification.
  2. Status Request: Query the current status of a GDPR request.
  3. Discovery Request: Inquire as to the supported API version and Data Format.
  4. Cancellation: Cancel a GDPR request during its pending phase.

App Owners need to implement UI changes to their app, so that App Users can submit requests. Note that GDPR requests are per one user at a time.

1. GDPR request

GDPR request flow

The GDPR request types, access, portability, erasure, and rectification, have the same flow:

  1. App User submits a request.
  2. The App Owner constructs the GDPR request (see below) and sends it to AppsFlyer.
  3. AppsFlyer receives the request and responds with a "201 OK" for valid requests.
  4. During the following 48 hours, the request is queued and has a pending status. The App User may cancel the request. 
  5. After 48 hours, the request status changes to in_progress. AppsFlyer sends a ‘status change’ postback. The request can't be canceled. 
  6. a) Within 28-days AppsFlyer fulfills the request.
    In the case of erasure or rectification, the App User's data is deleted.
    In the case of portability or access, the App User's data can be accessed in the AppsFlyer dashboard under GDPR, or via the Request API (see below).
    b) The request status updates to completed.  AppsFlyer sends a status change postback.

GDPR request format

A GDPR Request API can be submitted via HTTP POST to the following endpoint -

https://hq1.appsflyer.com/gdpr/opengdpr_requests?api_token=[api token]

The API token is the same API token used for pull API. You can retrieve from your dashboard under API Access.

Parameters
Property Name Mandatory Description
subject_request_id Yes UUID v4 string. Generated by the controller at the time of request submission to a Processor. It can then be used in order to check the status of the request, update or cancel it.
subject_request_type Yes

String value representing the type of GDPR Request. Supported values:

  • erasure
  • portability
  • access
  • rectification
subject_identities Yes
  • An array of identity objects defining the requester's identity (see below).
  • Each request can contain only one subject identity.
submitted_time Yes
  • RFC 3339 date string of the time of the original request by the data subject
  • Timestamps  in UTC
property_id Yes

String representing the mobile app to which this request is scoped:

Examples:

  • iOS: id123456789 
  • Android: com.example, com.publishers.name 
  • Android out-of-store: com.publisher.name-channel
    Note In some cases, app owners record out-of-store attribution using the Android Google Play name. In these cases use the regular app name as it displays in the Dashboard.
api_version No Version string representing the desired version of the GDPR Requests API
status_callback_urls Yes
  • An array of endpoints for status callbacks to be sent to following request status changes.
  • Only https endpoints are supported.
Subject_identities objects
Object type Mandatory Description
identity_type Yes
  • The identity type in string format:
    • ios_advertising_id
    • android_advertising_id
    • fire_advertising_id
    • microsoft_advertising_id
  • Example: "android_advertising_id"
identity_value Yes
  • Format: String
  • Example: "a7551968-d5d6-44b2-9831-815ac9017798"
identity_format Yes
  • The method used to encode the identity_value: raw is the only supported:
  • Example: "raw"

Example GDPR erasure request 

HTTP POST 
https://hq1.appsflyer.com/gdpr/opengdpr_requests?api_token={api token] 
HTTP/1.1Host: example.processo.com
Accept: application/json
Content-Type: application/json
{ 
  "subject_request_id":"a7551968-d5d6-44b2-9831-815ac9017798",
  "subject_request_type":"erasure",
  "submitted_time":"2018-10-02T15:00:00Z",
  "subject_identities":[ 
   { 
     "identity_type":"android_advertising_id",
     "identity_value":"a55684fd-j661-46df-9149-f7bfd652egge",
     "identity_format":"raw"
   }
  ],
  "api_version":"0.1",
  "property_id":"com.example",
  "status_callback_urls":[ 
   "https://examplecontroller.com/opengdpr_callbacks"
  ]
}
 

 

GDPR erasure request code example

JavaPythonNode.jsC#
/* 
using the okhttp package install from maven
https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp
 */

import okhttp3.*;
import java.io.IOException;

public class GdprSendRequest {
  public static void main(String[] args){

    OkHttpClient client = new OkHttpClient();
    RequestBody body = RequestBody.create(null, "" +
    "{\r\n\"subject_request_id\": \"<SUBJECT_ID>\"," +
    "\r\n\"subject_request_type\": \"erasure\"," +
    "\r\n\"submitted_time\": \"2018-11-02T15:00:00Z\"," +
    "\r\n\"subject_identities\": [\r\n" +
    "{\r\n\"identity_type\": \"android_advertising_id\"," +
    "\r\n\"identity_value\": \"<ADVERTISING_ID>\"," +
    "\r\n\"identity_format\": \"raw\"\r\n}" +
     "\r\n]," +
     "\r\n\"property_id\": \"com.example.application\"}");

    Request request = new Request.Builder()
    .url("https://hq1.appsflyer.com/gdpr/opengdpr_requests?api_token=<API_TOKEN>")
    .post(body)
    .addHeader("Content-Type", "application/json")
     .addHeader("Accept", "application/json")
    .build();

    try {
      Response response = client.newCall(request).execute();
      System.out.println(response.code());
      System.out.println(response.body().string());
      System.exit(0);
    } catch (IOException e) {
      e.printStackTrace();
      System.exit(1);
    }
  }
}

2. Status request

Every submitted GDPR request can be later queried for its status, by specifying the subject_request_id. There are four supported status types:

  1. pending - A correct request has been received and is currently in the queue
  2. in_progress - A request is currently being acted on
  3. completed - A request has been fulfilled
  4. canceled - A request has been canceled

Status request format

A status request can be submitted via HTTP GET to the following endpoint:

https://hq1.appsflyer.com/gdpr/opengdpr_requests/[subject_request_id]?api_token=[api token]

Status response example

HTTP/1.1 200 OK
Content-Type: application/json
X-OpenGDPR-Processor Domain: example processor.com
X-OpenGDPR-Signature:
kiGlog3PdQx+FQmB8wYwFC1fekbJG7Dm9WdqgmXc9uKkFRSM4uPzylLi7j083461xLZ+mUloo3tpsmyIZpt5eMfgo7ejXPh6lqB4ZgCnN6+1b6Q3NoNcn/+11UOrvmDj772wvg6uIAFzsSVSjMQxRs8LAmHqFO4cF2pbuoPuK2diHOixxLj6+t97q0nZM7u3wmgkwF9EHIo3C6G1SI04/odvyY/VdMZgj3H1fLnz+X5rc42/wU4974u3iBrKgUnv0fcB4YB+L6Q3GsMbmYzuAbe0HpVA17ud/bVoyQZAkrW2yoSy1x4Ts6XKba6pLifIHf446Bubsf5r7x1kg6Eo7B8zur666NyWOYrglkOzU4IYO8ifJFRZZXazOgk7ggn9obEd78GBc3kjKKZdwaCrLx7WV5y9TMDCf+2FILOJM/MwTUy1dLZiaFHhGdzld2AjbjK1CfVzyPssch0iQYYtbR49GhumvkYl11S4oDfu0c3t/xUCZWg0hoR3XL3B7NjcrlrQinB1KbyTNZccKR0F4Lk9fDgwTVkrAg152UqPyzXxpdzXjfkDkSEgAevXQwVJWBNf18bMIEgdH2usF/XauQoyrne7rcMIWBISPgtBPj3mhcrwscjGVsxqJva8KCVCKD/4Axmo9DISib5/7A6uczJxQG2Bcrdj++vQqK2succ=
{
 "controller_id":"example_controller_id",
 "expected_completion_time":"2018-11-01T15:00:01Z",
 "subject_request_id":"a7551968-d5d6-44b2-9831-815ac9017798",
 "request_status":"pending",
 "api_version":"0.1"
}

Status postbacks

As described in the GDPR Request Flow above, when the status of a GDPR request changes, from pending to in_progress to completed, AppsFlyer sends a GDPR postback to the requesting endpoints, specified with the status_callback_urls property.

Status Postback Example:

POST /opengdpr_callbacks HTTP/1.1
Host: examplecontroller.com
Content-Type: application/json
X-OpenGDPR-Processor Domain: appsflyer.com
X-OpenGDPR-Signature: kiGlog3PdQx+FQmB8wYwFC1fekbJG7Dm9WdqgmXc9uKkFRSM4uPzylLi7j083461xLZ+mUloo3tpsmyIZpt5eMfgo7ejXPh6lqB4ZgCnN6+1b6Q3NoNcn/+11UOrvmDj772wvg6uIAFzsSVSjMQxRs8LAmHqFO4cF2pbuoPuK2diHOixxLj6+t97q0nZM7u3wmgkwF9EHIo3C6G1SI04/odvyY/VdMZgj3H1fLnz+X5rc42/wU4974u3iBrKgUnv0fcB4YB+L6Q3GsMbmYzuAbe0HpVA17ud/bVoyQZAkrW2yoSy1x4Ts6XKba6pLifIHf446Bubsf5r7x1kg6Eo7B8zur666NyWOYrglkOzU4IYO8ifJFRZZXazOgk7ggn9obEd78GBc3kjKKZdwaCrLx7WV5y9TMDCf+2FILOJM/MwTUy1dLZiaFHhGdzld2AjbjK1CfVzyPssch0iQYYtbR49GhumvkYl11S4oDfu0c3t/xUCZWg0hoR3XL3B7NjcrlrQinB1KbyTNZccKR0F4Lk9fDgwTVkrAg152UqPyzXxpdzXjfkDkSEgAevXQwVJWBNf18bMIEgdH2usF/XauQoyrne7rcMIWBISPgtBPj3mhcrwscjGVsxqJva8KCVCKD/4Axmo9DISib5/7A6uczJxQG2Bcrdj++vQqK2succ=

{
"controller_id":"example controller id at the processor",
"expected_completion_time":"2018-11-01T15:00:01Z",
"status_callback_url":"https://examplecontroller.com/opengdpr_callbacks",
"Subject_request_id":"a7551968-d5d6-44b2-9831-815ac9017798",
"Request_status":"pending"
}

3. Report request

Once an Access Request or Portability Request has been completed, you can download the report via HTTP GET to the following endpoint:

https://hq1.appsflyer.com/gdpr/download/[REQUEST_ID]?api_token=[TOKEN]

The generated report is available for seven days from the time of completion.

4. Discovery request

To learn about the formats supported by AppsFlyer, a discovery request can be submitted via HTTP GET to the following endpoint:

https://hq1.appsflyer.com/gdpr/discovery?api_token=[api token]

Discovery response example

HTTP/1.1 200 OK
Content-Type: application/json
{
 "api_version": "0.1",
 "supported_identities": [
  {
   "identity_type": "android_advertising_id",
   "identity_format": "raw"
  },
 ],
 "supported_subject_request_types": [
  "erasure", "access", "portability", "rectification"
 ],
 "processor_certificate": "https://exampleprocessor.com/cert.pem"
}

5. Cancellation request

It is possible to cancel a GDPR request, based on its subject_request_id, but only during the pending phase.

To so submit an HTTP DELETE with subject_request_id to:

https://hq1.appsflyer.com/gdpr/opengdpr_requests/[subject_request_id]?api_token=[api token]

Cancellation response

When a GDPR cancellation request is received, AppsFlyer returns an HTTP response with status code 202 and several other parameters. For more details check the GDPR "Cancellation Response Properties" chapter.

Once the cancellation of the request takes place AppsFlyer sends a postback with the cancelled status.

6. GDPR requests test API

This AppsFlyer’s API is a test API for the AppsFlyer’s GDPR Requests API.

How does it work?

The test API works as follows:

1. Once a GDPR request has been made, the request is immediately placed in ‘Pending’ status. For testing purposes the status changes every 30 seconds.

2. If an endpoint for a status postback has been inserted in the GDPR request, a first postback is sent right after the request and two more status postbacks are sent in 30 second intervals.

GDPR Request Test Endpoint:

https://hq1.appsflyer.com/gdpr/stub?api_token=[api token]

Status Request Test Endpoint:

https://hq1.appsflyer.com/gdpr/stub/[request id]?api_token=[api token]

Discovery Request Test Endpoint:

https://hq1.appsflyer.com/gdpr/stub/discovery?api_token=[api token]

Cancellation Request Test Endpoint:

https://hq1.appsflyer.com/gdpr/stub/[request id]?api_token=[api token]

 Notes

  • A valid API token must be inserted with the request.
  • In the ‘property_id’ property, the App ID must belong to the account owner (according to the API token).

Request logs

All GDPR requests submitted are available to be viewed in the Logs Dashboard by account owners only.

For completed access and portability requests, it is also possible to download the report from within this dashboard.

To access the Logs Dashboard:

1. Go to the main dashboard and click your user name.

2. Click Logs and the following window opens:

GDPR_Table.png

 

Was this article helpful?
2 out of 4 found this helpful