Skip to main content

Embedded flow

The CDK provides an End-to-End widget that handles the complete Verifiable Parental Consent (VPC) flow within a single interface, covering age gate, VPC, data notices, permissions, and preferences all in one seamless experience.

Using the widgets on mobile

The end-to-end and age gate widgets are fully supported on mobile. Display the widget URL with the same system browser surfaces used for verification URLs and receive the result through the redirectUrl callback. See the mobile apps guide for the display methods.

For the age gate and consent steps, building the UX natively with the custom workflow and the CDK UX guidelines typically delivers the most seamless, brand-integrated player experience. The widget UI works on mobile today and its mobile UX is being continuously optimized.

What's the end-to-end widget?

The End-to-End Widget is a comprehensive solution that handles the complete compliance flow in a single interface, covering age gate, VPC, data notices, permissions, and preferences all in one seamless experience. This widget can be used by parents either on the child's device or on their own device, providing maximum flexibility for the consent process.

Generating the widget URL

Call the /widget/generate-e2e-url API to create an end-to-end widget URL that handles the complete VPC flow. This returns a unique URL for users to complete the age collection and parental consent process.

Example request

POST /api/v1/widget/generate-e2e-url
Content-Type: application/json
Authorization: Bearer your-api-key

{
"jurisdiction": "US-CA"
}

Configuration flags

The optional flags parameter allows you to customize which parts of the flow to skip:

  • skipDataNotices: Skip data notices and consent collection
  • skipVerification: Skip verification step
  • skipPermissions: Skip permission management
  • skipPreferences: Skip preference settings

Pass a platform age signal (optional)

If your game already has age data from the platform (Apple iOS, Google Play, Xbox, Meta Horizon, or a prior k-ID verification), include it as platformAgeSignal in the request body. The widget forwards the signal to the underlying age-gate check so it can skip the age gate when a verified signal indicates an adult, satisfy verified-age permissions without an extra verification step, and detect conflicts between the signal and the player's self-reported age.

POST /api/v1/widget/generate-e2e-url
Content-Type: application/json
Authorization: Bearer your-api-key

{
"jurisdiction": "US-CA",
"platformAgeSignal": {
"name": "apple-ios",
"ageLow": 18,
"ageHigh": 25,
"declarationType": "governmentIDChecked"
}
}

For the supported platforms and field shapes, see Platform age signals.

Example response

{
"id": "7854909b-9124-4bed-9282-24b44c4a3c97",
"url": "https://family.k-id.com/widget?token=eyJhbGciOiJFUzM4NCIs..."
}

Presenting the widget URL

The widget URL is a hosted web page. Open it in the surface that fits your application:

  • Web app: embed in an iframe (example below), open as a pop-up, or redirect to it as a full page.
  • Mobile app: open the widget URL in a system browser surface (Custom Tabs on Android, ASWebAuthenticationSession on iOS) and pass options.redirectUrl to receive the result as a deep link back into your app. See the Mobile apps quick start for the display methods. For the most brand-integrated experience, consider building the age gate and consent UX natively with the custom workflow instead.
  • Console (Switch, PlayStation, Xbox): console browsers are typically restricted or absent. Display the widget URL as a QR code so the player completes the flow on a paired mobile device. Receive results via webhook plus /session/get polling, since the mobile-device redirect can't return to the console.

The available methods inside the widget automatically adapt to jurisdictional requirements regardless of host.

Web example

<div id="vpc-container">
<iframe
id="vpc-widget"
src="WIDGET_URL"
width="100%"
height="600"
frameborder="0"
allow="camera;payment;publickey-credentials-get;publickey-credentials-create">
</iframe>
</div>

For mobile surfaces, pass options.redirectUrl when calling /widget/generate-e2e-url and handle the callback in your app. See the Mobile apps quick start for end-to-end examples.

Handling events

Where DOM events reach you

The JavaScript events below (Widget.AgeGate.Result, Widget.AgeGate.Challenge, Widget.ExitReview) are delivered via postMessage. To receive them, your app needs a live JavaScript listener for the widget window. That covers iframes, pop-ups opened via window.open, and mobile WebView / WKWebView with a JS bridge (see the Mobile apps quick start). System browser components (ASWebAuthenticationSession, SFSafariViewController, Chrome Custom Tabs) and full-page top-level redirects don't expose a listener, so they receive results via the redirectUrl callback and confirm server-side with /session/get or webhooks.

When the age gate flow completes, a session is created to store the player's permissions and age status. A challenge is created whenever the flow needs one, either for Verifiable Parental Consent or for Automatic age assurance when the player claims an age old enough to skip parental consent.

The widget emits JavaScript events that you can listen to. Listen for the Widget.AgeGate.Result event, which includes a sessionId when the flow completes successfully. If a challenge was created during the flow, the event also includes the challengeId. For detailed information about challenge-specific events, see Widget.AgeGate.Challenge.

Closing the UI

Listen for the Widget.ExitReview event to determine when to close the widget UI. This event is emitted when the user clicks the 'Done' button, indicating the flow is complete and the iframe should be closed or hidden.

window.addEventListener('message', (event) => {
if (!event.origin.endsWith('.k-id.com')) {
return;
}

const message = event.data;

if (message.eventType === 'Widget.AgeGate.Result') {
if (message.data.status === 'PASS') {
const sessionId = message.data.sessionId;

// If challengeId is present, a challenge was resolved during the flow
// (for example, parental consent or auto age-assurance).
if (message.data.challengeId) {
console.log('Challenge resolved, session issued:', sessionId);
} else {
console.log('Session created (no challenge required):', sessionId);
}

grantAccess(sessionId);
}
}

// Handle challenge-specific events if needed
if (message.eventType === 'Widget.AgeGate.Challenge') {
if (message.data.status === 'FAIL') {
// Parent denied consent - restrict access
console.log('Consent denied');
restrictAccess();
}
}

if (message.eventType === 'Widget.ExitReview') {
// Close the widget UI when the user clicks 'Done'
closeWidget();
}
});

What the widget handles

The widget automatically handles:

  • Age Collection: Jurisdiction-appropriate age collection methods
  • Data Notices: Data notices to accept, depending on the product's configuration in the Compliance Studio
  • Permissions: Permissions to manage, depending on the product's configuration in the Compliance Studio
  • Parental Consent Challenge: If the user is determined to be a minor, a challenge is created for trusted adult approval
  • Automatic age assurance: If the product has Automatic age assurance enabled for the jurisdiction, players who claim an age old enough to skip parental consent are asked to prove the claim (facial age estimation or ID document) inside the widget before a session is issued.

The specific flow depends on the jurisdiction and your product's configuration in the Compliance Studio.

Session creation timing with Automatic age assurance

When Automatic age assurance triggers inside the end-to-end widget, the session is created after the player passes verification rather than immediately after the age gate. The Widget.AgeGate.Result event is still fired once the flow completes and includes the sessionId on PASS. Until the event arrives, treat the flow as in progress.

For more information on implementing VPC, see the Quick Start Guide.