Expo AgeRange
A library that provides access to age range information using Play Age Signals API on Android and Declared Age Range framework on iOS.
For the complete documentation index, see llms.txt. Use this file to discover all available pages.
This library is currently in alpha and will frequently experience breaking changes.
expo-age-range provides access to user age range information. It uses Google's Play Age Signals API on Android and Apple's Declared Age Range framework on iOS.
This library allows you to request age range information from your app users to help you comply with age-appropriate content regulations (such as in Texas, USA) and provide age-appropriate experiences in your app.
Limitations
We strongly recommend testing the functionality on a real device, as simulator runtimes may not work as expected.
Installation
- npx expo install expo-age-rangeIf you are installing this in an existing React Native app, make sure to install expo in your project.
Configuration in app config
Setup iOS project
To use the age range API on iOS, you need to build your project with Xcode 26.0 or later. The com.apple.developer.declared-age-range entitlement is required. Add it to your app config file:
{ "expo": { "ios": { "entitlements": { "com.apple.developer.declared-age-range": true } } } }
Are you using this library in an existing React Native app?
For existing React Native projects, add the entitlement to your project's ios/[app]/[app].entitlements file:
<key>com.apple.developer.declared-age-range</key> <true/>
Usage
import * as AgeRange from 'expo-age-range'; import { useState } from 'react'; import { StyleSheet, Text, View, Button } from 'react-native'; export default function App() { const [result, setResult] = useState<AgeRange.AgeRangeResponse | { error: string } | null>(null); const requestAgeRange = async () => { try { const ageRange = await AgeRange.requestAgeRangeAsync({ threshold1: 10, threshold2: 13, threshold3: 18, }); setResult(ageRange); } catch (error) { setResult({ error: error.message }); } }; return ( <View style={styles.container}> <Button title="Request Age Range" onPress={requestAgeRange} /> {result && ( <Text style={styles.result}> {'error' in result ? `Error: ${result.error}` : `Lower age bound: ${result.lowerBound}`} </Text> )} </View> ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', padding: 20, }, result: { marginTop: 20, fontSize: 16, }, });
Additional resources
- Play Age Signals API: Android documentation for age signals
- Declared Age Range framework: iOS documentation for declared age range
API
import * as AgeRange from 'expo-age-range';
Methods
Returns the set of regulatory features that the OS reports as required for the current user.
Use this to discover which age-assurance obligations apply.
Resolves with null on iOS earlier than 26.4 and on Android and web — treat
null as "unknown" rather than "no features required".
Promise<AgeRangeRegulatoryFeature[] | null>Asks the OS whether age-assurance regulation applies to the current user. Apple uses this to signal that the account region is covered by a law such as Utah's or Louisiana's age-assurance requirements, so apps can avoid gating users in jurisdictions where the rules do not apply.
- Resolves with
trueonly when Apple confirms regulation applies. - Resolves with
falsewhen the OS confirms regulation does not apply. - Resolves with
nullon iOS earlier than 26.2, and on Android and web. Treatnullas "unknown" rather than a definitivefalse. - Rejects when the request fails — see AgeRangeService.Error
for more information. Treat rejection as "unknown" and fall through to
requestAgeRangeAsyncor your own gating logic.
Recommended pattern: call this first and only prompt the user for their age
range when the result is not false. When it is false, the user is outside
a regulated jurisdiction and you can skip the age gate entirely.
Promise<boolean | null>Example
try { const eligible = await isEligibleForAgeFeaturesAsync(); if (eligible === false) { // Regulation does not apply — no age gate needed. return; } } catch { // Treat errors as "unknown" and fall through to the prompt below or your own gating logic. } const ageRange = await requestAgeRangeAsync({ threshold1: 18 });
| Parameter | Type |
|---|---|
| options | AgeRangeRequest |
Prompts the user to share their age range with the app. Responses may be cached by the OS for future requests.
Promise<AgeRangeResponse>A promise that resolves with user's age range response, or rejects with an error.
The user needs to be signed in on the device to get a valid response.
When not supported (earlier than iOS 26 and web), the call returns lowerBound: 18, which is equivalent to the response of an adult user.
| Parameter | Type | Description |
|---|---|---|
| updateDescription | string | A description of the significant update to show to the user. |
Displays a system-provided interface for people to acknowledge a significant app update.
Only on iOS 26.4+, this presents an update acknowledgement dialog and resolves once the user confirms it, or rejects with an error. On unsupported platforms this resolves immediately without showing any UI.
Call getRequiredRegulatoryFeaturesAsync first to
determine whether the user actually needs to acknowledge a significant change — only invoke
this function when the returned features include 'significantAppChangeRequiresAdultNotification'.
Doing so avoids prompting users who are not subject to the regulation.
Promise<void>Types
Literal Type: string
A regulatory feature that your app may need to support for the current user.
Mirrors AgeRangeService.RegulatoryFeature.
Acceptable values are: 'declaredAgeRangeRequired' | 'significantAppChangeRequiresAdultNotification' | 'significantAppChangeRequiresParentalConsent'
Options for requesting age range information from the user.
| Property | Type | Description |
|---|---|---|
| threshold1 | number | The required minimum age for your app. |
| threshold2(optional) | number | An optional additional minimum age for your app. |
| threshold3(optional) | number | An optional additional minimum age for your app. |
Response containing the user's age range information.
Contains age boundaries and platform-specific metadata.
| Property | Type | Description |
|---|---|---|
| activeParentalControls(optional) | string[] | Only for: iOS List of parental controls enabled and shared as a part of age range declaration. |
| ageRangeDeclaration(optional) | 'selfDeclared' | 'guardianDeclared' | null | Only for: iOS Indicates whether the age range was declared by the user themselves or someone else (parent, guardian, or Family Organizer in a Family Sharing group). |
| installId(optional) | string | null | Only for: Android An ID assigned to supervised user installs by Google Play, used to notify you of revoked app approval. |
| lowerBound | number | null | The lower limit of the person’s age range. |
| mostRecentApprovalDate(optional) | number | null | Only for: Android The effective date (timestamp) of the most recent significant change that was approved. |
| upperBound | number | null | The upper limit of the person’s age range. |
| userStatus(optional) | 'VERIFIED' | 'SUPERVISED' | 'SUPERVISED_APPROVAL_PENDING' | 'SUPERVISED_APPROVAL_DENIED' | 'DECLARED' | 'UNKNOWN' | null | Only for: Android The user's age verification or supervision status. |
Error codes
Available in the code property of any error thrown by the native module. For Android-specific error codes, see "Handle API error codes" in Use Play Age Signals API docs.
| Code | Platform | Description |
|---|---|---|
ERR_AGE_RANGE_USER_DECLINED | iOS | User declined to share their age range. |
ERR_AGE_RANGE_NOT_AVAILABLE | iOS | Age range not available. The most likely cause is that user is not signed in to their Apple account on the device. |
ERR_AGE_RANGE_INVALID_REQUEST | iOS | The provided params were invalid. The age ranges need to be minimum 2 years apart. |