User Privacy API

The User Privacy API helps you comply with end-user data deletion requests mandated by global privacy laws such as GDPR and CCPA.

The API lets you programmatically submit requests to delete all data for a set of known Amplitude IDs or User IDs.

Authentication

This API uses basic authentication, using the API key and secret key for your project. Pass base64-encoded credentials in the request header like {api-key}:{secret-key}. api-key replaces username, and secret-key replaces the password.

Your authorization header should look something like this:

--header 'Authorization: Basic YWhhbWwsdG9uQGFwaWdlZS5jb206bClwYXNzdzByZAo'

For more information, see Find your API Credentials

Endpoints

Region Endpoint
Standard server https://amplitude.com/api/2/deletions/users
EU residency server https://analytics.eu.amplitude.com/api/2/deletions/users

Considerations

Keep these considerations in mind when using the User Privacy API.

  • You may delete all data tied to an end user across your entire organization or across a particular project. By default, deletion requests submitted through the User Privacy API create jobs for a particular project within your organization. The API key provided in the request identifies this project. To delete a user across your entire organization, follow the guidelines below in "JSON body parameter" and set the delete_from_org parameter to true in your request. In this case, the ignore_invalid_ids parameter is ignored and treated as true. The API then creates one deletion job per project across your entire organization that contains information on the requested users.
  • When you make a deletion request, Amplitude emails all account admins with the deletion details.
  • Amplitude deletes all events and user properties added up until the time that job runs for each Amplitude ID in a deletion job.
  • Running a deletion job for a user doesn't block new events for that user. Amplitude accepts new events from a deleted user.
  • If Amplitude receives events for a deleted user, then it counts the deleted user as a new user.
    Because deletion removes all user data from Amplitude servers, Amplitude doesn't recognize the new user as the deleted user.
  • Amplitude schedules batch jobs for deletions to reduce resource impact and ensure high availability, with the batch's first request date serving as the reference point for scheduling the jobs.
    In line with GDPR article 12.3 and 17, Amplitude processes deletion requests without undue delay, within 30 days after receiving the request.
    The actual timeline for deletion depends on the complexity and number of requests Amplitude receives.
    If your data volume is large (>1BB/month), then Amplitude may need to reduce your frequency of deletion scheduling.
  • You can revoke requests in the batch until three (3) days before the day the job scheduled run date. During the three (3) day period, you can't edit the batch.
    Amplitude adds deletion requests made during this time to a new batch.
  • After the three (3) day period, the request's status changes to submitted. You can't stop the job at this point.
    The deletion process removes all data associated with the user from all Amplitude's systems, including associated recovery and back-up systems.
    After the job completes, its status changes to done.
  • By default, deletion requests create jobs for a particular project within your organization. API calls identify this project with the API key you provide in the request. To delete a user across your entire organization, set the delete_from_org parameter to true in your request. With this, the API creates one deletion job per project that contains information on the requested users.
  • To check the progress of your deletion requests, use the GET API to inspect the job status for each project, utilizing each project’s respective project API key.

User tracking

Using this API doesn't prevent future user tracking for the deleted users. To learn about how to stop tracking users in your application, see the setOptOut() method in documentation for the Amplitude SDK you're using.

Limits

The endpoint /api/2/deletions/users has a rate limit of 1 HTTP request per second. Each HTTP request can contain up to 100 amplitude_ids or user_ids.

Make up to 100 deletion requests per second if you batch 100 users in each request.

Delete users

POST /deletions/users

Add a user for deletion using a JSON body. Specify up to 100 users at a time. You can use mix of Amplitude IDs and User IDs.

Example: Delete a user in one project

1curl --request POST 'https://amplitude.com/api/2/deletions/users' \
2-u 'API_KEY:API_SECRET' \
3--header 'Content-Type: application/json' \
4--header 'Accept: application/json' \
5--data-raw '{
6 "amplitude_ids": [123123, 543221],
7 "user_ids": ["user_1"],
8 "requester": "employee@yourcompany.com"
9}'

1POST /api/2/deletions/users HTTP/1.1
2Host: amplitude.com
3Authorization: Basic API_KEY:SECRET_KEY
4Content-Type: application/json
5 
6{
7 "amplitude_ids": [
8 356896327775,
9 356896327755
10 
11 ],
12 "user_ids": [
13 1000,
14 2999
15 ],
16 "requester": "employee@yourcompany.com"
17}

1var headers = {
2 'Content-Type':'application/json',
3 'Accept':'application/json'
4 
5};
6 
7$.ajax({
8 url: 'https://amplitude.com/api/2/deletions/users',
9 method: 'post',
10 
11 headers: headers,
12 success: function(data) {
13 console.log(JSON.stringify(data));
14 }
15})

1const request = require('node-fetch');
2const inputBody = '{
3 "amplitude_ids": [
4 "amp_id_1",
5 "amp_id_2",
6 "..."
7 ],
8 "user_ids": [
9 "user_id_1",
10 "user_id_2",
11 "..."
12 ],
13 "requester": "employee@yourcompany.com"
14}';
15const headers = {
16 'Content-Type':'application/json',
17 'Accept':'application/json'
18 
19};
20 
21fetch('https://amplitude.com/api/2/deletions/users',
22{
23 method: 'POST',
24 body: inputBody,
25 headers: headers
26})
27.then(function(res) {
28 return res.json();
29}).then(function(body) {
30 console.log(body);
31});

1require 'rest-client'
2require 'json'
3 
4headers = {
5 'Content-Type' => 'application/json',
6 'Accept' => 'application/json'
7}
8 
9result = RestClient.post 'https://amplitude.com/api/2/deletions/users',
10 params: {
11 }, headers: headers
12 
13p JSON.parse(result)

1import requests
2import json
3from requests.auth import HTTPBasicAuth
4 
5url = "https://amplitude.com/api/2/deletions/users"
6 
7payload = json.dumps({
8 "amplitude_ids": [
9 1231231
10 ],
11 "user_ids": [
12 "user_1"
13 ],
14 "requester": "employee@yourcompany.com"
15})
16headers = {
17 'Content-Type': 'application/json',
18 'Accept': 'application/json'
19}
20auth = HTTPBasicAuth('API_KEY', 'API_SECRET')
21response = requests.request("POST", url, headers=headers, data=payload, auth=auth)
22 
23print(response.text)

1URL obj = new URL("https://amplitude.com/api/2/deletions/users");
2HTTPURLConnection con = (HTTPURLConnection) obj.openConnection();
3con.setRequestMethod("POST");
4int responseCode = con.getResponseCode();
5BufferedReader in = new BufferedReader(
6 new InputStreamReader(con.getInputStream()));
7String inputLine;
8StringBuffer response = new StringBuffer();
9while ((inputLine = in.readLine()) != null) {
10 response.append(inputLine);
11}
12in.close();
13System.out.println(response.toString());

1package main
2 
3import (
4 "fmt"
5 "strings"
6 "net/http"
7 "io/ioutil"
8)
9 
10func main() {
11 
12 url := "https://amplitude.com/api/2/deletions/users"
13 method := "POST"
14 
15 payload := strings.NewReader(`{
16 "amplitude_ids": [
17 356896327775,
18 356896327755
19 
20 ],
21 "user_ids": [
22 1000,
23 2999
24 ],
25 "requester": "employee@yourcompany.com"
26}`)
27 
28 client := &http.Client {
29 }
30 req, err := http.NewRequest(method, url, payload)
31 
32 if err != nil {
33 fmt.Println(err)
34 return
35 }
36 req.Header.Add("Authorization", "Basic API_KEY:API_SECRET")
37 req.Header.Add("Content-Type", "application/json")
38 
39 res, err := client.Do(req)
40 if err != nil {
41 fmt.Println(err)
42 return
43 }
44 defer res.Body.Close()
45 
46 body, err := ioutil.ReadAll(res.Body)
47 if err != nil {
48 fmt.Println(err)
49 return
50 }
51 fmt.Println(string(body))
52}

Example: Delete users from all projects

1curl --location --request POST 'https://amplitude.com/api/2/deletions/users' \
2-u 'API_KEY:SECRET_KEY' \
3--header 'Content-Type: application/json' \
4--data-raw '{
5 "amplitude_ids": [
6 356896327775,
7 356896327755
8 
9 ],
10 "user_ids": [
11 1000,
12 2999
13 ],
14 "ignore_invalid_id": "true",
15 "delete_from_org": "true",
16 "requester": "employee@yourcompany.com"
17}'

1POST /api/2/deletions/users HTTP/1.1
2Host: amplitude.com
3Authorization: Basic API_KEY:SECRET_KEY
4Content-Type: application/json
5 
6{
7 "amplitude_ids": [
8 356896327775,
9 356896327755
10 
11 ],
12 "user_ids": [
13 1000,
14 2999
15 ],
16 "delete_from_org": "true",
17 "ignore_invalid_ids": "true",
18 "requester": "employee@yourcompany.com"
19}

1var headers = {
2 'Content-Type':'application/json',
3 'Accept':'application/json'
4 
5};
6 
7$.ajax({
8 url: 'https://amplitude.com/api/2/deletions/users',
9 method: 'post',
10 
11 headers: headers,
12 success: function(data) {
13 console.log(JSON.stringify(data));
14 }
15})

1const request = require('node-fetch');
2const inputBody = '{
3 "amplitude_ids": [
4 "amp_id_1",
5 "amp_id_2",
6 "..."
7 ],
8 "user_ids": [
9 "user_id_1",
10 "user_id_2",
11 "..."
12 ],
13 "delete_from_org": true,
14 "ignore_invalid_ids": true,
15 "requester": "employee@yourcompany.com"
16}';
17const headers = {
18 'Content-Type':'application/json',
19 'Accept':'application/json'
20 
21};
22 
23fetch('https://amplitude.com/api/2/deletions/users',
24{
25 method: 'POST',
26 body: inputBody,
27 headers: headers
28})
29.then(function(res) {
30 return res.json();
31}).then(function(body) {
32 console.log(body);
33});

1require 'rest-client'
2require 'json'
3 
4headers = {
5 'Content-Type' => 'application/json',
6 'Accept' => 'application/json'
7}
8 
9result = RestClient.post 'https://amplitude.com/api/2/deletions/users',
10 params: {
11 }, headers: headers
12 
13p JSON.parse(result)

1import requests
2import json
3 
4url = "https://amplitude.com/api/2/deletions/users"
5 
6payload = json.dumps({
7 "amplitude_ids": [
8 356896327775,
9 356896327755
10 ],
11 "user_ids": [
12 1000,
13 2999
14 ],
15 "delete_from_org": True,
16 "ignore_invalid_ids": True,
17 "requester": "employee@yourcompany.com"
18})
19headers = {
20 'Authorization': 'Basic API_KEY:API_SECRET',
21 'Content-Type': 'application/json'
22}
23 
24response = requests.request("POST", url, headers=headers, data=payload)
25 
26print(response.text)

1URL obj = new URL("https://amplitude.com/api/2/deletions/users");
2HTTPURLConnection con = (HTTPURLConnection) obj.openConnection();
3con.setRequestMethod("POST");
4int responseCode = con.getResponseCode();
5BufferedReader in = new BufferedReader(
6 new InputStreamReader(con.getInputStream()));
7String inputLine;
8StringBuffer response = new StringBuffer();
9while ((inputLine = in.readLine()) != null) {
10 response.append(inputLine);
11}
12in.close();
13System.out.println(response.toString());

1package main
2 
3import (
4 "fmt"
5 "strings"
6 "net/http"
7 "io/ioutil"
8)
9 
10func main() {
11 
12 url := "https://amplitude.com/api/2/deletions/users"
13 method := "POST"
14 
15 payload := strings.NewReader(`{
16 "amplitude_ids": [
17 356896327775,
18 356896327755
19 
20 ],
21 "user_ids": [
22 1000,
23 2999
24 ],
25 "delete_from_org": true,
26 "ignore_invalid_ids": true,
27 "requester": "employee@yourcompany.com"
28}`)
29 
30 client := &http.Client {
31 }
32 req, err := http.NewRequest(method, url, payload)
33 
34 if err != nil {
35 fmt.Println(err)
36 return
37 }
38 req.Header.Add("Authorization", "Basic API_KEY:API_SECRET")
39 req.Header.Add("Content-Type", "application/json")
40 
41 res, err := client.Do(req)
42 if err != nil {
43 fmt.Println(err)
44 return
45 }
46 defer res.Body.Close()
47 
48 body, err := ioutil.ReadAll(res.Body)
49 if err != nil {
50 fmt.Println(err)
51 return
52 }
53 fmt.Println(string(body))
54}

JSON body parameter

The body parameter is required. It's the deletion request object listing the user_ids and amplitude_ids for the users to delete.

Name
Description
amplitude_ids Amplitude IDs for the users to delete.
user_ids User IDs for the users to delete.
requester The internal user who requested the deletion. This is useful for auditing.
ignore_invalid_id Boolean. Defaults to false. With false, if any users in the request aren't found in the project, the API returns a 400 error, and it doesn't mark any users in the request for deletion. With true, the response is a 200 success that includes a list of invalid_ids, and the API adds any users found in the relevant project to the relevant job. invalid_ids represent any requested users with no data found in the relevant project. If the parameter delete_from_org is true, this field is automatically set to true, ignoring the input.
delete_from_org Boolean. Defaults to false. By default, the request will only delete the requested users from the project identified by the given API key. When set to true, the requested users are deleted across your entire organization. In doing so, the request will insert the end users into a job for each project that contains data for the requested users. When true, the ignore_invalid_ids parameter is automatically set to true, ignoring the input.
include_mapped_user_ids When true, this parameter returns the valid user_id values that correspond to a supplied amplitude_id. This only changes the response object. To delete mapped users set with the User Mapping API, include each user_id of the mapped user in the user_ids array.

Response

The response for a POST request contains these fields:

Name
Description
day The day the deletion job is scheduled to begin.
status The status of the deletion job.
amplitude_ids and user_ids List of the Amplitude IDs to delete.
app The project or app ID. Included when the deletion request is for multiple projects.
invalid_ids When ignore_invalid_ids is true, contains a list of users that were requested but not found in the projects

The amplitude_ids key contains these fields:

Name
Description
amplitude_id The Amplitude ID of the user to be deleted.
requester The person who requested the Amplitude ID to be deleted.
requested_on_day The day this deletion was requested.
user_id The corresponding User ID. Included when include_mapped_user_ids is true and the amplitude_id are matched to user_ids.

Get deletion jobs

/api/2/deletions/users?start_day=YYYY-MM-DD&end_day=YYYY-MM-DD

Retrieves a list of deletion jobs scheduled in a time range. The time range should include the date you made the request on plus 30 days. For example, you made a deletion request on August 1st, 2018.
Your deletion request should have start_day = 2018-08-01 and end_day = 2018-08-31.

If the request returns no values, then no jobs are scheduled for that time range. Note: The largest permitted time range is six months.

1# You can also use wget
2curl -X GET https://amplitude.com/api/2/deletions/users?start_day=string&end_day=string \
3 -H 'Accept: application/json' \
4 -U API_KEY:API_SECRET

1GET https://amplitude.com/api/2/deletions/users?start_day=string&end_day=string HTTP/1.1
2Host: amplitude.com
3Authorization: Basic API_KEY:API_SECRET
4Accept: application/json

1var headers = {
2 'Accept':'application/json'
3 
4};
5 
6$.ajax({
7 url: 'https://amplitude.com/api/2/deletions/users',
8 method: 'get',
9 data: '?start_day=string&end_day=string',
10 headers: headers,
11 success: function(data) {
12 console.log(JSON.stringify(data));
13 }
14})

1const request = require('node-fetch');
2 
3const headers = {
4 'Accept':'application/json'
5 
6};
7 
8fetch('https://amplitude.com/api/2/deletions/users?start_day=string&end_day=string',
9{
10 method: 'GET',
11 
12 headers: headers
13})
14.then(function(res) {
15 return res.json();
16}).then(function(body) {
17 console.log(body);
18});

1require 'rest-client'
2require 'json'
3 
4headers = {
5 'Accept' => 'application/json'
6}
7 
8result = RestClient.get 'https://amplitude.com/api/2/deletions/users',
9 params: {
10 'start_day' => 'string',
11'end_day' => 'string'
12}, headers: headers
13 
14p JSON.parse(result)

1import requests
2headers = {
3 'Accept': 'application/json'
4}
5 
6r = requests.get('https://amplitude.com/api/2/deletions/users', params={
7 'start_day': 'string', 'end_day': 'string'
8}, headers = headers)
9 
10print r.json()

1URL obj = new URL("https://amplitude.com/api/2/deletions/users?start_day=string&end_day=string");
2HTTPURLConnection con = (HTTPURLConnection) obj.openConnection();
3con.setRequestMethod("GET");
4int responseCode = con.getResponseCode();
5BufferedReader in = new BufferedReader(
6 new InputStreamReader(con.getInputStream()));
7String inputLine;
8StringBuffer response = new StringBuffer();
9while ((inputLine = in.readLine()) != null) {
10 response.append(inputLine);
11}
12in.close();
13System.out.println(response.toString());

1package main
2 
3import (
4 "bytes"
5 "net/http"
6)
7 
8func main() {
9 
10 headers := map[string][]string{
11 "Accept": []string{"application/json"},
12 
13 }
14 
15 data := bytes.NewBuffer([]byte{jsonReq})
16 req, err := http.NewRequest("GET", "https://amplitude.com/api/2/deletions/users", data)
17 req.Header = headers
18 
19 client := &http.Client{}
20 resp, err := client.Do(req)
21 // ...
22}

Query parameters

Name Description
start_day Required. First hour included in data series, formatted YYYY-MM-DD. For example, 20220201.
end_day Required. Last hour included in data series, formatted YYYY-MM-DD For example, 20220201.

Response

The success response for a GET request contains these fields:

Property
Description
day The day the deletion job is scheduled to begin.
status The deletion job's status.

Staging: The job hasn't started, and you can modify it. More deletion requests may get scheduled into this job and you can remove requests from this job.

Submitted: The job is submitted to run. You can't modify it.

Done: The job has finished running. You can't modify it.
amplitude_ids List of the Amplitude Ids of users to delete.
app Project or app ID. Appears if the deletion is applied to more than one project.
active_scrub_done_date The date that the scrub has completed, and the data is no longer accessible. After this point, the system waits 5 days for any backups to be automatically cleared. The status will change to 'done' only when the backups are removed.

The amplitude_ids key contains these fields:

Name
Description
amplitude_id The Amplitude ID of the user to be deleted.
requester The person who requested the Amplitude ID to be deleted.
requested_on_day The day this deletion was requested.
1[
2 {
3 "day": "string",
4 "amplitude_ids": [
5 {
6 "amplitude_id": 0,
7 "requested_on_day": "string",
8 "requester": "string"
9 }
10 ],
11 "status": "string"
12 }
13]

Delete a user from a deletion job

Removes the specified Amplitude ID from a deletion job.

/api/2/deletions/users/AMPLITUDE_ID/YYYY-MM-DD

1curl -X DELETE \
2 'https://amplitude.com/api/2/deletions/users/AMPLITUDE_ID/JOB_START_DAY' \
3 -H 'Content-Type: application/json' \
4 -U API_KEY:API_SECRET

Path variables

Name
Description
AMPLITUDE_ID Required. The amplitude_id to be removed from a deletion job.
JOB_START_DAY Required. Day the deletion is schedule for. YYYY-MM-DD

Response

A successful request returns a response with this schema:

Property
Description
amplitude_id The Amplitude ID of the user that was removed from the job
requester The person who requested the Amplitude ID to be deleted.
requested_on_day The day this deletion was requested.
1{
2 "amplitude_id": 1234567,
3 "requested_on_day": "string",
4 "requester": "string"
5}

Status codes

Code Message
200 Success
400 Bad Request
401 Unauthorized
Was this page helpful?

Thanks for your feedback!

May 21st, 2024

Need help? Contact Support

Visit Amplitude.com

Have a look at the Amplitude Blog

Learn more at Amplitude Academy

© 2024 Amplitude, Inc. All rights reserved. Amplitude is a registered trademark of Amplitude, Inc.