Skip to main contentSkip to Content
Compliance & Privacy

Compliance & Privacy

CampaignOS provides built-in tools for managing consent, unsubscription, and data subject requests.

Unsubscribe

GET /api/unsubscribe

One-click unsubscribe via token or message ID.

Auth: None required

Query Parameters:

ParamTypeDescription
tokenstringSigned unsubscribe token
midstringMessage ID (alternative to token)
channelstringSpecific channel to unsubscribe from

Response:

{ "success": true, "message": "You have been unsubscribed" }

POST /api/unsubscribe

Same as GET but accepts parameters in the request body.

Request Body:

{ "token": "abc123...", "messageId": "msg_abc123", "channel": "EMAIL" }

When a contact unsubscribes:

  1. Consent status is set to OPTED_OUT for the channel
  2. An audit log entry is created
  3. Future sends are immediately suppressed

Preference Center

GET /api/preferences

Returns the contact’s current channel preferences.

Auth: Token-based (no session required)

Query Parameters:

ParamTypeDescription
tokenstringSigned preferences token
contactIdstringDirect contact ID (alternative)

Response:

{ "contact": { "id": "ct_abc123", "email": "jane@example.com", "firstName": "Jane", "lastName": "Smith" }, "preferences": [ { "channel": "EMAIL", "status": "OPTED_IN" }, { "channel": "PUSH", "status": "OPTED_IN" }, { "channel": "TELEGRAM", "status": "OPTED_OUT" }, { "channel": "ONSITE", "status": "OPTED_IN" } ] }

PUT /api/preferences

Updates channel preferences.

Query Parameters: Same as GET (token or contactId)

Request Body:

{ "preferences": [ { "channel": "EMAIL", "status": "OPTED_IN" }, { "channel": "PUSH", "status": "OPTED_OUT" }, { "channel": "TELEGRAM", "status": "OPTED_OUT" } ] }

Data Subject Requests (DSR)

Export My Data

GET /api/workspaces/{workspaceId}/contacts/{contactId}/export

Returns a complete data export for a contact including identities, consents, tags, events, messages, segment memberships, campaign enrollments, push subscriptions, and inbox threads.

Forget Me (Right to Erasure)

POST /api/workspaces/{workspaceId}/contacts/{contactId}/export

Requires ADMIN role.

Anonymizes the contact:

  • Nulls all PII fields (name, email, phone)
  • Deletes identities and push subscriptions
  • Marks contact as anonymized
  • Logs an audit event

campaignos.js supports a consent gate so that no behavioural data leaves the browser before the visitor agrees. Pick the mode with the consent query parameter (see Website Script for the full reference):

ModeUse when
requiredYou run your own cookie banner and will call CampaignOS.consent.grant() yourself.
cmpYou use OneTrust, Cookiebot, Google Consent Mode or a TCF v2 CMP and want CampaignOS to follow it automatically.
autoDefault. Tracks unless a TCF/Cookiebot CMP is detected.
disabledConsent is not required in your jurisdiction.

While consent is pending the script buffers up to 50 events in memory (nothing is persisted) and sends them, with their original timestamps, once consent is granted. Revoking consent drops the buffer, closes the real-time stream and stops all further tracking. The decision is stored in localStorage as cos_consent.

OneTrust

<script src="https://cdn.cookielaw.org/scripttemplates/otSDKStub.js" data-domain-script="YOUR-ONETRUST-ID"></script> <script src="https://your-campaignos-domain.com/campaignos.js?workspace=your-slug&consent=cmp" async></script>

CampaignOS wraps OptanonWrapper (your own wrapper still runs) and re-evaluates on OneTrustGroupsUpdated. Analytics is group C0002; add consent-category=marketing to key off C0004 instead.

Cookiebot

<script id="Cookiebot" src="https://consent.cookiebot.com/uc.js" data-cbid="YOUR-CBID" data-blockingmode="auto"></script> <script src="https://your-campaignos-domain.com/campaignos.js?workspace=your-slug&consent=cmp" async></script>

Consent is granted when Cookiebot.consent.statistics is true (or .marketing with consent-category=marketing). If you use Cookiebot’s automatic blocking mode, mark the CampaignOS tag with data-cookieconsent="statistics" and type="text/plain" so Cookiebot unblocks it after consent.

<script> window.dataLayer = window.dataLayer || []; function gtag(){ dataLayer.push(arguments); } gtag("consent", "default", { analytics_storage: "denied", ad_storage: "denied" }); </script> <script src="https://your-campaignos-domain.com/campaignos.js?workspace=your-slug&consent=cmp" async></script> <script> // called by your banner function onAccept() { gtag("consent", "update", { analytics_storage: "granted", ad_storage: "granted" }); } </script>

CampaignOS reads the last consent default / consent update entry in dataLayer and follows every later update (analytics_storage, or ad_storage with consent-category=marketing).

Custom banner

<script src="https://your-campaignos-domain.com/campaignos.js?workspace=your-slug&consent=required" async></script> <script> function onBannerAccept() { CampaignOS.consent.grant(); } function onBannerReject() { CampaignOS.consent.revoke(); } function onOpenPreferences() { console.log(CampaignOS.consent.status()); } </script>

Website consent controls whether tracking events are sent; it does not change the contact’s channel consents (EMAIL, PUSH, …). Record marketing permissions explicitly through forms with double opt-in, the preference center, or PUT /api/workspaces/{workspaceId}/contacts/{contactId}/consent. Every change is written to the consent history and shown on the contact timeline.


ChannelDescription
EMAILEmail communications
PUSHWeb push notifications
TELEGRAMTelegram messages
ONSITEOn-site modals, banners, toasts
SMSSMS messages
StatusDescription
OPTED_INContact has given consent
OPTED_OUTContact has withdrawn consent
PENDINGConsent not yet confirmed
DOUBLE_OPT_IN_PENDINGAwaiting double opt-in confirmation

An email opt-out stops marketing emails only. Transactional emails (password resets, receipts, inbox replies) are still sent; see Email types.

Every email message automatically includes:

  • A one-click unsubscribe link ({{unsubscribeUrl}})
  • A link to the preference center ({{preferencesUrl}})

These are injected as personalization tokens during template rendering.

Last updated on