User Deletion and Suppression

In keeping with our commitment to GDPR readiness, we offer the ability to delete and suppress data about end users if they are identified by a userId, should they revoke or alter their consent to data collection. For instance, if an end user in the EU invokes their Right to Object or Right to Erasure under the GDPR, you can use these features to block ongoing data collection about the user and additionally to delete all historical data across Segment’s systems, connected S3 buckets and warehouses, and supported downstream partners.

PLEASE NOTE (Business Plan Customers): If you utilize this functionality to delete data, this means that you will not be able to Replay that data. For standard Replay requests, we ask that you wait for deletions to complete and not submit any new deletion requests for the period of time that we replay data for you.

Overview

All deletion and suppression actions within Segment are asynchronous, and fall under the umbrella of what we call “Regulations.” Regulations are requests to Segment to impart control over your data flow. They can be issued from your Segment Workspace Settings page under End User Privacy.

Regulations enable you to issue a single request to delete and suppress data about a user by userId. All regulations are scoped to your workspace and target all sources within the workspace. This way, you needn’t page over every source within Segment in order to delete data about a user across all your users.

There are currently three valid regulation types:

  • SUPPRESS

  • UNSUPPRESS

  • SUPPRESS_AND_DELETE

SUPPRESS regulations add a user to your suppression list by userId. Suppressed users are blocked across all sources; any message you send to Segment with a suppressed userId will be blocked at our API. These messages will not surface in the debugger, nor propagate to our archives and systems or any downstream server-side destinations. Suppression does not affect device-mode destinations.

Moreover, typically when a customer exercises their right to erasure, they also expect that you will no longer collect data about them. Suppression can help ensure that regardless of the channel or application from which you’re sending data to Segment, if a user opts out, that their wishes are respected on an ongoing basis and across applications.

Suppression is not a substitute for gathering affirmative, unambiguous consent about data collection and its uses. Segment offers suppression to help you manage the challenge of opting out a user across multiple channels and platforms, but we encourage and expect that you architect your systems and applications so that you do not collect or forward data to Segment until you have gathered unambiguous, specific, informed consent or established another lawful legal basis to do so.

When you create an UNSUPPRESSION regulation, we will remove the user from the suppression list.

Deletion Support and the Right to Be Forgotten

When you create a SUPPRESS_AND_DELETE regulation, once the user is actively suppressed, Segment will begin the process of permanently deleting all data pertaining to this user from your workspace. This includes scanning and removing all messages keyed by that userId from all storage mediums that don’t automatically expire data within 30 days, including archives, databases, and intermediary stores.

Messages keyed by this userId will also be deleted from your connected raw data Destinations, including Redshift, BigQuery, Postgres, Snowflake and Amazon S3. Warehouse deletions happen via DML run against your cluster or instance, and S3 deletions are achieved by “recopying” cleaned versions of any files in your bucket that had data pertaining to that userId.

Finally, we will also forward these deletion requests to a growing list of supported partners.

Segment cannot guarantee that data is deleted from your Destinations.

We will forward the deletion request to supported streaming Destinations (such as Braze, Intercom, and Amplitude, but you will need to reach out to each partner directly to confirm the request was fulfilled.

You will also need to work with unsupported Destinations separately to manage user data deletion.

Note that if you subsequently UNSUPPRESS a user, the deletion functionality will not cleanup data sent after removing the user from the suppression list.

UI Walkthrough

Suppressed Users

The Suppressed Users tab shows an up-to-date list of actively suppressed userIds. Data about these users will be blocked across all sources.

To create a suppression regulation and add a userId to this list, click the “Add User” button. You’ll be prompted for the userId on following form.

Under the hood, this creates a SUPPRESS regulation; this userId will be added to your suppression list within 24 hours.

To remove someone from the suppression list, simply click the actions icon on the associated userId row, and choose “Remove.”

Under the hood, this creates an UNSUPPRESS regulation; this userId will be removed from your suppression list, allowing data to flow again, within 24 hours.

Deletion Requests

The deletion requests pane shows a log of all regulations with a deletion element along with their status, so that you can understand the status of a deletion.

You can drill down on individual deletions to view the status of the deletion across Segment and your connected destinations.

Programmatic User Deletion and Suppression via API

NOTE: If you have the Amplitude destination enabled in one or more sources, you’ll need to include Amplitude’s secret key in each source(s) settings since they require this key to accept the deletion request we send to them (add it under the “Secret Key” setting of the Amplitude destination). You can find your Secret Key on the General Settings of your Amplitude project.

Regulate User from all Sources in Workspace

In order to create a regulation programmatically, you issue a GraphQL mutation via POST to https://gdpr.segment.com/graphql

mutation {
  createWorkspaceRegulation(
    workspaceSlug: "workspace-slug"
    type: SUPPRESS | UNSUPPRESS | SUPPRESS_AND_DELETE
    userId: "userIdToDelete"
  ) {
    id
  }
}

As you can see, there are three fields in the mutation input:

Field NameTypeDescription
workspaceSlugString (required)Your workspace slug. You can find this by looking at the url path of your workspace.
userIdString(required)The target user’s userId.
typeEnum (required; all caps, no quotes)The regulation type. Can be SUPPRESS, UNSUPPRESS, or SUPPRESS_AND_DELETE

And one in the mutation output:

Field NameTypeDescription
idString(required)The regulation ID. You can use this to identify the regulation or check its status.

This will create a regulation on user with userId your entire workspace.

Regulate User from a single Source in a Workspace

Similarly, if you want to suppress a user only on a single source, send a POST to:

mutation {
createSourceRegulation( workspaceSlug: "workspace-slug" sourceSlug: "source-slug" type: SUPPRESS | UNSUPPRESS | SUPPRESS_AND_DELETE userId: "userIdToDelete" ) { id } }
Field NameTypeDescription
workspaceSlugString (required)Your workspace slug. You can find this by looking at the url path of your workspace.
sourceSlugString (required)Your source slug. You can find this by looking at the url path of your source.
userIdString(required)The target user’s userId.
typeEnum (required; all caps, no quotes)The regulation type. Can be SUPPRESS, UNSUPPRESS, or SUPPRESS_AND_DELETE

Now, only the source corresponding with source-slug will regulate user with userId

Delete Object from a Cloud Source

Cloud Sources sync objects to Segment. As a result, Cloud Sources are regulated based on an objectId instead of a userId. To remove an object from a cloud source, send a POST to:

mutation {
createSourceObjectDeletion( workspaceSlug: "workspace-slug" sourceSlug: "source-slug" collection: "source-collection" objectId: "objectIdToDelete" ) { id } }
Field NameTypeDescription
workspaceSlugString (required)Your workspace slug. You can find this by looking at the url path of your workspace.
sourceSlugString (required)Your source slug. You can find this by looking at the url path of your source.
objectIdString(required)The target objects objectId
collectionString(required)The collection to which this object belongs

Note, this will not suppress the object from being pulled in via the Cloud Source. Before you delete the object from Segment, you should delete it from the upstream system first.

List Suppressed Users for your Workspace

List the actively suppressed users for your workspace.

query {
suppressedUsers(workspaceSlug: "workspace-slug", cursor: { limit: 20 }) { data { userId } cursor { hasMore next limit } } }
Field NameTypeDescription
workspaceSlugString (required)Your workspace slug. You can find this by looking at the url path of your workspace.
cursorObject (optional)Cursor is used for pagination. By default, lists the first 20 results. Use the next property returned by the GraphQL response to continue to the next page of results.

List Deletion Requests for your Workspace

List the all the deletion requests you have sent to Segment for a given workspace. The below query will return both the userId and status of the deletion request.

query {
deletionRequests(workspaceSlug: "workspace-slug", cursor: { limit: 20 }) { data { userId status } cursor { hasMore next limit } } }
Field NameTypeDescription
workspaceSlugString (required)Your workspace slug. You can find this by looking at the url path of your workspace.
cursorObject (optional)Cursor is used for pagination. By default, lists the first 20 results. Use the next property returned by the GraphQL response to continue to the next page of results.

Making requests with GraphQL

GraphQL requests are POST requests with JSON payloads. The query of mutation is sent in the body of the request Here’s how that might look with cURL:

curl \
  -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <Access Token>" \
  –data '{"query":"mutation {createWorkspaceRegulation(workspaceSlug:\"<workspace-slug>\" type:SUPPRESS_AND_DELETE userId:\"<userIdToDelete>\") { id }}"}' \
  https://gdpr.segment.com/graphql

Here’s how it might look using a generic HTTP request library:

require('isomorphic-fetch');

fetch('https://gdpr.segment.com/graphql&#39;, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ query: mutation {
    createWorkspaceRegulation(
      workspaceSlug: &quot;workspace-slug&quot;
      type: SUPPRESS_AND_DELETE
      userId: &quot;userIdToDelete&quot;
    ) {
      id
    }
  }
  }),
})
  .then(res => res.json())
  .then(res => console.log(res.data));

We recommend using a library purpose built for making GraphQL requests. For example, in node.js, we recommend apollo-fetch.

const fetch = createApolloFetch({
 uri: 'https://gdpr.segment.com/graphql&#39;
})

fetch({
 query: mutation {
   createWorkspaceRegulation(
     workspaceSlug: &quot;workspace-slug&quot;
     type: SUPPRESS_AND_DELETE
     userId: &quot;user_id&quot;
   ) {
     id
   }
 }
}).then(res => {
 console.log(res.data);
})

Please note that any other queries or mutations exposed by gdpr.segment.com are not officially public, and as such we have not made any commitments or guarantees around their stability or longevity. We do not recommend building functionality against this undocumented queries or mutations on this API, as they are not officially supported and will change without notice.If you’re interested in programmatic access to your workspace, we ask that you get in touch separately! We are actively exploring how best to evolve our APIs to support your needs.

Authentication

The mutation above requires a valid access token in the Authorization request header, which you can generate using the credentials of any workspace owner.

In order to fetch an access token, you simply issue a mutation like the one above with the following structure:

mutation auth($email:String!, $password:String!) {
  login(email:$email, password:$password)
}

The access token will be returned in the JSON payload at data.login.access_token

IMPORTANT:Access tokens are short-lived, so we recommend prefacing every attempt to create a regulation with a fresh login.

Note that your Segment password should always be kept secret. It’s imperative that you treat it as a privileged secret in your program. We recommend using something like AWS Secrets Manager or Chamber to securely store, encrypt, and decrypt your password on program or request handler invocation. Regulation creation should never be attempted from the browser or a client application, as you would expose this secret.

Once you have your access token, include it in the Authorization header with the prefix “Bearer ".

Here’s a full bash example of authenticating and making a deletion request:

token=$(curl -X POST -H "Content-Type: application/json" -d '{"query": "mutation auth($email:String!, $password:String!) {login(email:$email, password:$password)}", "variables": {"email": "<your_email>", "password": "your_password"}}' https://gdpr.segment.com/graphql | jq -r '.data.login.access_token')

curl -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $token" \
  -d '{"query":"mutation {createWorkspaceRegulation(workspaceSlug:\"<slug>\" type:SUPPRESS_AND_DELETE userId:\"<userId>\") { id }}"}' \
  https://gdpr.segment.com/graphql

Putting it all together, here’s an example internal microservice that you could deploy with next or up, both of which offer modest paid plans with encrypted environment variables for secrets. You could invoke this service at /deleteUserFromSegment

const { createApolloFetch } = require("apollo-fetch");
const express = require("express");
const { PORT = 3000 } = process.env;

const app = express();
const fetchMiddleware = function(req, res, next) {
  req.fetch = createApolloFetch({
    uri: "https://gdpr.segment.com/graphql&quot;
  });
  next();
};

const loginMiddleware = async function(req, res, next) {
  const response = await fetch({
    query: mutation Login($email: String!, $password: String!) {
                login(email:$email, password:$password)
              },
    variables: {
      email: process.env.SEG_USER, 
      password: process.env.SEG_PW // secret
    }
  })

  const token = response.data.login.access_token

  req.fetch.use(({ request, options }, cb) => {
    if (!options.headers) {
      options.headers = {};
    }

    options.headers["Authorization"] = Bearer ${token};

    cb()
  })

  next()
}

app.get("/deleteUserFromSegment/:userId", login, function(req, res) {
  const delete = req
    .fetch({
      query: mutation {
          createWorkspaceRegulation(
            workspaceSlug: &quot;workspace-slug&quot;
            type: SUPPRESS_AND_DELETE
            userId: ${req.params.userId}
          ) { id }
        }
    })
    .then(del => {
      console.log(del)
    });

  res.send("Success")
});

app.listen(PORT)

Frequently Asked Questions

How can I find my user’s userId?

The easiest way to resolve a customer’s userId is by querying an existing tool. Specifically, you can use your Segment data warehouse to query for a userId by any other field on the user in the users table!

Can I create a regulation for a single source?

Not yet. Currently, all regulations are workspace scoped. If this is a requirement for you, please let us know!

I need more fine grained deletion / suppression / anonymization capabilities.

The features and functionality above represent the first release of Segment’s efforts pertaining to end user data privacy. We’d love your input on how this functionality could be improved to suit your needs in light of GDPR and in light of our shared commitment and responsibility to earn the trust and honor the privacy of your end users. Please don’t hesitate to get in touch!


If you have any questions or see anywhere we can improve our documentation, please let us know or kick off a conversation in the Segment Community!