Docs · Reference
JavaScript SDK
@ageassure/js opens a session’s hosted url in a centered popup and reports the result — no iframe, no polling on your end. Zero dependencies, built as both an ES module and a ~1.5 kB minified script-tag build.
Install
Via npm
npm install @ageassure/jsimport { AgeAssure } from "@ageassure/js";
AgeAssure.open({
url: session.url, // from POST /v1/verification-sessions
onComplete: ({ sessionId, status }) => {
if (status === "passed") {
// unlock whatever was age-gated
} else {
// show the "not verified" state — offer another method or exit
}
},
});Via a script tag
No build step: download ageassure.min.js from the @ageassure/js npm package’s dist/ folder and self-host it (a hosted CDN URL is coming — this page will be updated with it). It defines a single window.AgeAssure global with the same open() API.
<script src="/vendor/ageassure.min.js"></script>
<script>
AgeAssure.open({
url: session.url,
onComplete: function (result) {
console.log(result.sessionId, result.status);
},
});
</script>AgeAssure.open(options)
| Field | Type | Description |
|---|---|---|
urlrequired | string | The session url from POST /v1/verification-sessions. |
onCompleterequired | (result) => void | Called once with { sessionId, status } where status is "passed" or "failed", when the session reaches that outcome. |
onClose | () => void | Popup mode only. Called if the user dismisses the popup before a result arrives — a distinct outcome from failed, since nothing was actually checked. |
mode | "popup" | "redirect" | "popup" (default): open a ~480×760 centered popup. "redirect": navigate the current page to url instead — onComplete/onClose are never called in this mode, since the page navigates away; rely on the return_url redirect and/or a webhook instead. |
Returns a handle with a close() method for tearing things down early (e.g. on your own component unmount) — most callers can ignore the return value.
Popup vs. redirect
Popup mode keeps the user on your page — best when verification gates a specific action (posting, checking out) without losing where they were. If the popup is blocked, the SDK falls back to a full-page redirect automatically, so a call to open() is never a dead click.
Redirect mode is simpler when the whole page is behind the gate (e.g. an age-restricted landing page) — send the user, and let return_url plus a webhook carry the result back, exactly as described in the quickstart.
The postMessage contract
Under the hood, the hosted flow’s result screen posts one message to window.opener before it redirects/closes:
{ "type": "ageassure:result", "sessionId": "vs_...", "status": "passed" }It’s sent with target origin "*" — the payload carries no secret, only a session id and a pass/fail status. The SDK checks the message’s type and shape before acting on it, and as defense in depth also drops any message whose event.origin doesn’t match the origin of the url you opened. If you’re handling the postMessage yourself instead of using the SDK, confirm result.sessionId matches a session you actually created before trusting status — see the full example below.
Full example
import { AgeAssure } from "@ageassure/js";
async function startVerification() {
const res = await fetch("/api/verify/start", { method: "POST" }); // your own server route,
const session = await res.json(); // which calls AgeAssure's API
AgeAssure.open({
url: session.url,
mode: "popup", // default — "redirect" navigates the current page instead
onComplete: ({ sessionId, status }) => {
if (sessionId !== session.id) return; // defense in depth — see below
renderResult(status);
},
onClose: () => {
// user closed the popup before finishing — no result yet
renderDismissed();
},
});
}