> For the complete documentation index, see [llms.txt](https://documentation.pushly.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://documentation.pushly.com/integration/web-push/sdk/consent-and-privacy.md).

# Consent & Privacy

The SDK gives you two kinds of privacy control: reporting the visitor's consent from your consent management platform (CMP), and acting on the visitor's own requests to opt out or have their data deleted. This page covers both, with recipes for common consent platforms.

## Privacy Controls at a Glance

The SDK offers four privacy controls, and [Pushly's Privacy API](https://developers.pushly.com/reference/using-the-subscribers-api) offers a fifth. They do different things, so pick the one that matches the visitor's request.

| The visitor wants to…                          | Use                                                                                                                   | Can it be undone?                | What happens to their data                                        |
| ---------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | -------------------------------- | ----------------------------------------------------------------- |
| Answer your consent banner                     | [`consent`](#reporting-consent-from-a-consent-management-platform)                                                    | Yes, report `granted`            | Kept; nothing new is collected while consent is pending or denied |
| Stop receiving notifications for a while       | [`pause_notifications`](/integration/web-push/sdk/methods.md#pausing-resuming-a-users-notifications-soft-unsubscribe) | Yes, with `resume_notifications` | Kept; tracking continues                                          |
| Withdraw consent to notifications and tracking | [`opt_out`](/integration/web-push/sdk/methods.md#opting-a-visitor-out)                                                | Yes, with `opt_in`               | Kept; nothing new is collected                                    |
| Have their data deleted, from your site        | [`request_user_deletion`](/integration/web-push/sdk/methods.md#deleting-a-visitors-data)                              | No                               | Erased                                                            |
| Have their data deleted, as a known user       | [Pushly's Privacy API](https://developers.pushly.com/reference/using-the-subscribers-api)                             | No                               | Erased                                                            |

## Reporting Consent from a Consent Management Platform

If your site uses a consent management platform (CMP), report the visitor's consent with the `consent` option on every page, and report each change with the `consent` command. The SDK then waits, withdraws or loads before it starts anything.

{% hint style="warning" %}
Requires web SDK 3.8.0 or later.
{% endhint %}

Put `consent` in the `load` call of your snippet, so it reaches the SDK before the SDK starts:

```javascript
<script src="https://cdn.p-n.io/sdk/web/latest/pushly-sdk.min.js?domain_key=SDK_KEY" async></script>
<script>
  var PushlySDK = window.PushlySDK || [];
  function pushly() { PushlySDK.push(arguments) }
  pushly('load', {
    domainKey: 'DOMAIN_KEY',
    consent: 'pending' // the visitor has not answered your banner yet
  });
</script>
```

When your CMP answers, or the visitor changes their choice, report it:

```javascript
pushly('consent', 'granted'); // or 'denied'
```

| Value     | What the SDK does                                                                                                                                                                                                                                                      |
| --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `pending` | Waits. Nothing is started or sent, and an existing subscription is left alone. Your other commands are held until consent is reported.                                                                                                                                 |
| `granted` | Loads normally. If the visitor was opted out because consent was denied earlier, that is undone, and a browser that still allows notifications is subscribed again automatically.                                                                                      |
| `denied`  | Before starting anything, removes the visitor's push subscription and tells Pushly they opted out, exactly as `opt_out` does. A visitor with nothing to withdraw sends nothing at all. Events and an external ID stored on the device by an earlier visit are cleared. |
| not set   | No consent handling: the SDK behaves as it always has.                                                                                                                                                                                                                 |

Use `'pending'` until your CMP has answered. Don't report `'denied'` for a visitor who simply hasn't answered yet: that withdraws their subscription.

## Consent Platform Recipes

Each recipe keeps the snippet's `load` at `consent: 'pending'` and reports the answer with the `consent` command once your CMP has one. If your CMP never answers — for example because an ad blocker stops it loading — the SDK stays waiting, which keeps the visitor's data untouched.

{% hint style="warning" %}
Which categories or purposes count as consent for push notifications and tracking is your organization's decision. Adjust the checks below to match your consent policy before going live.
{% endhint %}

### IAB TCF (`__tcfapi`)

Most CMPs that support the IAB Transparency & Consent Framework v2, including OneTrust, Didomi and Sourcepoint, expose `__tcfapi`. Listen for its events and report consent once the visitor's choice is known:

```javascript
if (typeof window.__tcfapi === 'function') {
  window.__tcfapi('addEventListener', 2, function (tcData, success) {
    if (!success) return;

    // 'cmpuishown' means the banner is showing and the visitor hasn't answered yet: stay pending.
    if (tcData.eventStatus !== 'tcloaded' && tcData.eventStatus !== 'useractioncomplete') return;

    // Purpose 1: store and/or access information on a device.
    var granted = !!(tcData.purpose && tcData.purpose.consents && tcData.purpose.consents[1]);

    pushly('consent', granted ? 'granted' : 'denied');
  });
}
```

If your CMP lists Pushly as a vendor, also check the vendor's consent, `tcData.vendor.consents[VENDOR_ID]`, before reporting `'granted'`. Where GDPR doesn't apply to the visitor, `tcData.gdprApplies` is `false`; decide whether your policy treats that as consent.

### OneTrust

OneTrust calls `OptanonWrapper` when its script loads and again whenever the visitor saves their choices. Report consent only once the visitor has answered the banner:

```javascript
var previousOptanonWrapper = window.OptanonWrapper;

window.OptanonWrapper = function () {
  if (typeof previousOptanonWrapper === 'function') previousOptanonWrapper();

  // Until the visitor answers the banner, stay pending.
  if (!window.OneTrust || !window.OneTrust.IsAlertBoxClosed()) return;

  // Replace C0004 with the OneTrust category your Pushly integration belongs to.
  var activeGroups = (window.OnetrustActiveGroups || '').split(',');

  pushly('consent', activeGroups.indexOf('C0004') !== -1 ? 'granted' : 'denied');
};
```

### Global Privacy Control

A browser that sends the [Global Privacy Control](https://globalprivacycontrol.org/) signal sets `navigator.globalPrivacyControl` to `true`. If your site treats that as an opt-out, report `'denied'` in the snippet itself, and keep it denied whatever your CMP reports:

```javascript
var globalPrivacyControl = navigator.globalPrivacyControl === true;

pushly('load', {
  domainKey: 'DOMAIN_KEY',
  consent: globalPrivacyControl ? 'denied' : 'pending'
});

// In your CMP callback:
// pushly('consent', globalPrivacyControl || !granted ? 'denied' : 'granted');
```

## Deletion Links

A page opened with `pushly_udr` in its address (for example `https://example.com/?pushly_udr`) requests deletion for that browser, exactly as [`request_user_deletion`](/integration/web-push/sdk/methods.md#deleting-a-visitors-data) does. It works whatever consent the page reports.

{% hint style="warning" %}
Erasure can't be undone. A `pushly_udr` link pasted into a newsletter or a shared page erases the data of every reader who opens it. If your site doesn't use the link, turn it off.
{% endhint %}

To turn the link off, set `disableUserDeletionUrlTrigger` when loading the SDK. `request_user_deletion` keeps working from code either way.

```javascript
pushly('load', {
  domainKey: 'DOMAIN_KEY',
  disableUserDeletionUrlTrigger: true
});
```

{% hint style="info" %}
For how to call `opt_out`, `opt_in` and `request_user_deletion` directly, see [SDK Methods](/integration/web-push/sdk/methods.md).
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://documentation.pushly.com/integration/web-push/sdk/consent-and-privacy.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
