GDPR

  • Advertisers
  • Agencies
  • Ad Networks
  • Developers

GDPR Compliance

The General Data Protection Regulation (GDPR) is a regulation in EU law regarding data protection and privacy for European Union citizens. It states that brands in control of personal data, must be able to honor, within one month, requests for access, portability, rectification and erasure

With regard to mobile attribution, since it is impossible to know in advance which users are European citizens, GDPR applies to all mobile users, European or not.

The GDPR Initiative

To address and manage requests from data subjects, as required for GDPR compliancy, AppsFlyer, along with mParticle, Amplitude and Braze, have initiated the OpenGDPR protocol.

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

You can read more about the initiative here.

GDPR Entities

Data Subject The end-user of the mobile app for which the data is being collected
Data Controller The advertiser determines the purpose and means by which the personal data is processed.
Data Processor 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 advertiser must comply.

Rights

GDPR Definition

How AppsFlyer helps the Controller

Right of Access

  1. If requested, data subjects have the right to know if, why, and for how long the data controller will be processing their data.
  2. If data is shared with third parties (like AppsFlyer), data subjects have the right to know who those third parties are.
  3. The right to know what categories of data are being processed.
  4. If there is automated processing, that has a significant effect on them.
When sending an ‘access’ request, Data controllers receive a copy of the Data Subjects’ processed personal data.

Right to Data Portability

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

When sending a ‘’portability’ request, Data controller receives a copy of the Data Subjects’ processed personal data

Right to Rectification

Allows Data Subjects to correct their data if they see it is inaccurate or untruthful. Data controllers then have to erase or fix inaccurate or incomplete data.

When the data controller submits a ‘rectification’ request, AppsFlyer deletes the data subject's past data and new data is updated

Right of Erasure

The right of erasure forces data controllers to remove the personal data within one month.

Advertisers can delete the collected data of data subjects with an ‘erasure’ request.

GDPR_logo2.png

AppsFlyer's GDPR Requests API

AppsFlyer supports the above requirements via its GDPR Requests API (starting May 25th 2018 - requests received prior to this date are not handled):

  1. GDPR Request - Perform one of the above request types: 'access', 'portability', 'erasure' or '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

It is up to the data controller to implement GUI changes, so that its end users can submit these requests. Note that GDPR requests are per one user at a time.

1. GDPR Request

GDPR Request Flow

All GDPR request types, 'access', 'portability', 'erasure' and 'rectification', have the same common flow:

  1. Data subject (end user) submits a request.
  2. Data Controller (advertiser) constructs the GDPR request (see below) and sends it to AppsFlyer.
  3. Data Processor (AppsFlyer) receives the request and responds with "201 OK" for valid requests.
  4. In the next 48 hours the request is queued in pending status, and may still be cancelled.
  5. Afterwards, the request status changes to in_progress, and AppsFlyer sends a ‘status change’ postback. The request CANNOT be cancelled from here on.
  6. a) AppsFlyer fulfills the request during the next 28 days.
    In the case of ‘erasure’ / 'rectification' - the end user's data is deleted.
    In the case of ‘portability’ / ‘access’ - the end user's data can be accessed in AppsFlyer’s dashboard under GDPR section, or via the Request API (see below).
    b) The request changes status to completed, and 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]

with the following properties: 

Property Name Required / Optional Description
subject_request_id REQUIRED UUID v4 string. This must be generated by the controller at the time of request submission to a Processor.
subject_request_type REQUIRED String value representing the type of GDPR Request. Supported values: "erasure", "portability", "access" and "rectification"
subject_identities REQUIRED Array of Identity Objects covering the type, value and format of the device ID (see below).  Each request can only have one device ID.
submitted_time REQUIRED RFC 3339 date string representing the time of the original request by the data subject. Note that all timestamps are sent in UTC
property_id REQUIRED String representing the mobile app to which this request is scoped, e.g., com.example for Android, id123456789 for iOS
api_version OPTIONAL Version string representing the desired version of the GDPR Requests API
status_callback_urls  OPTIONAL Array of endpoints for status callbacks to be sent to following request status changes. Note that ONLY https endpoints are supported.

A GDPR request MUST contain one or more Identity Objects used to fulfill the request. 

  1. identity_type - REQUIRED string value representing the form of identity. The supported Identity Types by AppsFlyer are ios_advertising_id, android_advertising_id, fire_advertising_id and microsoft_advertising_id
  2. identity_value - REQUIRED string value representing the identity.
  3. identity_format - REQUIRED string value representing the encoding of the identity. Currently raw is the only supported Identity Format by AppsFlyer.    

GDPR Erasure Request Example

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

Java Python Node.js C#
/* 
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?
1 out of 2 found this helpful