Skip to content

Guest to registered — try before register

The “try before register” UX is one of the most effective ways to reduce sign-up friction. Rakomi supports it natively via anonymous sign-ins and a lossless claim operation: the users.id is preserved across the transition, so any data your app attached to the guest (cart, metadata, preferences) follows the user into their registered account without any migration code.

Positioning. Unlike enterprise-only providers (Stytch, WorkOS), Rakomi supports guest sessions for consumer and B2C workloads. Firebase’s linkWithCredential() and Supabase’s anonymous sign-ins cover the same shape — Rakomi’s claim flow reads as the OAuth-ecosystem-neutral equivalent.

┌──────────────────┐ POST /v1/auth/anonymous ┌──────────────────────┐
│ Visitor lands │──────────────────────────▶│ Guest session │
│ (no account) │ │ is_anonymous: true │
└──────────────────┘ └──────────┬───────────┘
│ user fills cart
│ submits order
POST /v1/auth/register + anon bearer
┌──────────────────────┐
│ Registered user │
│ same users.id │
│ is_anonymous: false │
│ claimed_at: now() │
└──────────────────────┘

Anna lands on your storefront without an account. She adds items to her cart, reaches checkout, and only then registers. You want the cart to survive the registration.

1. Mint a guest session when the user interacts

Section titled “1. Mint a guest session when the user interacts”
import { useAnonymousSignin, useAuth } from '@rakomi/react';
export function AddToCartButton({ productId }: { productId: string }) {
const auth = useAuth();
const { signIn } = useAnonymousSignin();
async function onAdd() {
if (!auth.isLoaded) return;
if (!auth.isSignedIn) {
// Create the guest on the first "Add to cart" click — NOT on page load
// (Minimise MAU churn: zero-intent visits do not consume MAU).
await signIn({ publicMetadata: { entry_point: 'product_page' } });
}
await fetch('/api/cart', { method: 'POST', body: JSON.stringify({ productId }) });
}
return <button onClick={onAdd}>Add to cart</button>;
}

On the server side, key the cart by users.id (e.g. user_id column or document key). Because the id does not change at claim time, you do not need to migrate anything.

import { useAuth } from '@rakomi/react';
export function CheckoutRegisterForm() {
const { getToken } = useAuth();
async function onSubmit(email: string, password: string) {
const token = await getToken();
if (!token.ok) return;
await fetch('/v1/auth/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token.token}`,
'X-API-Key': process.env.NEXT_PUBLIC_RAKOMI_API_KEY!,
},
body: JSON.stringify({ email, password, consent: true }),
});
// The underlying users.id is unchanged — the cart survives.
}
// ...
}

After registration, auth.user.isAnonymous flips to false on the next token refresh. The session remains valid, the cart remains valid — no “welcome back, please re-add” dialog necessary.

Unclaimed guests are hard-deleted by a daily cron at 02:30 UTC once last_active_at exceeds the tenant’s configured retention (1–90 days, default 30). See Settings → Authentication → Anonymous in the dashboard.

In addition to email + password, a guest can claim their session by signing in with a social provider (Google, GitHub, Microsoft, Apple, Discord, Facebook, Slack, Twitter/X, GitLab, LinkedIn). The flow is identical from the developer’s perspective: send the anonymous bearer on the /oauth/{provider}/authorize initiate call, then let the user complete the provider’s consent screen. The callback will update the same users.id in place — no new user row is created, and every FK-keyed downstream row (sessions, metadata, org memberships) carries over exactly as in the email-claim flow. never_trust providers (Facebook, Twitter) are the exception: per industry-standard anti-takeover practice, they do NOT promote the anon row by email and instead create a fresh account.

  • Tokens and sessions — the anonymous bearer is revoked at claim time; the user is expected to re-authenticate with the regular post-registration flow.
  • Data that is explicitly keyed on “is anonymous” state (rare — most apps key by user_id).

Anonymous users count toward your MAU quota from the moment they are created. Hard deletion mid-month does not refund MAU credit — this mirrors the Rakomi MAU-peak billing model (see the pricing page) and is consistent with industry practice.

  • API reference: Anonymous sign-ins
  • Security posture: short-lived pseudonymous identifier, no PII on the user row, GDPR Art. 4(5) pseudonymisation.