Capacitor Age Signals Plugin
Capacitor plugin to use the Play Age Signals API (Android) and DeclaredAgeRange (iOS) to request age signals about the user.
Features
The Capacitor Age Signals plugin is one of the most complete age assurance solutions for Capacitor apps. Here are some of the key features:
- 🖥️ Cross-platform: Supports Android and iOS.
- 🔍 Age Verification: Request user age signals using Play Age Signals API (Android) and DeclaredAgeRange (iOS).
- 👨👩👧👦 Parental Controls: Support for supervised accounts with parental approval status.
- 🧪 Testing Support: Built-in
FakeAgeSignalsManagerintegration for testing different age verification scenarios (Android). - 🌍 Compliance Ready: Built for US state age verification requirements (effective January 1, 2026).
- 🤝 Compatibility: Works alongside the App Integrity and Root Detection plugins.
- 📦 CocoaPods & SPM: Supports CocoaPods and Swift Package Manager for iOS.
- 🔁 Up-to-date: Always supports the latest Capacitor version.
Missing a feature? Just open an issue and we'll take a look!
Use Cases
The Age Signals plugin is typically used to comply with age verification requirements and to tailor the app experience to the user's age, for example:
- Age-gated content: Restrict access to mature or sensitive content based on the user's verification status and age range.
- Regulatory compliance: Meet US state age verification requirements by requesting age signals from Google Play and Apple's DeclaredAgeRange API.
- Parental supervision: Detect supervised accounts and react to pending or denied parental approvals.
- Regional eligibility checks: Use
getRegulatoryRequirements()on iOS to determine whether the user is in a region with additional age-related obligations. - Automated testing: Simulate different age verification scenarios in your Android tests using the built-in fake manager.
Compatibility
| Plugin Version | Capacitor Version | Status |
|---|---|---|
| 0.3.x | >=8.x.x | Active support |
| 0.2.x | 7.x.x | Deprecated |
Installation
You can use our AI-Assisted Setup to install the plugin. Add the Capawesome Skills to your AI tool using the following command:
npx skills add capawesome-team/skills --skill capacitor-plugins
Then use the following prompt:
Use the `capacitor-plugins` skill from `capawesome-team/skills` to install the `@capawesome/capacitor-age-signals` plugin in my project.
If you prefer Manual Setup, install the plugin by running the following commands and follow the platform-specific instructions below:
npm install @capawesome/capacitor-age-signals
npx cap sync
Android
Variables
If needed, you can define the following project variable in your app's variables.gradle file to change the default version of the dependency:
$androidPlayAgeSignalsVersionversion ofcom.google.android.play:age-signals(default:0.0.4)
This can be useful if you encounter dependency conflicts with other plugins in your project.
Note: The FakeAgeSignalsManager testing API is included in the main age-signals library, so no additional dependency is required for testing.
iOS
Entitlements
To use the DeclaredAgeRange API, you must enable the com.apple.developer.declared-age-range entitlement in your app's entitlements file by adding the following key:
<key>com.apple.developer.declared-age-range</key>
<true/>
Check out the Apple documentation for more information.
Configuration
No configuration required for this plugin.
Usage
The following examples show how to request the user's age range and how to react to the regulatory requirements that apply to the user.
Request the user's age range
Call requestAgeRange(...) to ask the user to share their age range. The status tells you whether the age range was shared, and the ageRange property contains the bounds:
import { AgeRangeStatus, AgeSignals } from '@capawesome/capacitor-age-signals';
const requestAgeRange = async () => {
const result = await AgeSignals.requestAgeRange();
if (result.status !== AgeRangeStatus.Shared) {
console.log('The user has not shared their age range:', result.status);
return;
}
console.log('Lower Bound:', result.ageRange?.lowerBound);
console.log('Upper Bound:', result.ageRange?.upperBound);
};
On Android, a status of VERIFICATION_REQUIRED means the user must resolve their status in the Google Play Store before an age range can be shared.
Read the age range without prompting
Call getAgeRange() to read the age range again without showing a prompt. This is useful to poll for a significantChange status that moves from PENDING to APPROVED. Only available on Android:
import { AgeSignals } from '@capawesome/capacitor-age-signals';
const getAgeRange = async () => {
const result = await AgeSignals.getAgeRange();
console.log('Significant Change:', result.significantChange?.status);
};
Check the regulatory requirements
Check whether the user is in a region and account state that requires age assurance, and which regulatory features your app must support. Only available on iOS:
import {
AgeSignals,
RegulatoryFeature,
} from '@capawesome/capacitor-age-signals';
const getRegulatoryRequirements = async () => {
const result = await AgeSignals.getRegulatoryRequirements();
if (
result.regulatoryFeatures.includes(
RegulatoryFeature.SignificantAppChangeRequiresAdultNotification,
)
) {
await AgeSignals.showSignificantUpdateAcknowledgment({
updateDescription: 'This app now supports direct messages between users.',
});
}
};
API
getAgeRange()getRegulatoryRequirements()isAvailable()requestAgeRange(...)setNextAgeSignalsAccessResult(...)setNextAgeSignalsException(...)setNextAgeSignalsResult(...)setNextRequestAgeSignalsAccessException(...)setUseFakeManager(...)showSignificantUpdateAcknowledgment(...)- Interfaces
- Enums
getAgeRange()
getAgeRange() => Promise<GetAgeRangeResult>
Get the age range that the user has already shared with the app.
This method never shows a system prompt. Call requestAgeRange(...) first
and only call this method if the returned status was SHARED.
Use this method to poll for changes (for example a significantChange
status that moves from PENDING to APPROVED) without prompting the user
again.
Only available on Android.
Returns: Promise<GetAgeRangeResult>
Since: 0.5.0
getRegulatoryRequirements()
getRegulatoryRequirements() => Promise<GetRegulatoryRequirementsResult>
Get the regulatory requirements that apply to the current user.
Call this method before starting any age assurance flow to find out whether the user is in a region and account state where age assurance applies at all.
Only available on iOS (26.2+).
Returns: Promise<GetRegulatoryRequirementsResult>
Since: 0.5.0
isAvailable()
isAvailable() => Promise<IsAvailableResult>
Check whether age signals are available on this device.
On Android, this checks whether the Google Play Store is installed. On iOS, this checks whether the device runs iOS 26.0 or later.
A result of true does not guarantee that an age range can be retrieved.
Always handle the errors of the other methods as well.
Returns: Promise<IsAvailableResult>
Since: 0.5.0
requestAgeRange(...)
requestAgeRange(options?: RequestAgeRangeOptions | undefined) => Promise<RequestAgeRangeResult>
Ask the user to share their age range with the app.
This method may show a system prompt. The system caches the decision of the user, so subsequent calls may resolve without any user interaction.
On Android, the prompt is only shown to unsupervised users who have
chosen to be asked before sharing. It is not shown in regions where age
verification is mandatory. In that case the status is
VERIFICATION_REQUIRED and the user must resolve their status in the
Google Play Store. Google Play also suppresses the prompt after the user
has dismissed or declined it a few times.
On iOS, the prompt is not shown in regions where age assurance is
mandatory. In that case the age range is shared without user interaction.
| Param | Type |
|---|---|
options | RequestAgeRangeOptions |
Returns: Promise<RequestAgeRangeResult>
Since: 0.5.0
setNextAgeSignalsAccessResult(...)
setNextAgeSignalsAccessResult(options: SetNextAgeSignalsAccessResultOptions) => Promise<void>
Set the next access result to be returned by the fake manager.
Only available on Android.
| Param | Type |
|---|---|
options | SetNextAgeSignalsAccessResultOptions |
Since: 0.5.0
setNextAgeSignalsException(...)
setNextAgeSignalsException(options: SetNextAgeSignalsExceptionOptions) => Promise<void>
Set the next error to be thrown by the fake manager when the age range is read.
Only available on Android.
| Param | Type |
|---|---|
options | SetNextAgeSignalsExceptionOptions |
Since: 0.3.1
setNextAgeSignalsResult(...)
setNextAgeSignalsResult(options: SetNextAgeSignalsResultOptions) => Promise<void>
Set the next age range result to be returned by the fake manager.
Only available on Android.
| Param | Type |
|---|---|
options | SetNextAgeSignalsResultOptions |
Since: 0.3.1
setNextRequestAgeSignalsAccessException(...)
setNextRequestAgeSignalsAccessException(options: SetNextRequestAgeSignalsAccessExceptionOptions) => Promise<void>
Set the next error to be thrown by the fake manager when access to the age range is requested.
Only available on Android.
| Param | Type |
|---|---|
options | SetNextRequestAgeSignalsAccessExceptionOptions |
Since: 0.5.0
setUseFakeManager(...)
setUseFakeManager(options: SetUseFakeManagerOptions) => Promise<void>
Enable or disable the fake manager for testing.
The fake manager is only available in debuggable builds. In release builds
this method rejects with FAKE_MANAGER_NOT_ALLOWED, because it would
otherwise allow age signals to be forged from the web layer.
Only available on Android.
| Param | Type |
|---|---|
options | SetUseFakeManagerOptions |
Since: 0.3.1
showSignificantUpdateAcknowledgment(...)
showSignificantUpdateAcknowledgment(options: ShowSignificantUpdateAcknowledgmentOptions) => Promise<void>
Show a system interface that lets the user acknowledge a significant change to the app.
Only call this method if getRegulatoryRequirements() returned
SIGNIFICANT_APP_CHANGE_REQUIRES_ADULT_NOTIFICATION.
Only available on iOS (26.4+).
| Param | Type |
|---|---|
options | ShowSignificantUpdateAcknowledgmentOptions |
Since: 0.5.0
Interfaces
GetAgeRangeResult
| Prop | Type | Description | Since |
|---|---|---|---|
ageRange | AgeRange | The age range that the user has shared with the app. undefined if the user has not shared their age range. | 0.5.0 |
installId | string | An ID assigned to supervised user installs by Google Play, used for the purposes of notifying you of revoked app approval. Only available on Android. | 0.5.0 |
significantChange | SignificantChange | The parental approval state for the significant changes of the app. Significant changes are declared in the Google Play Console. Google Play then asks the parent or guardian of a supervised user to approve them. undefined if the user is not supervised, if no significant change has been declared yet or if significant changes do not apply in the jurisdiction of the user. Only available on Android. | 0.5.0 |
AgeRange
| Prop | Type | Description | Since |
|---|---|---|---|
activeParentalControls | ParentalControl[] | The parental controls that are active for the user. Only available on iOS. | 0.5.0 |
ageRangeDeclaration | AgeRangeDeclaration | How the age range was declared. The more granular values are only returned in some regions. undefined if the system does not provide this information. Only available on iOS. | 0.5.0 |
ageRangeSource | AgeRangeSource | How the age range was established. undefined if the system does not provide this information. Only available on Android. | 0.5.0 |
lowerBound | number | The (inclusive) lower bound of the age range. undefined if the user is below the lowest requested age gate. | 0.5.0 |
upperBound | number | The (inclusive) upper bound of the age range. undefined if the user meets or exceeds the highest requested age gate. | 0.5.0 |
SignificantChange
| Prop | Type | Description | Since |
|---|---|---|---|
approvalDate | string | The effective date of the most recently approved significant change, in ISO 8601 format. All significant changes with an earlier effective date are approved as well. undefined if no significant change has been approved yet. | 0.5.0 |
status | SignificantChangeStatus | The parental approval state for the most recent significant change. | 0.5.0 |
GetRegulatoryRequirementsResult
| Prop | Type | Description | Since |
|---|---|---|---|
ageAssuranceRequired | boolean | Whether the user must share their age range because of a law or regulation that applies to their region and account. | 0.5.0 |
regulatoryFeatures | RegulatoryFeature[] | The regulatory features that the app must support for this user. Empty on iOS versions below 26.4. | 0.5.0 |
IsAvailableResult
| Prop | Type | Description | Since |
|---|---|---|---|
available | boolean | Whether age signals are available on this device. | 0.5.0 |
RequestAgeRangeResult
| Prop | Type | Description | Since |
|---|---|---|---|
ageRange | AgeRange | The age range that the user has shared with the app. undefined if the status is not SHARED. | 0.5.0 |
installId | string | An ID assigned to supervised user installs by Google Play, used for the purposes of notifying you of revoked app approval. Only available on Android. | 0.5.0 |
significantChange | SignificantChange | The parental approval state for the significant changes of the app. Significant changes are declared in the Google Play Console. Google Play then asks the parent or guardian of a supervised user to approve them. undefined if the user is not supervised, if no significant change has been declared yet or if significant changes do not apply in the jurisdiction of the user. Only available on Android. | 0.5.0 |
status | AgeRangeStatus | Whether the user has shared their age range with the app. | 0.5.0 |
RequestAgeRangeOptions
| Prop | Type | Description | Default | Since |
|---|---|---|---|---|
ageGates | number[] | The age thresholds that are relevant for the app. The provided array must contain at least 1 and at most 3 ages. The ages must be sorted in ascending order and must be at least two years apart from each other. The system may ignore these thresholds and return a different age range if a law or regulation requires it. Only available on iOS. | [13, 15, 18] | 0.5.0 |
SetNextAgeSignalsAccessResultOptions
| Prop | Type | Description | Since |
|---|---|---|---|
status | AgeRangeStatus | The status to be returned by the fake manager. | 0.5.0 |
SetNextAgeSignalsExceptionOptions
| Prop | Type | Description | Since |
|---|---|---|---|
errorCode | ErrorCode | The error code to be thrown by the fake manager. Only the error codes that are available on Android are supported. | 0.3.1 |
SetNextAgeSignalsResultOptions
| Prop | Type | Description | Since |
|---|---|---|---|
ageLower | number | The (inclusive) lower bound of the age range. | 0.3.1 |
ageRangeSource | AgeRangeSource | How the age range was established. | 0.5.0 |
ageUpper | number | The (inclusive) upper bound of the age range. | 0.3.1 |
installId | string | An ID assigned to supervised user installs by Google Play. | 0.3.1 |
significantChangeApprovalDate | string | The effective date of the most recently approved significant change, in ISO 8601 format. | 0.5.0 |
significantChangeStatus | SignificantChangeStatus | The parental approval state for the most recent significant change. | 0.5.0 |
SetNextRequestAgeSignalsAccessExceptionOptions
| Prop | Type | Description | Since |
|---|---|---|---|
errorCode | ErrorCode | The error code to be thrown by the fake manager. Only the error codes that are available on Android are supported. | 0.5.0 |
SetUseFakeManagerOptions
| Prop | Type | Description | Default | Since |
|---|---|---|---|---|
useFake | boolean | Whether to use the fake manager for testing. | false | 0.3.1 |
ShowSignificantUpdateAcknowledgmentOptions
| Prop | Type | Description | Since |
|---|---|---|---|
updateDescription | string | A short description of what has changed in the app and why the user must acknowledge it. | 0.5.0 |
Enums
ParentalControl
| Members | Value | Description | Since |
|---|---|---|---|
CommunicationLimits | 'COMMUNICATION_LIMITS' | The system limits the communication features for the user. | 0.5.0 |
AgeRangeDeclaration
| Members | Value | Description | Since |
|---|---|---|---|
CheckedByOtherMethod | 'CHECKED_BY_OTHER_METHOD' | The user set their own age range using an unspecified method. Only available on iOS (26.2+). | 0.5.0 |
Confirmed | 'CONFIRMED' | The age range was set using a scrutinized method, like a credit card or government ID. Only available on iOS (26.5+). | 0.4.0 |
GovernmentIdChecked | 'GOVERNMENT_ID_CHECKED' | The user set their own age range using a government ID. Only available on iOS (26.2+). | 0.5.0 |
GuardianCheckedByOtherMethod | 'GUARDIAN_CHECKED_BY_OTHER_METHOD' | A parent or guardian set the age range using an unspecified method. Only available on iOS (26.2+). | 0.5.0 |
GuardianDeclared | 'GUARDIAN_DECLARED' | A parent or guardian declared the age range without external verification. | 0.4.0 |
GuardianGovernmentIdChecked | 'GUARDIAN_GOVERNMENT_ID_CHECKED' | A parent or guardian set the age range using a government ID. Only available on iOS (26.2+). | 0.5.0 |
GuardianPaymentChecked | 'GUARDIAN_PAYMENT_CHECKED' | A parent or guardian set the age range using a payment method, like a credit card. Only available on iOS (26.2+). | 0.5.0 |
PaymentChecked | 'PAYMENT_CHECKED' | The user set their own age range using a payment method, like a credit card. Only available on iOS (26.2+). | 0.5.0 |
SelfDeclared | 'SELF_DECLARED' | The user declared their own age range without external verification. | 0.4.0 |
AgeRangeSource
| Members | Value | Description | Since |
|---|---|---|---|
TierA | 'TIER_A' | The user has self-declared their age. | 0.5.0 |
TierB | 'TIER_B' | The age of the user is managed by a parent or guardian. | 0.5.0 |
TierC | 'TIER_C' | The age of the user was assessed using a credit card, an email address, a selfie assessment, a government ID or a tax ID. | 0.5.0 |
TierD | 'TIER_D' | The age of the user was checked using a combination of a government ID and a selfie assessment, or using a digital ID. | 0.5.0 |
SignificantChangeStatus
| Members | Value | Description | Since |
|---|---|---|---|
Approved | 'APPROVED' | The parent or guardian has approved the most recent significant change and all prior significant changes. | 0.5.0 |
Declined | 'DECLINED' | The parent or guardian has declined one or more significant changes. | 0.5.0 |
Pending | 'PENDING' | The parent or guardian has not yet approved one or more significant changes. | 0.5.0 |
RegulatoryFeature
| Members | Value | Description | Since |
|---|---|---|---|
DeclaredAgeRangeRequired | 'DECLARED_AGE_RANGE_REQUIRED' | The user must share their age range with the app. | 0.5.0 |
SignificantAppChangeRequiresAdultNotification | 'SIGNIFICANT_APP_CHANGE_REQUIRES_ADULT_NOTIFICATION' | An adult user must acknowledge a significant change of the app. Use showSignificantUpdateAcknowledgment(...) to show the system interface for the acknowledgment. | 0.5.0 |
SignificantAppChangeRequiresParentalConsent | 'SIGNIFICANT_APP_CHANGE_REQUIRES_PARENTAL_CONSENT' | A parent or guardian must consent to a significant change of the app. This plugin does not implement the consent flow. Use Apple's PermissionKit framework to request the consent. | 0.5.0 |
AgeRangeStatus
| Members | Value | Description | Since |
|---|---|---|---|
NotShared | 'NOT_SHARED' | The user has not shared their age range with the app. | 0.5.0 |
Shared | 'SHARED' | The user has shared their age range with the app. | 0.5.0 |
Unspecified | 'UNSPECIFIED' | The system did not specify whether the user has shared their age range. Treat this value like NOT_SHARED. Google Play does not document when it is returned. Only available on Android. | 0.5.0 |
VerificationRequired | 'VERIFICATION_REQUIRED' | The user must verify their age in the Google Play Store before the age range can be shared. Only available on Android. | 0.5.0 |
ErrorCode
| Members | Value | Description | Since |
|---|---|---|---|
ApiNotAvailable | 'API_NOT_AVAILABLE' | The age signals API is not available. On Android, the Play Store app version installed on the device might be old. On iOS, the system was unable to share the age range. | 0.0.1 |
AppNotOwned | 'APP_NOT_OWNED' | The app was not installed by Google Play. Only available on Android. | 0.0.1 |
CannotBindToService | 'CANNOT_BIND_TO_SERVICE' | Binding to the service in the Play Store has failed. This can be due to having an old Play Store version installed on the device or device memory is overloaded. Only available on Android. | 0.0.1 |
ClientTransientError | 'CLIENT_TRANSIENT_ERROR' | There was a transient error in the client device. Only available on Android. | 0.0.1 |
FakeManagerNotAllowed | 'FAKE_MANAGER_NOT_ALLOWED' | The fake manager is not available, because the app is not debuggable. Only available on Android. | 0.5.0 |
FakeManagerNotEnabled | 'FAKE_MANAGER_NOT_ENABLED' | The fake manager is not enabled. Only available on Android. | 0.5.0 |
InternalError | 'INTERNAL_ERROR' | Unknown internal error. Only available on Android. | 0.0.1 |
InvalidRequest | 'INVALID_REQUEST' | The request contains invalid parameters. On iOS, this is also returned if the requested age gates are rejected by the system. | 0.5.0 |
NetworkError | 'NETWORK_ERROR' | No available network is found. Only available on Android. | 0.0.1 |
NotSupported | 'NOT_SUPPORTED' | Age signals are not supported on this device. | 0.5.0 |
PlayServicesNotFound | 'PLAY_SERVICES_NOT_FOUND' | Play Services is not available or its version is too old. Only available on Android. | 0.0.1 |
PlayServicesVersionOutdated | 'PLAY_SERVICES_VERSION_OUTDATED' | Play Services needs to be updated. Only available on Android. | 0.0.1 |
PlayStoreNotFound | 'PLAY_STORE_NOT_FOUND' | No Play Store app is found on the device. Only available on Android. | 0.0.1 |
PlayStoreVersionOutdated | 'PLAY_STORE_VERSION_OUTDATED' | The Play Store app needs to be updated. Only available on Android. | 0.0.1 |
PresentationContextUnavailable | 'PRESENTATION_CONTEXT_UNAVAILABLE' | No view controller was found to present the system interface. Only available on iOS. | 0.5.0 |
SdkVersionOutdated | 'SDK_VERSION_OUTDATED' | The Age Signals SDK version is outdated. Only available on Android. | 0.4.0 |
Testing
The plugin includes support for the FakeAgeSignalsManager API on Android, which allows you to simulate different age signals scenarios in your tests without requiring live responses from Google Play.
Android Testing
Important: The fake manager is only available if your app is debuggable. In release builds, setUseFakeManager(...) rejects with FAKE_MANAGER_NOT_ALLOWED, because it would otherwise allow age signals to be forged from the web layer.
Important: Due to a known issue in versions 0.0.1 and 0.0.2 of the Age Signals API, you may encounter a java.lang.VerifyError when calling the builder method of AgeSignalsResult in unit tests. As a workaround, run your tests as Android instrumented tests within the androidTest source set.
Example: Testing a Self-Declared Adult User
import {
AgeRangeSource,
AgeRangeStatus,
AgeSignals,
} from '@capawesome/capacitor-age-signals';
// Enable the fake manager
await AgeSignals.setUseFakeManager({ useFake: true });
// The user agrees to share their age range
await AgeSignals.setNextAgeSignalsAccessResult({
status: AgeRangeStatus.Shared,
});
// Set up an adult user
await AgeSignals.setNextAgeSignalsResult({
ageLower: 18,
ageRangeSource: AgeRangeSource.TierA,
});
const result = await AgeSignals.requestAgeRange();
console.log(result.status); // 'SHARED'
console.log(result.ageRange?.lowerBound); // 18
Example: Testing a Supervised User (13-17 years old)
import {
AgeRangeSource,
AgeRangeStatus,
AgeSignals,
} from '@capawesome/capacitor-age-signals';
await AgeSignals.setUseFakeManager({ useFake: true });
await AgeSignals.setNextAgeSignalsAccessResult({
status: AgeRangeStatus.Shared,
});
await AgeSignals.setNextAgeSignalsResult({
ageLower: 13,
ageUpper: 17,
ageRangeSource: AgeRangeSource.TierB,
installId: 'fake_install_id',
});
const result = await AgeSignals.requestAgeRange();
console.log(result.ageRange?.lowerBound); // 13
console.log(result.ageRange?.upperBound); // 17
console.log(result.installId); // 'fake_install_id'
Example: Testing Parental Approval Scenarios
import {
AgeRangeSource,
AgeRangeStatus,
AgeSignals,
SignificantChangeStatus,
} from '@capawesome/capacitor-age-signals';
await AgeSignals.setUseFakeManager({ useFake: true });
await AgeSignals.setNextAgeSignalsAccessResult({
status: AgeRangeStatus.Shared,
});
// Test pending approval
await AgeSignals.setNextAgeSignalsResult({
ageLower: 13,
ageUpper: 17,
ageRangeSource: AgeRangeSource.TierB,
significantChangeApprovalDate: '2026-02-01T00:00:00.000Z',
significantChangeStatus: SignificantChangeStatus.Pending,
});
const result = await AgeSignals.requestAgeRange();
console.log(result.significantChange?.status); // 'PENDING'
console.log(result.significantChange?.approvalDate); // '2026-02-01T00:00:00.000Z'
Example: Testing a User Who Must Verify Their Age
import { AgeRangeStatus, AgeSignals } from '@capawesome/capacitor-age-signals';
await AgeSignals.setUseFakeManager({ useFake: true });
await AgeSignals.setNextAgeSignalsAccessResult({
status: AgeRangeStatus.VerificationRequired,
});
const result = await AgeSignals.requestAgeRange();
console.log(result.status); // 'VERIFICATION_REQUIRED'
console.log(result.ageRange); // undefined
Example: Testing Error Scenarios
import { AgeSignals, ErrorCode } from '@capawesome/capacitor-age-signals';
await AgeSignals.setUseFakeManager({ useFake: true });
// Simulate a network error while access is requested
await AgeSignals.setNextRequestAgeSignalsAccessException({
errorCode: ErrorCode.NetworkError,
});
try {
await AgeSignals.requestAgeRange();
} catch (error) {
console.log('Caught network error:', error);
}
// Simulate a network error while the age range is read
await AgeSignals.setNextAgeSignalsException({
errorCode: ErrorCode.NetworkError,
});
try {
await AgeSignals.getAgeRange();
} catch (error) {
console.log('Caught network error:', error);
}
Disabling the Fake Manager
import { AgeSignals } from '@capawesome/capacitor-age-signals';
// Switch back to the production manager
await AgeSignals.setUseFakeManager({ useFake: false });
// This will now use the real Age Signals API
const result = await AgeSignals.requestAgeRange();
FAQ
Which age verification APIs does this plugin use?
On Android, the plugin uses the Play Age Signals API to request age signals from Google Play. On iOS, it uses Apple's DeclaredAgeRange framework, which requires the com.apple.developer.declared-age-range entitlement (see Installation).
What do the different statuses mean?
The status property tells you whether the user shared their age range. SHARED means an age range is available, NOT_SHARED means the user declined or is not in an applicable region, and VERIFICATION_REQUIRED (Android only) means the user must resolve their status in the Google Play Store first.
How do the Android age range sources map to the iOS age range declarations?
Android reports how an age was established as a tier, while iOS reports a declaration method. They do not map one to one, so both values are exposed as separate properties. The following table shows the closest equivalents:
| Android | iOS |
|---|---|
TIER_A | SELF_DECLARED |
TIER_B | GUARDIAN_DECLARED |
TIER_C | PAYMENT_CHECKED, CHECKED_BY_OTHER_METHOD, GUARDIAN_PAYMENT_CHECKED, GUARDIAN_CHECKED_BY_OTHER_METHOD |
TIER_D | GOVERNMENT_ID_CHECKED, GUARDIAN_GOVERNMENT_ID_CHECKED |
On iOS 26.5 and later, the more granular declarations may be replaced by CONFIRMED, which covers both TIER_C and TIER_D.
How can I test different age verification scenarios?
On Android, the plugin integrates the FakeAgeSignalsManager API, which lets you simulate age signals without live responses from Google Play. Enable it with setUseFakeManager(...) and set the next results or exceptions with setNextAgeSignalsAccessResult(...), setNextAgeSignalsResult(...), setNextRequestAgeSignalsAccessException(...) and setNextAgeSignalsException(...). The fake manager is only available if your app is debuggable. See the Testing section for complete examples.
Why do I get a VerifyError in my Android unit tests?
Due to a known issue in versions 0.0.1 and 0.0.2 of the Age Signals API, calling the builder method of AgeSignalsResult in unit tests may throw a java.lang.VerifyError. As a workaround, run your tests as Android instrumented tests within the androidTest source set.
Why does the plugin reject with an error like API_NOT_AVAILABLE or APP_NOT_OWNED?
The Play Age Signals API requires an up-to-date Play Store app and Play Services on the device, so errors like API_NOT_AVAILABLE, PLAY_STORE_VERSION_OUTDATED, or PLAY_SERVICES_NOT_FOUND usually indicate outdated or missing Google Play components. The APP_NOT_OWNED error means the app was not installed by Google Play. Check the ErrorCode enum in the API section for the full list of error codes.
Can I use this plugin with Ionic, React, Vue or Angular?
Yes, the plugin is framework-agnostic. It works in any Capacitor app regardless of the web framework, including Ionic with Angular, React, or Vue, as well as plain JavaScript projects.
Related Plugins
- App Integrity: Verify app and device integrity using the Play Integrity API and App Attest.
- App Tracking Transparency: Request user authorization via Apple's App Tracking Transparency framework.
- Root Detection: Detect rooted and jailbroken devices.
Newsletter
Stay up to date with the latest news and updates about the Capawesome, Capacitor, and Ionic ecosystem by subscribing to our Capawesome Newsletter.
Changelog
See CHANGELOG.md.
License
See LICENSE.