Age-Based Consent

This page provides context on how to implement an age-based consent solution for the OneTrust iOS/tvOS SDK.

1. Overview

Age-Based Consent (also called "Age Gate") enables automatic consent enforcement based on a user's age range. Administrators configure age range groups (e.g., 0-13, 14-17, 18+) in the OneTrust admin console and link them to specific purposes or purpose groups. When a user falls within a restricted age range, consent for the linked purposes is automatically denied and the user cannot override this restriction.

How It Works

  1. Admin configures restricted age range groups in the OneTrust admin console and links purposes/purpose groups to them.
  2. Your application provides the user's age range to the SDK via a delegate/callback.
  3. The SDK sends the age range to the CMP API, which evaluates it against the configured restrictions.
  4. The SDK reflects the restrictions in the consent UI (Preference Center) and public APIs.

Key Concepts

ConceptDescription
Age RangeA lower and upper bound representing the user's age (e.g., 13-17). Both bounds are optional. To represent "18+" (adults), set lowerBound = 18 and leave upperBound nil. The SDK validates that at least one bound is provided before sending to the server.
Restricted Age GroupAn age range configured in the admin console and linked to one or more purposes. Users whose age range overlaps are restricted.
Restricted PurposeA purpose linked to an age group. When the user is restricted, consent is denied and the toggle is disabled.
AGEGATE_RANGEThe CMP API interaction type used to log and enforce age-based consent restrictions.

What Age-Based Consent Does NOT Do

  • It does not determine the user's age. Your application must provide this data.
  • It does not use platform-level APIs (e.g., Apple's DeclaredAgeRange, Android AccountManager) as a source.
  • It does not change the existing Age Gate prompt UI or getAgeGatePromptValue() API -- these are independent features (see Appendix).

Supported SDKs

The implementation pattern is the same across all OneTrust SDKs. The delegate/callback name and language syntax differ, but the feature behavior is identical:

SDKLanguageDelegate/Callback
Apple (iOS/tvOS)Swift / Objective-CCustomConfigurator.getProfileAgeRange(for:completion:)
AndroidKotlin / JavaOTCustomConfigurator.getProfileAgeRange(profileID, callback)
MAUIC#Equivalent CustomConfigurator implementation
UnityC#Equivalent CustomConfigurator implementation
CTV (HTML5)JavaScriptEquivalent configurator callback
RokuBrightScriptEquivalent configurator callback
Hybrid (React Native, Flutter, Cordova)Bridge to nativeWraps the native SDK's CustomConfigurator

Note: This guide uses Apple (Swift) and Android (Kotlin) code snippets as examples. The concepts apply identically to all SDKs listed above.


2. Prerequisites

Before implementing Age-Based Consent, ensure:

Admin Console Configuration

  • Age range groups are configured in the OneTrust admin console (under the Age Gate section).
  • Purpose groups/categories are linked to the appropriate age range groups.
  • The Age Gate feature flag is enabled for your organization.

SDK Version

  • Apple (iOS/tvOS): 202608.1.0 or later (Phase 2 enhancements require 202610.1.0+).
  • Android: equivalent version supporting Age Gate.
  • Other SDKs: check the respective changelog for Age Gate support.

CMP API Flow

  • Your application must be using the CMP API flow (not the legacy mobile-data flow).
  • Age-Based Consent is not supported in the legacy flow.

Age Gate Prompt is NOT Required

  • Age range enforcement works independently of the Age Gate prompt. You do not need to enable the prompt UI to use age range-based enforcement.
  • If you already have an age signal from your application (e.g., from user registration or login), you can use it directly.

3. Implementation

Step 1: Define Your Age Range Provider

Implement the age range delegate/callback in your application. The SDK calls this method automatically during initialization (startSDK) and whenever checkAndLogConsent is invoked for the .ageGate permission type.

Apple (Swift)

import OTPublishersHeadlessSDK
class MyAppConfigurator: CustomConfigurator {
    func getProfileAgeRange(
        for profileID: String,
        completion: @escaping (ProfileAgeRange?) -> Void
    ) {
        // Retrieve the user's age range from your application's user profile system.
        // This supports asynchronous operations (e.g., network calls, database lookups).
        guard let user = UserService.getUser(by: profileID) else {
            completion(nil)  // Age unknown -- no restriction applied from this device
            return
        }
        switch user.ageCategory {
        case .child:
            completion(ProfileAgeRange(lowerBound: 0, upperBound: 12))
        case .teen:
            completion(ProfileAgeRange(lowerBound: 13, upperBound: 17))
        case .adult:
            completion(ProfileAgeRange(lowerBound: 18, upperBound: nil))  // 18+ (open-ended)
        case .unknown:
            completion(nil)
        }
    }
}

Important: The profileID parameter identifies the current user/profile session. Your implementation should return the age range specific to that user. This is especially important in multi-profile or account-switching scenarios.

Step 2: Register the Provider

Register your age range provider before calling startSDK.

Apple (Swift)

let configurator = MyAppConfigurator()
OTPublishersHeadlessSDK.shared.customConfigurator = configurator
OTPublishersHeadlessSDK.shared.startSDK(
    storageLocation: "cdn.cookielaw.org",
    domainIdentifier: "YOUR-DOMAIN-ID",
    languageCode: "en"
) { response in
    // SDK is ready. Age Gate restrictions are already applied.
}

Note: getProfileAgeRange is part of the CustomConfigurator protocol/class, which also handles proxy URLs. If you are already using CustomConfigurator, simply add the getProfileAgeRange method to your existing implementation.

Step 3: Handle Age Range Changes at Runtime

If the user's age range can change after SDK initialization (e.g., profile update, account switch, login), call checkAndLogConsent to re-evaluate and log the change.

Apple (Swift)

// Call this after the user's age range may have changed
AppPermissionType.ageGate.checkAndLogConsent { success in
    if success {
        // Age range was updated and logged successfully
    } else {
        // No change detected, or the update failed
    }
}

When to call checkAndLogConsent:

ScenarioAction
User updates their profile (age or date of birth changes)Call checkAndLogConsent
User switches accountsCall checkAndLogConsent
User logs in or re-authenticatesCall checkAndLogConsent
App launch / SDK initializationNot needed -- the SDK does this automatically

4. SDK Lifecycle and Behavior

What Happens During startSDK

When the SDK initializes:

  • It calls your getProfileAgeRange delegate to retrieve the user's age range.
  • If a valid age range is returned and it differs from the previously stored value:
    • The SDK sends the age range to the CMP API server via a save-log-consent call with the AGEGATE_RANGE interaction type.
    • The server evaluates the age range against the configured age groups and returns updated consent data.
    • On success, the SDK stores the server-confirmed age range locally and enforces restrictions.
  • If the delegate returns nil:
    • The SDK does not send an age range to the server.
    • If the server already has an age range for this profile (from a prior interaction or another device), it continues to enforce those restrictions via cached data.
    • If no age range exists for this profile, no restrictions are applied.

What checkAndLogConsent Does (Same Logic, Called at Runtime)

  • Calls your getProfileAgeRange delegate to get the latest age range.
  • Compares it against the previously stored age range.
  • If changed and a valid age range is provided (not nil):
    • Sends the new value to the CMP API with the AGEGATE_RANGE interaction type.
    • If the CMP API call succeeds, stores the server-confirmed age range locally and enforces the updated restrictions.
    • If the CMP API call fails, local storage is not updated, and the previously synced age range remains in effect.
  • If unchanged, or if the delegate returns nil, no action is taken.

Age Range Source of Truth: CMP API, Not the App

The SDK only honors the age range registered with the CMP API. It does not apply the app-provided age range locally until the server has acknowledged it. This is a deliberate design decision:

  • If the AGEGATE_RANGE call succeeds: The SDK stores the server-confirmed age range locally and enforces the restrictions returned by the server. The locally cached data (consent map, consent strings, UI data) all reflect the server-evaluated state.
  • If the AGEGATE_RANGE call fails (e.g., network error): The SDK does not store or apply the app-provided age range locally. Instead, it continues using whatever age range was last successfully synced with the CMP API (if any). If no age range has ever been synced, no restrictions are applied.

Subsequent CMP API calls (banner, preference center, etc.) also require network connectivity. If the Age Gate call fails due to a network issue, those calls will fail too, since the Age Gate call is the first call during SDK setup. Adding local enforcement for a scenario that also prevents all other SDK operations would add unnecessary complexity.

This behavior follows the same pattern as all other SDK data flows (banner, preference center, etc.): the SDK uses cached server-synced data for processing. The CMP API is the authoritative source for consent state, and the SDK renders its data.

In Practice

An age range registration failure is an extremely rare event. A user's age range typically changes at most once (during profile creation or a birthday update), and for that single call to fail requires a simultaneous network outage. The risk does not justify duplicating the CMP API's enforcement logic in the SDK.

Age Range Persists on the Profile

Once a profile is registered with an age range on the CMP API, that age range stays associated with the profile. Even if the SDK or client subsequently sends nil/null for both lowerBound and upperBound, the CMP API will continue to use the last successfully registered age range for that profile. The only way to remove an age range from a profile is through admin action. This means age-based restrictions, once applied, remain in effect until a new valid age range is provided or the range is cleared server-side.


5. SDK Public APIs Affected by Age Gate

getConsentStatus(forCategory:)

Returns the consent status for a purpose group. Returns 0 (denied) for any purpose restricted by Age Gate.


// iOS
let status = OTPublishersHeadlessSDK.shared.getConsentStatus(forCategory: "C0005")
// Returns: 1 = given, 0 = denied (including age-restricted), -1 = invalid group ID

getPurposeConsentLocal(forCustomGroupId:)

Returns the most up-to-date consent value on the device. Returns 0 (denied) for age-restricted purposes. This API includes a local age gate check and will return 0 even if the underlying stored consent value differs.


// iOS
let status = OTPublishersHeadlessSDK.shared.getPurposeConsentLocal(forCustomGroupId: "C0005")

updatePurposeConsent(forGroup:consentValue:)

Updates consent programmatically. For age-restricted purposes, the SDK silently blocks any attempt to set consent to true (via canToggleConsentStatus(), which checks age gate authorization).


// iOS
OTPublishersHeadlessSDK.shared.updatePurposeConsent(forGroup: "C0005", consentValue: true)
// If C0005 is age-restricted, this call is silently ignored.

Summary

  • getConsentStatus: Normal purpose returns user's consent (0 or 1). Age gate restricted purpose returns 0 (denied).
  • getPurposeConsentLocal: Normal purpose returns local consent value. Age gate restricted purpose returns 0 (denied).
  • updatePurposeConsent(true): Normal purpose updates consent to given. Age gate restricted purpose is silently ignored, and consent remains denied.
  • updatePurposeConsent(false): Normal purpose updates consent to denied. Age gate restricted purpose is a no-op (already denied).

getAgeGatePromptValue()

This API returns the user's interaction state with the existing Age Gate prompt UI. It is completely independent of age range-based enforcement and is not affected by Age-Based Consent.


// iOS
let value = OTPublishersHeadlessSDK.shared.getAgeGatePromptValue()
// Returns: 1 = accepted, 0 = denied, -1 = not interacted

6. Preference Center Behavior

When a user's age range overlaps with a restricted age group:

  • Purpose visibility: The purpose remains visible in the Preference Center.
  • Consent toggle: Shown in a disabled (grayed-out) state, set to OFF.
  • Explanatory copy: Displayed below the toggle in purpose details: "This item isn't available for your age range and cannot be enabled."
  • User interaction: The toggle cannot be changed through touch, keyboard, remote, or accessibility.
  • Consent value: Automatically set to 0 (denied).
  • Legitimate Interest: If linked, the LI toggle is also disabled when restricted by Age Gate.
  • Always Active purposes: Purposes configured as "Always Active" (consentToggleStatus == 2) are never restricted by Age Gate, even if linked to a restricted age group.

When the user is NOT restricted:

  • Purpose visibility: Normal.
  • Consent toggle: Normal, visible and interactive.
  • Consent value: Based on user's actual choice.

Note (Phase 2 Change): In earlier versions (Phase 1), restricted purpose toggles were completely hidden from the UI. Starting with Phase 2 (SDK 202610.1.0+), restricted toggles are shown in a disabled state instead. This provides better transparency to users and aligns the preference center with privacy disclosures.

Accept All / Reject All

Accept All and Reject All operate on purposes that are available to the user. Age Gate restricted purposes remain denied regardless of Accept All/Reject All actions.

7. Consent String Handling

  1. When Age Gate restrictions are applied, the CMP API correctly recomputes all applicable consent strings:

    • TC String (TCF): Re-encoded with restricted purposes reflected as denied
    • GPP String: Re-encoded based on the final consent state with restrictions applied
    • US Privacy String: Generated based on the current consent state with restrictions applied
    • Google Additional Consent: Re-encoded appropriately

    Why "not applicable" instead of "opted out"? Because the user never saw or acted on the restricted purpose. From a privacy string perspective, the user did not make a choice -- the purpose was unavailable. This is semantically different from the user explicitly opting out.

Data Model Reference

ProfileAgeRange

Represents the user's age range. This is the type your getProfileAgeRange delegate returns.

Properties

NameTypeRequiredDescription
lowerBoundInteger, 0-255OptionalMinimum age in the range. If omitted, treated as 0 (i.e., from birth).
upperBoundInteger, 0-255OptionalMaximum age in the range. If omitted, treated as open-ended (i.e., no upper limit).

Constraints

  • Both bounds are optional at the data model level.
  • The SDK validates that at least one bound is provided before sending to the CMP API. If both are nil, the SDK treats it as "no age range" and does not send an AGEGATE_RANGE request.
  • When both are provided, upperBound must be greater than or equal to lowerBound. Equal values (e.g., 18, 18) are valid and represent a single-age range.
  • Values are clamped to the 0-255 range (SDK-side).

Valid Examples

ExamplelowerBoundupperBoundMeaning
Child (0-12)nil or 012Ages 0 through 12.
Teen (13-17)1317Ages 13 through 17.
Adult (18+)18nilAges 18 and above (open-ended).
Exact range2534Ages 25 through 34.

Invalid Examples (silently rejected by the SDK)

ExamplelowerBoundupperBoundWhy invalid
Both nilnilnilAt least one bound is required.
Equal bounds1818Valid, since it represents a single-age range.
Inverted2518Lower must be less than upper.

When an invalid age range is provided, the SDK logs a warning and treats it as if nil was returned. No age range is sent to the server.

Age Range Validation Rules

Both fields are optional at the data model level. The SDK performs the following validation before sending to the CMP API:

ConfigurationResult
Both bounds are nilTreated as "no age range"; SDK does not send AGEGATE_RANGE.
Lower > Upper (when both provided)Rejected; treated as nil.
Lower == Upper (e.g., 18, 18)Valid; represents a single-age range.
Only lower bound provided (e.g., 18+)Valid; upper is open-ended.
Only upper bound provided (e.g., 0-12)Valid; lower defaults to 0.
Both bounds valid (lower < upper)Valid.
Values outside 0-255Clamped to 0-255.

Age Range Overlap Logic

A user is considered restricted for a purpose if their age range shares any overlap with one or more restricted age groups linked to that purpose. Partial overlap results in restriction. The overlap evaluation happens server-side (CMP API).

Overlap Formula:

restricted = (user.lowerBound <= group.upperBound) AND (user.upperBound >= group.lowerBound)

Where:

TermDefinition
user.lowerBoundDefaults to 0 if not provided.
user.upperBoundDefaults to unbounded (effectively infinity) if not provided.
group.lowerBoundDefaults to 0 if not configured.
group.upperBoundAlways configured (required in admin setup).

Example: Restricted age group 0-15

User age rangeResultReason
[0, 18]RestrictedOverlap at ages 0-15.
[14, 16]RestrictedOverlap at ages 14-15.
[18, 25]Not restrictedNo overlap (18 > 15).
[18, nil]Not restrictedOpen-ended 18+ does not intersect 0-15.
[nil, 12]Restricted0-12 is fully within 0-15.

A purpose can be linked to multiple age groups. A user is restricted if their age range overlaps with any of the linked groups.

10. Cross-Device Behavior

For environments with Cross-Device Consent (CRO) or Authenticated Consent enabled, age-based restrictions are enforced server-side and persist across devices.

  • A user's age range is logged from any device (via SDK or CMP API).
  • The CMP API stores the age range for the user's profile.
  • All subsequent consent responses for that profile enforce the same restrictions.
  • Enforcement applies across devices, sessions, and SDK versions.

SDK Version Compatibility in Cross-Device Scenarios

SDK versionToggle behaviorAPI enforcementServer override
Phase 2+ SDK (recommended)Shown as disabledupdatePurposeConsent blockedYes
Phase 1 SDKHiddenupdatePurposeConsent blockedYes
Older SDK (with CMP API support)Hidden (via consentToggleStatus: -1)Not enforced locallyOverrides on next sync
Legacy SDK (no CMP API)May remain visibleNot enforcedOverrides on next sync

Recommendation: Upgrade all applications to the latest SDK version with Age-Based Consent support for complete enforcement at both the UI and API levels.

11. Anonymous-to-Known User Consent Transfer

When a user transitions from an anonymous session to an authenticated (known) session, the SDK transfers consent using the SYNC_PROFILE interaction. Age-Based Consent adds safeguards to this process.

If the known profile already has an age range:

  • Consent for Age Gate-linked purposes is not transferred, regardless of recency.
  • The server preserves the existing age-restricted consent state.
  • Consent for non-linked purposes transfers normally (latest value wins).

If the known profile does NOT have an age range:

  • All consent transfers normally (latest value wins).
  • Age-based restrictions are not applied until an age range is provided.

Important: The anonymous user's age range is not carried over to the known profile. Age range is identity-specific. The authenticated profile must provide its own age range via the getProfileAgeRange delegate.

Implementation Guidance

  • Implement getProfileAgeRange for authenticated users (recommended).
  • Optionally implement it for anonymous users if age data is collected pre-login.

When a user authenticates:

  1. The SDK calls getProfileAgeRange with the new profile ID.
  2. Your app should return the correct age range for that authenticated user.

What Happens to the Anonymous User's Age Range During SYNC_PROFILE?

The anonymous user's age range is intentionally discarded during SYNC_PROFILE. The CMP API explicitly strips the anonymous OT consent string's age gate data before evaluating the sync (setting ageGate: undefined). The known profile's existing age range (if any) is read from the profile's dataElements and re-applied to the returned consent string. This prevents a potentially unverified anonymous age range from being carried over to an authenticated profile.

Example Flow

Anonymous user (DSID: a1b2c3d4-..., age 14-17) provides consent. Age Gate restricts linked purposes.

  1. User logs in. The SDK renames the DSID to the authenticated profile's DSID (e.g., f9e8d7c6-...).
  2. The SDK calls handleAuthenticatedConsent, which sends SYNC_PROFILE to the CMP API.
  3. The CMP API evaluates the known profile:
    • The anonymous age range (14-17) is discarded. It is not transferred.
    • If the known profile has age 14-17 (from a prior registration), restrictions remain, and consent for linked purposes reflects the profile's state.
    • If the known profile has age 18-25, there is no restriction, and consent transfers normally.
    • If the known profile has no age range, all consent transfers, and restrictions are applied only after age is provided.
  4. The SDK calls getProfileAgeRange("f9e8d7c6-..."). Your app maps this DSID to the authenticated user and returns their age range. The SDK then sends AGEGATE_RANGE to register it.

12. ATT + Age Gate (iOS/tvOS Only)

On Apple platforms, App Tracking Transparency (ATT) and Age Gate can both be configured to link to the same purposes. When both are active, they interact as follows.

Can a Purpose Be Linked to Both?

Yes. ATT-linked categories and Age Gate-linked categories are managed independently in the admin console. A single purpose can appear in both prompts.idfa.linkedCategories and prompts.ageGate.linkedCategories.

Priority: Age Gate Over ATT

When a purpose is restricted by both ATT (not authorized) and Age Gate (age range overlaps), Age Gate takes priority.

ScenarioconsentToggleStatusisConsentDisabledToggle behavior
Age Gate restricted only-1trueDisabled (grayed out) and OFF.
ATT not authorized only0falseInactive: visible, but consent is forced to 0 until ATT is granted.
Both restricted-1trueAge Gate wins, so the toggle is disabled (grayed out) and OFF.
Neither restricted0 or 1falseNormal interactive toggle.

This priority is enforced both server-side (CMP API) and client-side (SDK):

  • CMP API: getChildConsentToggleStatus checks Age Gate before ATT. getRestrictedLinkedCategories pushes Age Gate entries first, so consent receipts use the Age Gate reason.
  • iOS SDK: canToggleConsentStatus() checks isAuthorizedWithAgeGate before shouldAuthorizeWithATT. getLatestConsent forces 0 if either restriction applies.

ATT Blocks Consent Logging Until Determined

On iOS, when ATT-linked categories exist and ATT status is .notDetermined, the SDK blocks all consent logging (not just ATT-linked purposes). The SDK's saveAndLogConsent returns early with the message "Consent will not be logged as ATT permission has not been provided by the user." This means:

  • If both ATT and Age Gate are configured, the ATT system prompt must be presented before any consent (including non-ATT purposes) can be saved.
  • The SDK automatically triggers the ATT system prompt before confirm, reject, and close actions in the banner and preference center.
  • Age Gate (AGEGATE_RANGE) logging is separate. It uses checkAndLogConsent, not saveAndLogConsent, so it is not blocked by ATT status.

Recommended Flow When Both Are Configured

  1. App registers CustomConfigurator (with getProfileAgeRange).
  2. App calls startSDK().
    • SDK calls getProfileAgeRange and sends AGEGATE_RANGE to the CMP API.
  3. SDK shows the banner.
  4. User interacts with the banner. SDK triggers the ATT system prompt if needed.
  5. ATT status is determined and consent is logged.
  6. Preference Center: Age Gate restricted purposes are shown as disabled. ATT-restricted purposes are shown with a toggle, but consent is blocked until ATT is authorized.

The Age Gate prompt (AppPermissionType.ageGate.showConsentUI) and the ATT prompt are independent. Your app controls the order in which they are presented. The SDK does not enforce a specific sequence between the two prompts, but ATT must be determined before any banner or Preference Center consent can be logged.

Android

ATT does not exist on Android. On Android, isConsentDisabled and isLegIntDisabled in the CMP API response are always Age Gate restrictions. The SDK renders them identically to iOS (disabled toggle with hint text).

13. Offline and Failure Behavior

What Happens When the AGEGATE_RANGE Call Fails

The SDK follows a fail-open design for Age Gate. If the AGEGATE_RANGE save-log-consent call fails:

ScenarioLocal stateSDK behavior
First-time user, no prior age rangeNo age range is stored locally.Treats the user as unrestricted (no enforcement).
Returning user with a previously synced age rangeLocal storage retains the last successfully synced age range.Continues enforcing the previously synced restrictions.
App passes a new age range, call failsThe new age range is not persisted locally. The previously synced age range is retained.The previously synced age range remains in effect.

Why Fail-Open?

The Age Gate call is the first network call during SDK setup. If it fails due to a network issue, all subsequent CMP API calls (banner, preference center) will also fail, and the SDK falls back to cached server data for all rendering. Adding local enforcement for a network-failure scenario that already prevents all other SDK operations would introduce inconsistency between local enforcement and server state without any user-facing benefit.

Key Takeaway

If your application collects age data during registration and the first AGEGATE_RANGE call succeeds, subsequent sessions will always have a cached age range available. The offline/failure scenario mainly affects the gap between when the app first collects an age range and when it is first successfully synced.

14. End-to-End Flow

15. Troubleshooting and FAQ

Q: I set an age range, but the purposes are not being restricted.

Check:

  • Are age range groups configured and linked to purposes in the admin console?
  • Is the Age Gate feature flag enabled for your organization?
  • Does the user's age range actually overlap with the configured restricted age groups? (See Overlap Logic)
  • Did the save-log-consent call succeed? Age range restrictions are only applied after a successful server sync.

Q: The toggle is hidden instead of being shown as disabled.

This is Phase 1 behavior. Ensure you are using SDK version 202610.1.0 or later (Phase 2), which shows restricted toggles in a disabled state instead of hiding them.

Q: I provided an age range but the SDK did not apply it.

The SDK only honors age ranges that have been successfully registered with the CMP API. If the AGEGATE_RANGE network call failed, the SDK does not apply the app-provided range locally. Check your network connectivity and ensure the CMP API endpoint is reachable.

Verify the age range is valid (see Validation Rules). Invalid ranges (both bounds nil, lower >= upper) are silently rejected by the SDK before any network call is made.

Check SDK logs for messages containing "age range" or AGEGATE_RANGE to diagnose the issue.

Q: What happens if the Age Gate call fails (offline/network error)?

The SDK follows a fail-open design. See Offline and Failure Behavior for detailed platform-specific behavior. In summary:

  • First-time user with no prior sync: treated as unrestricted.
  • Returning user with prior sync: the last successfully synced age range continues to be enforced.
  • When connectivity is restored and the SDK re-initializes or checkAndLogConsent is called again, the updated age range will be sent to the CMP API and applied upon success.

Q: What if both ATT and Age Gate are configured for the same purpose? (Apple only)

Age Gate takes priority. If a purpose is restricted by both, the toggle is shown as disabled (Age Gate behavior), not just inactive (ATT behavior). See ATT + Age Gate for details.

Q: Does the ATT prompt block Age Gate logging?

No. AGEGATE_RANGE logging uses checkAndLogConsent, which is separate from the saveAndLogConsent path that ATT blocks. Age Gate calls proceed independently of ATT status.

Q: Can I use Age-Based Consent without the Age Gate prompt?

Yes. Age range enforcement and the Age Gate prompt are independent features. You can enable age range enforcement without enabling the Age Gate prompt UI. This is especially useful if your application already has an age signal from user registration or login.

Q: How do I clear a user's age range?

Returning nil from your getProfileAgeRange delegate does not clear the locally stored age range or the server-side profile age range. The SDK treats nil as "no age range available from the app" and leaves the previously synced age range in effect. This is because the SDK only updates local storage after a successful AGEGATE_RANGE CMP API call, and nil age ranges are not sent to the server. Furthermore, once an age range is registered with the CMP API, it persists on the profile. Even if nil/null is sent for both bounds, the CMP API continues using the last registered age range.

To change a user's restrictions, provide a new valid age range via the delegate. Removing an age range from a profile entirely requires admin action.

Q: What happens if my getProfileAgeRange delegate takes a long time?

The delegate supports asynchronous operations. The SDK will wait for your completion handler. However, if your delegate blocks indefinitely, it will delay SDK initialization. Implement a reasonable timeout in your delegate.

Q: Why are my IAB GPP/TC strings not updating after Age Gate?

Ensure you are using a CMP API version that includes the Phase 2 consent string fixes. The CMP API correctly recomputes TC, GPP, and US Privacy strings during Age Gate interactions. If you are seeing stale strings, verify that:

  • The AGEGATE_RANGE request was successful.
  • You are reading the strings from the response, not from cached values.
  • Ensure the SDK version is 202610.1.0 or later.

Q: What if the same user has different age ranges on different devices?

The CMP API stores the most recently provided age range for each profile. If you provide a different age range from a different device, the new range replaces the old one. All devices will pick up the updated restrictions on their next sync.

Debugging Tips

Enable SDK logging to see Age Gate-related log messages.

  • Look for messages containing "age range", "Age Gate", or AGEGATE_RANGE.
  • The SDK logs when it retrieves, validates, stores, and sends the age range.
  • Check the CMP API response for consentToggleStatus and isConsentDisabled values on each purpose to verify restrictions are being applied.
  • Verify the admin configuration. Ensure age range groups are properly linked to the intended purposes in the OneTrust admin console.

Appendix: Age Gate Prompt vs Age-Based Consent

Purpose

  • Age Gate Prompt: Shows a Yes/No prompt to gate consent UI
  • Age-Based Consent (Age Range): Enforces consent restrictions based on age range

Data Source

  • Age Gate Prompt: User interaction with prompt UI
  • Age-Based Consent (Age Range): Application provides age range via delegate

Storage

  • Age Gate Prompt: Local boolean (yes/no)
  • Age-Based Consent (Age Range): Server-side profile data + local cache

Enforcement

  • Age Gate Prompt: Local only, no server interaction
  • Age-Based Consent (Age Range): Server-side enforcement via CMP API

Cross-Device

  • Age Gate Prompt: No
  • Age-Based Consent (Age Range): Yes (with CRO/Authenticated Consent)

SDK APIs

  • Age Gate Prompt: showConsentUI, getAgeGatePromptValue
  • Age-Based Consent (Age Range): getProfileAgeRange delegate, checkAndLogConsent

Independent?

  • Age Gate Prompt: Yes, works without Age-Based Consent
  • Age-Based Consent (Age Range): Yes, works without the Age Gate prompt

These two features can be used independently or together based on your requirements.


Did this page help you?