Set up browser posture
Set up browser posture with the kya-os CLI, serve the beacon from your own domain, verify the signed token on your server, and check the result on a live page
Browser posture gives your server a signed copy of Checkpoint's verdict on a browser session, so a protected request can carry it. This page takes the CLI path to a verified token on a live page.
A verified token shows that Checkpoint issued it for this page and this session, and it carries Checkpoint's verdict. It doesn't identify the visitor. A server that finds no token, or a refused one, should treat the request as having no posture, never as permission.
Prerequisites
kya-os2.3.1 or later, signed in withkya-os login. Posture calls use your management sign-in. Changing origins needs write access to the project.@kya-os/checkpoint-beacon1.4.3 or later on the pages. The CLI installs the release it verified. Below 1.4.3 it installs the beacon without posture wiring and prints a note; the reference has the version rules.- Pages served over HTTPS. The beacon doesn't store the token on other pages.
- A server or edge you control that can read two request headers and verify an ES256 signature.
Add the beacon and set its origins
Every project has a posture key, so there is nothing to turn on. Add the beacon and set the page origins in one command:
kya-os setup --surface beacon --origins https://www.example.com,https://shop.example.comkya-os detect install takes the same flags: --origins and --proxy. The flag tables list them and how the CLI normalizes each origin.
--origins replaces the project's additional origins, so an origin you leave out is removed. On
setup, --origin (singular) is the Checkpoint address you sign in to. Page origins are
--origins (plural).
Checkpoint issues a token only to pages on the project's domain and the origins you list. Wildcards, the apex rule, and the limit of 20 are in Verifying the posture token.
Without a terminal, the CLI asks nothing and leaves the origins as they are unless you pass --origins. Signed out, detect install notes that browser posture was not configured and carries on. The reference lists the terminal prompt and every other case.
The CLI then checks the key and prints key: confirmed at the keys endpoint or key: not confirmed, with a note that says why. --json output carries keyConfirmed. The reference has the retry rules. Tokens start flowing within 10 minutes, and Verifying the posture token explains the delay.
Check what the CLI wrote
Before it installs the beacon, the CLI checks the release against the npm registry and jsDelivr, and installs nothing if either check fails. The reference has the checks, the pinning rules, and the table by stack. For posture:
- Self-hosted files. For an HTML page with a static directory,
beacon.worker.jsgoes into_checkpoint/<version>/at any beacon version. For a package install at beacon 1.4.3 and later, bothbeacon.worker.jsandbeacon-lazy-signals.min.jsgo into_checkpoint/<version>/under your static directory (public/for Next.js). The CLI setsworkerUrl, andlazySignalsUrlwhere it wrote the chunk, to those paths, so a page with a strict Content-Security-Policy can load them from its own origin. - A header helper. The generated code exports
checkpointPostureHeaders(), orwindow.checkpointPostureHeaders()in an HTML page. It returnsKYA-Posture-Sessionalways andKYA-Posturewhile the latest token hasn't expired.
Use the helper on requests to a protected API on another host, where the beacon's host-only cookies don't travel:
import { checkpointPostureHeaders } from './checkpoint-detect';
await fetch('https://api.example.com/generate', {
method: 'POST',
headers: { ...checkpointPostureHeaders() },
});For a cross-origin request, add both header names to the API's Access-Control-Allow-Headers: KYA-Posture, KYA-Posture-Session. The CLI prints that line with the verifier configuration.
Serve the beacon through your own domain
A strict Content-Security-Policy may not allow connect-src https://kya.vouched.id or a script from a CDN. --proxy moves both onto your origin under a path you choose:
kya-os detect install --surface beacon --proxy /_cpThe beacon's endpoint becomes /_cp/api/v1/beacon, which your domain forwards to https://kya.vouched.id/api/v1/beacon. The forwarding uses Forward edge evidence: your edge sets X-API-Key and KYA-Forwarded-IP on the proxied request, and Checkpoint scores it with the visitor's address instead of your proxy's.
The proxy key has the proxy purpose, which carries only the forward permission: it authenticates forwarded evidence and nothing else. It's shown once, and minting needs a project owner or admin. Signed in, the CLI stores it as CHECKPOINT_PROXY_KEY in a gitignored env file and never prints it. Signed out, it tells you to sign in and re-run, or to set the variable yourself.
For Next.js, the CLI writes a helper, checkpoint-beacon-proxy.ts, and one entry file. For nginx, Cloudflare, and Akamai, it prints the configuration for you to add and applies nothing. Checkpoint hasn't verified the printed Akamai rule against a live property, so test it in staging. The reference lists each target.
Every generated proxy removes the visitor's Cookie and Authorization headers. The Next.js
proxy and the Cloudflare Worker also remove every KYA-Forwarded-* header the visitor sent. The
nginx block and the Akamai rule clear only three KYA-Forwarded-* headers by name (JA4,
challenge, challenge-id), so delete any other KYA-Forwarded-* header yourself.
On Vercel and other hosts, .env.local isn't deployed. Set CHECKPOINT_PROXY_KEY in the host's
environment too.
With the proxy in place, connect-src needs only 'self', and script-src needs only 'self' when the script is self-hosted. The CLI prints the exact directives for your install. The reference lists what each one needs, including when to add base-uri 'none' and trusted-types checkpoint-beacon.
Verify the token on your server
Your server reads the KYA-Posture and KYA-Posture-Session headers, or the matching cookies on the same host. Verifying the posture token has the precedence, cookie names, and token format.
The server SDKs verify for you. They need the project's UUID (the lowercase UUID, not the friendly id), the key, and the page origin. Get the key id and public JWK from any of these:
- The Next.js, Express, or ASP.NET Core block the CLI prints on every
setupanddetect installrun. The Java block carries the keys URL only, and no block prints without a usable page origin. posture.state.keyIdandposture.state.publicJwkin--jsonoutput.- The Installations card in step 6.
The examples read them from environment variables. For a server that answers for several origins, list the extras next to the primary:
export default withCheckpoint({
projectId: '<lowercase project UUID>',
browserPosture: {
origin: 'https://www.shop.example',
origins: ['https://checkout.shop.example', 'https://*.shop.example'],
keyId: process.env.CHECKPOINT_POSTURE_KEY_ID!,
publicKey: JSON.parse(process.env.CHECKPOINT_POSTURE_PUBLIC_JWK!),
},
});SDK verifiers compare the token's signed origin claim with origin and origins, then check that aud names the same origin. They ignore the request's Host and Origin headers. The gateway needs no configuration: it matches the request's origin against the project's domain and additional origins, then checks the token against the match.
A refused token doesn't stop the request, grant an allow, or override a block. The request proceeds as if it carried no posture. The only trace is telemetry: the SDK sends postureOutcome with status of verified, absent, or rejected, and a reason on every rejected, to POST /api/v1/log-detection.
Read the outcome in your handler
In Java, .NET and Express the middleware or filter has already verified the token, so your handler can read the result instead of verifying it a second time. In Next.js the accessor verifies the token itself. Every runtime gives you the same three statuses (verified with the verified claims, absent, or rejected with a reason). verified means the token's signature and claims are valid, not that the visitor is human: check the verdict in the claims. In the Java, .NET and Express middleware a missing result means the request was not checked, which is not the same as absent: treat it as unknown before you gate an action on it. The Next.js accessor verifies the token itself, so it always returns a status.
PostureOutcome posture = (PostureOutcome) request.getAttribute(PostureOutcome.REQUEST_ATTRIBUTE);
if (posture != null && posture.status() == PostureOutcome.Status.VERIFIED) {
BrowserPosture claims = posture.posture().orElseThrow();
// check claims.verdict() before treating the visitor as human
}Check the page with detect doctor
kya-os detect doctor fetches a live page and reports whether the beacon and its posture path can work there:
kya-os detect doctor --url https://www.example.comIt reads the page's HTML, then probes the files and headers the beacon needs. Each check reports ok, info, warn, or fail, and the command exits 1 if any check fails. The reference lists every check and the scan limits. These catch most posture problems:
A failing run:
Checked https://staging.example.com/
[ok ] page: https://staging.example.com/ answered 200
[ok ] beacon script integrity: the served bytes match the page's integrity hash
[FAIL] posture origin: https://staging.example.com is not among the allowed origins (https://www.example.com, https://shop.example.com)
fix: Run: kya-os detect install --surface beacon --project <project uuid> --origins 'https://shop.example.com,https://staging.example.com' (--origins replaces the whole list, so this keeps the current additional origins)
1 problem(s) found.The doctor doesn't check that your page forwards KYA-Posture headers to your API or that the API allows them in CORS. Test that with a real request.
Watch it in Installations
Open Installations in the project's dashboard, at /dashboard/<org>/<project>/installations. The Browser posture card shows:
Anyone who can read the project sees the health view. Editing origins needs write access.
Posture health shows the share of responses issued a token, then a row per status and origin: Issued, Origin not allowed, Site URL not set, Signer unavailable, or State unavailable.
Counts are approximate: Checkpoint counts responses as they happen, not from stored detections, and buffers repeats briefly, so a burst can undercount. Each row's origin is what the browser reported, and it isn't verified. Each hour keeps 50 named origins per status and sums the rest as other origins, not listed. A flood of made-up origins can't hide your totals, though it can push a rarely seen real origin into that row. An origin's first occurrence in each short window is written straight away, so your own first page load shows up at once.
Common problems
Next steps
A token can also carry the beacon's own agent or bot verdict in an optional detection claim, which the server SDKs use to reclassify a request the server had called human. Verifying the posture token has the token's claims, for a stack the SDKs don't cover. Forward edge evidence covers the proxy headers and key checks. The CLI reference lists every flag, file, and JSON field.
