Consent or Pay¶
Overview¶
Consent or Pay (PUR) is a first-layer banner model for publishers using the PUR pricing model. Instead of only offering "Accept All" / "Deny All", the banner presents the user with a choice: consent to data processing, or subscribe/pay to access the content without giving consent. Users who already have a subscription can log in instead.
Usercentrics does not process payments and does not manage subscriber state. The SDK is only responsible for:
- Displaying the "Reject & Subscribe" card and the subscriber-login link on the first layer, using copy and URLs configured in the Admin UI
- Notifying your app when the user taps either action, via two dedicated callbacks
- Clearing stored TCF consent data once your app confirms the login or subscription succeeded
Everything else — checking whether a device/session already has a valid subscription, performing the login or checkout flow, and dismissing the banner afterwards — is your app's responsibility.
Banner Display Logic¶
The SDK has no knowledge of your subscriber or login state, so it cannot decide on its own whether the banner should be shown. Your app must perform this check itself before calling showFirstLayer.
Show the banner only when both of the following are true:
shouldCollectConsentreturnstruefrom the SDK- The user is not simultaneously logged in and subscribed
shouldCollectConsent | Logged in + subscribed | Show banner? |
|---|---|---|
true | No | ✅ Show |
true | Yes | ❌ Do not show |
false | No | ❌ Do not show |
false | Yes | ❌ Do not show |
Do not re-prompt after a successful login or subscription
Once a user has logged in or subscribed, do not show the first layer again for that session. The user has already provided payment as an alternative to consent, and a deny decision has already been stored — re-prompting at this point would be incorrect and manipulative.
Handling Login and Subscribe Actions¶
showFirstLayer accepts two optional callbacks, onLoginClicked and onSubscribeClicked, fired when the user taps the subscriber-login link or the "Reject & Subscribe" button respectively. Each callback receives the corresponding URL if one was configured in the Admin UI for that settings ID, or null if none was configured — in which case your app is responsible for deciding where to navigate.
The banner does not dismiss itself
Tapping either action does not close the banner. Your app must call the appropriate dismiss/close API once it has handled the action — see Signaling Success below.
UsercentricsBanner(activity, bannerSettings).showFirstLayer(
callback = { response ->
// Standard consent flow — Accept All, Deny All, granular save
},
onLoginClicked = { loginUrl ->
// Navigate to your login flow, using loginUrl if configured
},
onSubscribeClicked = { subscribeUrl ->
// Navigate to your subscription/checkout flow, using subscribeUrl if configured
},
)
UsercentricsBanner(bannerSettings: bannerSettings).showFirstLayer(
onLoginClicked: { loginUrl in
// Navigate to your login flow, using loginUrl if configured
},
onSubscribeClicked: { subscribeUrl in
// Navigate to your subscription/checkout flow, using subscribeUrl if configured
},
completionHandler: { response in
// Standard consent flow — Accept All, Deny All, granular save
}
)
Usercentrics.onLoginClicked.listen((loginUrl) {
// Navigate to your login flow, using loginUrl if configured
});
Usercentrics.onSubscribeClicked.listen((subscribeUrl) {
// Navigate to your subscription/checkout flow, using subscribeUrl if configured
});
final response = await Usercentrics.showFirstLayer();
import { Usercentrics } from '@usercentrics/react-native-sdk';
Usercentrics.onLoginClicked((loginUrl) => {
// Navigate to your login flow, using loginUrl if configured
});
Usercentrics.onSubscribeClicked((subscribeUrl) => {
// Navigate to your subscription/checkout flow, using subscribeUrl if configured
});
const response = await Usercentrics.showFirstLayer();
Usercentrics.Instance.ShowFirstLayer(
(response) => {
// Standard consent flow — Accept All, Deny All, granular save
},
(loginUrl) => {
// Navigate to your login flow, using loginUrl if configured
},
(subscribeUrl) => {
// Navigate to your subscription/checkout flow, using subscribeUrl if configured
}
);
Signaling Success Back to the SDK¶
Once your app has completed the login or subscription flow, call the matching notify*Success method so the SDK can clear stored TCF consent data — the login/subscribe action is treated as an implicit deny decision, so ad partners should no longer receive a consent signal for this user.
Scope of the storage clearing
Only TCF data (e.g. IABTCF_* keys) is cleared. Session, CCPA, and controller-ID data are left untouched — this is a lighter operation than Clear User Session, which resets everything.
// After a successful login:
Usercentrics.instance.notifyLoginSuccess({
// TCF data cleared — now dismiss the banner
}, { error ->
// Handle non-localized error
})
// After a successful subscription:
Usercentrics.instance.notifySubscribeSuccess({
// TCF data cleared — now dismiss the banner
}, { error ->
// Handle non-localized error
})
// After a successful login:
UsercentricsCore.shared.notifyLoginSuccess(onSuccess: {
// TCF data cleared — now dismiss the banner
}, onError: { error in
// Handle non-localized error
})
// After a successful subscription:
UsercentricsCore.shared.notifySubscribeSuccess(onSuccess: {
// TCF data cleared — now dismiss the banner
}, onError: { error in
// Handle non-localized error
})
// After a successful login:
await Usercentrics.notifyLoginSuccess();
// TCF data cleared — now dismiss the banner
// After a successful subscription:
await Usercentrics.notifySubscribeSuccess();
// TCF data cleared — now dismiss the banner
// After a successful login:
await Usercentrics.notifyLoginSuccess();
// TCF data cleared — now dismiss the banner
// After a successful subscription:
await Usercentrics.notifySubscribeSuccess();
// TCF data cleared — now dismiss the banner
// After a successful login:
Usercentrics.Instance.NotifyLoginSuccess(() => {
// TCF data cleared — now dismiss the banner
}, (errorString) => {
// Handle non-localized error
});
// After a successful subscription:
Usercentrics.Instance.NotifySubscribeSuccess(() => {
// TCF data cleared — now dismiss the banner
}, (errorString) => {
// Handle non-localized error
});
Dismissing the Banner¶
Neither tapping the login/subscribe action nor calling notifyLoginSuccess/notifySubscribeSuccess closes the banner automatically. Your app must dismiss it explicitly — typically right after the success signal above completes — using your platform's normal navigation/dismiss mechanism for however you presented the banner. If your app does not dismiss it, the banner remains visible indefinitely.
Handling a Lapsed Subscription¶
Usercentrics does not manage subscriber state, so it has no way to detect on its own when a user's subscription ends or is cancelled. Once your app detects this (e.g. from your billing provider's webhook or SDK), call notifySubscriptionLapsed so the SDK stops treating the user as an active Consent-or-Pay subscriber.
This does not change any existing consent decision
notifySubscriptionLapsed only resets the subscriber flag, so your app knows to re-run the Banner Display Logic check and show the first layer again. It does not clear TCF consent storage — whatever the user previously consented to (or was recorded as denying) remains accurate and unchanged, since a lapsed subscription doesn't retroactively alter what they agreed to.
Usercentrics.instance.notifySubscriptionLapsed({
// Subscriber flag reset — re-check Banner Display Logic and show the banner if needed
}, { error ->
// Handle non-localized error
})
UsercentricsCore.shared.notifySubscriptionLapsed(onSuccess: {
// Subscriber flag reset — re-check Banner Display Logic and show the banner if needed
}, onError: { error in
// Handle non-localized error
})
await Usercentrics.notifySubscriptionLapsed();
// Subscriber flag reset — re-check Banner Display Logic and show the banner if needed
await Usercentrics.notifySubscriptionLapsed();
// Subscriber flag reset — re-check Banner Display Logic and show the banner if needed
Usercentrics.Instance.NotifySubscriptionLapsed(() => {
// Subscriber flag reset — re-check Banner Display Logic and show the banner if needed
}, (errorString) => {
// Handle non-localized error
});
TCF Signal on Rejection¶
By default, a subscribed user who rejects consent via the second-layer Deny All is treated the same as a successful login/subscription: no "no consent" TCF signal is stored for them, matching the behavior described in Signaling Success Back to the SDK.
Publishers who instead want a "no consent" TC string recorded for this case can request that their settings ID be configured with includeTcfSignalForRejectedUsers disabled via the Admin UI. This has no effect unless Consent or Pay is enabled for the settings ID, and does not change behavior for users who are not active COP subscribers.
Best Practices¶
Perform the visibility check on every launch, not just once¶
Since login/subscription state can change outside your app's control (e.g. a subscription lapsing — see Handling a Lapsed Subscription), re-evaluate the Banner Display Logic table each time you would otherwise show the first layer — don't cache the "already handled" decision indefinitely.
Treat the login/subscribe URL as optional¶
Always check for null before using the URL passed to onLoginClicked/onSubscribeClicked. If no URL was configured for the settings ID in use, fall back to your app's own login/subscription entry point.