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:
| Param | Type | Description |
|---|---|---|
token | string | Signed unsubscribe token |
mid | string | Message ID (alternative to token) |
channel | string | Specific 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:
- Consent status is set to
OPTED_OUTfor the channel - An audit log entry is created
- 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:
| Param | Type | Description |
|---|---|---|
token | string | Signed preferences token |
contactId | string | Direct 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}/exportReturns 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}/exportRequires 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
Cookie Consent for the Website Script
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):
| Mode | Use when |
|---|---|
required | You run your own cookie banner and will call CampaignOS.consent.grant() yourself. |
cmp | You use OneTrust, Cookiebot, Google Consent Mode or a TCF v2 CMP and want CampaignOS to follow it automatically. |
auto | Default. Tracks unless a TCF/Cookiebot CMP is detected. |
disabled | Consent 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.
Google Consent Mode v2
<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>Recording consent on the contact
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.
Consent Channels
| Channel | Description |
|---|---|
EMAIL | Email communications |
PUSH | Web push notifications |
TELEGRAM | Telegram messages |
ONSITE | On-site modals, banners, toasts |
SMS | SMS messages |
Consent Statuses
| Status | Description |
|---|---|
OPTED_IN | Contact has given consent |
OPTED_OUT | Contact has withdrawn consent |
PENDING | Consent not yet confirmed |
DOUBLE_OPT_IN_PENDING | Awaiting 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.
Automatic Unsubscribe Links
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.