Headless / JS API
Everything the components do is available programmatically. Import Auth and getUnidyClient from the SDK module to read auth state, call the profile/newsletter/ticket/subscription APIs directly, and combine the results with any library — no u-* markup required.
View this guide as MarkdownAuth state from JavaScript
authState is the same reactive store the components use: read authState.authenticated for the current value and subscribe with onAuthChange for updates. Session restore runs asynchronously on page load, so reacting to the store — instead of a one-shot check — is the reliable pattern. Auth.Errors exposes stable error codes for handling specific sign-in failures.
- authState store — current auth state, shared with the components
- onAuthChange() — subscribe to sign-in/sign-out transitions
- Auth.Errors — stable error-code constants
<div class="rounded-lg border border-border bg-background-light p-4">
<p class="text-sm">
Authentication status:
<strong id="auth-status" class="font-mono">checking…</strong>
</p>
</div>
<script type="module">
// The same module the components use — import it for headless access
import {
authState,
onAuthChange,
Auth,
} from "https://cdn.jsdelivr.net/npm/@unidy.io/sdk@1.8.1/dist/sdk/index.esm.js";
const render = (authenticated) => {
document.getElementById("auth-status").textContent = authenticated
? "authenticated"
: "not authenticated";
};
// authState is a reactive store: read it now, subscribe for changes.
// (Session restore is async on page load — never rely on a one-shot check.)
render(authState.authenticated);
onAuthChange("authenticated", render);
// Auth.Errors holds stable error codes for the sign-in process,
// e.g. Auth.Errors.email.NOT_FOUND === "account_not_found"
console.log("Known email errors:", Auth.Errors.email);
</script> Authentication status: checking…
API calls with getUnidyClient
getUnidyClient() exposes typed services — profile, newsletters, tickets, subscriptions, auth. Calls return a [error, data] tuple, so error handling is a destructure instead of try/catch.
- client.profile.get() / .update() — read and write profile data
- [error, data] tuples — predictable error handling
- All feature areas — newsletters, tickets, subscriptions, auth
<div class="flex flex-col gap-3">
<button id="load-profile" class="btn btn-primary !min-h-0 !px-4 !py-2 w-fit text-sm">
Load my profile via the API
</button>
<pre
id="profile-output"
class="overflow-x-auto rounded-lg bg-background-light p-4 font-mono text-xs text-text-light">(click the button — requires being signed in)</pre>
</div>
<script type="module">
import { getUnidyClient } from "https://cdn.jsdelivr.net/npm/@unidy.io/sdk@1.8.1/dist/sdk/index.esm.js";
document.getElementById("load-profile").addEventListener("click", async () => {
const output = document.getElementById("profile-output");
// getUnidyClient() reads its config from <u-config> on the page.
// Every service call returns a [error, data] tuple — no try/catch needed.
const client = getUnidyClient();
const [error, profile] = await client.profile.get();
output.textContent = error
? `Error: ${JSON.stringify(error, null, 2)}`
: JSON.stringify(profile, null, 2);
// Also available: client.newsletters, client.tickets, client.subscriptions, client.auth
});
</script> (click the button — requires being signed in)
Mix with any library: profile QR code
SDK data is just data — here the signed-in user's name is fetched via the client and rendered as a QR code with a third-party library. The same pattern powers loyalty cards, wallet passes, or personalized widgets.
- SDK + npm ecosystem — combine with any client-side library
- u-signed-in gating — components and JS API work together
<u-signed-in>
<!-- Combine SDK data with any third-party library — here: a QR code
encoding the user's name, rendered fully client-side -->
<canvas id="profile-qr-canvas" width="200" height="200"></canvas>
</u-signed-in>
<u-signed-in not>
<p class="text-text-light">
Sign in on the <a href="/auth" class="text-primary underline">Auth page</a> to see your profile QR
code.
</p>
</u-signed-in>
<script type="module">
import QRCode from "https://esm.sh/qrcode@1.5.4";
import {
authState,
onAuthChange,
getUnidyClient,
} from "https://cdn.jsdelivr.net/npm/@unidy.io/sdk@1.8.1/dist/sdk/index.esm.js";
async function renderQr() {
const [error, profile] = await getUnidyClient().profile.get();
if (error) return;
const name = [profile.first_name?.value, profile.last_name?.value].filter(Boolean).join(" ");
QRCode.toCanvas(
document.getElementById("profile-qr-canvas"),
`Hello, ${name || "Unidy user"}!`
);
}
// Session restore is async on page load, so react to auth state instead
// of checking once
if (authState.authenticated) renderQr();
onAuthChange("authenticated", (authenticated) => authenticated && renderQr());
</script>