@crowdhub/cordova-plugin-age-verification
v0.0.5
Published
Cordova plugin for privacy-preserving age assurance using the Google Play Age Signals API (Android/Kotlin) and the Apple Declared Age Range API (iOS/Swift). Exposes a unified, Promise-based JavaScript API with TypeScript definitions.
Readme
@crowdhub/cordova-plugin-age-verification
Privacy-preserving age assurance for Cordova apps. One Promise-based JavaScript API (with TypeScript definitions) over the two native platform APIs:
| Platform | Native API | Language | | --- | --- | --- | | Android | Google Play Age Signals API | Kotlin | | iOS | Apple Declared Age Range API | Swift |
Both native layers normalize their platform-specific responses into a single
AgeRangeResult shape so your app can treat them uniformly.
Installation
cordova plugin add @crowdhub/cordova-plugin-age-verificationThe package is published to the CrowdHub npm scope (@crowdhub).
Requirements
Android
minSdkVersion23 or higher, plus AndroidX and Kotlin enabled — set all three in your app'sconfig.xml:<preference name="android-minSdkVersion" value="23" /> <preference name="AndroidXEnabled" value="true" /> <preference name="GradlePluginKotlinEnabled" value="true" />- The Age Signals API only returns data on installs updated by Google Play, and only for users in regions where age data is legally required. Enroll your app in the Play Console and configure your age bands there.
- Pairing with the Play Integrity API is recommended to ensure calls come from a genuine app.
iOS
- iOS 26.0+ at runtime; build with the iOS 26.2 SDK / Xcode 26.2 or later.
- Enable the Declared Age Range capability on your App ID in the Apple
Developer portal. The plugin adds the
com.apple.developer.declared-age-rangeentitlement to your build automatically. - The Swift bridge is wired up via
cordova-plugin-add-swift-support.
Usage
document.addEventListener('deviceready', async () => {
const ageVerification = cordova.plugins.ageVerification;
// Optional: check availability first.
const { supported } = await ageVerification.isSupported();
if (!supported) return;
try {
const result = await ageVerification.requestAgeRange({ ageGates: [13, 16, 18] });
if (!result.available) {
// No age data (declined, unknown region, unsupported OS). Apply your
// most restrictive default experience.
return;
}
const lower = result.lowerBound ?? 0;
if (lower >= 18) {
// adult experience
} else if (lower >= 16) {
// 16–17 experience
} else {
// restricted experience
}
} catch (err) {
console.error('Age request failed', err);
}
});TypeScript
import type { AgeRangeResult } from '@crowdhub/cordova-plugin-age-verification';
const result: AgeRangeResult = await cordova.plugins.ageVerification.requestAgeRange();API
requestAgeRange(options?): Promise<AgeRangeResult>
| Option | Type | Default | Notes |
| --- | --- | --- | --- |
| ageGates | number \| number[] | [18] | Age thresholds the app cares about. Used directly by iOS (up to three values). Ignored on Android, which returns its own Play Console-configured age bands. |
Resolves with an AgeRangeResult:
interface AgeRangeResult {
platform: 'android' | 'ios';
available: boolean; // true when usable age data was provided
status: AgeAssuranceStatus; // normalized status (see below)
lowerBound: number | null; // inclusive lower bound, or null
upperBound: number | null; // inclusive upper bound, or null
declaration: 'selfDeclared' | 'guardianDeclared' | 'confirmed' | null;
raw: AndroidAgeSignals | IosAgeRange; // platform-specific payload
}Normalized status values
| Status | Source | Meaning |
| --- | --- | --- |
| sharing | iOS | User shared an age range. |
| declined | iOS | User declined to share. |
| verified | Android | Age verified (gov ID / payment / estimation). |
| supervised | Android | Supervised account; age set by a guardian. |
| supervisedApprovalPending | Android | Guardian approval pending. |
| supervisedApprovalDenied | Android | Guardian denied approval. |
| declared | Android | User declared their own age. |
| unknown | Android | Not verified/supervised in an applicable region. |
| notAvailable | both | No age data (OS/region/account or error). |
isSupported(): Promise<{ supported: boolean; platform: string; reason?: string }>
Reports whether age assurance is available on the current OS version.
How age data maps across platforms
- Android never returns an exact age; it returns a coarse band
(
ageLower/ageUpper) plus a verification status, and aninstallIdyou can persist to handle revoked guardian approvals. - iOS never returns an exact age either; it returns bounds derived from the
ageGatesyou requested. Apple may override your gates based on the user's region.
Use age data only for age-appropriate compliance — not for advertising, marketing, profiling, or analytics. This is a contractual requirement of both platform APIs.
Releasing
Publishing to npm is automated via GitHub Actions and triggered by publishing a GitHub Release:
- Bump
versioninpackage.jsonandplugin.xml, then commit tomain. - Create a GitHub Release whose tag matches that version (e.g.
v1.2.0). - The publish workflow validates the package,
verifies the tag matches
package.json, and runsnpm publish --access public --provenance.
Requires an NPM_TOKEN repo secret with publish rights to the @crowdhub scope.
License
MIT © CrowdHub
