Amba
Platform

Local development

Run your Amba-powered app on localhost — what works in vite, next dev, expo, and React Native, and the one gotcha with magic-link callbacks.

The Amba browser SDK is designed to work in local development out of the box. Browser CORS preflight from http://localhost:* (or http://127.0.0.1:*, or http://[::1]:*) is allowed against https://api.amba.dev for every Amba project — no extra config, no proxy, no signed certificate.

This page covers what works, what doesn't, and the workarounds for the cases that don't.

What works

  • @layers/amba-web under vite dev, next dev, react-scripts start, parcel, webpack-dev-server, and any framework that serves on localhost over HTTP. Every wrapped namespace (auth, events, entitlements, config, collections, flags, storage) goes through the same fetch path and the same CORS rules.
  • @layers/amba-expo under npx expo start. Expo runs your app in the Expo Go shell (or a development build on a device). API calls go out from the device's network — no browser CORS involved.
  • @layers/amba-react-native under npx react-native start. Native fetch, no CORS.
  • @layers/amba-node under node --watch, tsx watch, nodemon, or any reload-on-save runner. Server-side, no CORS.

Point apiUrl at production from your local environment:

await Amba.configure({
  projectId: process.env.AMBA_PROJECT_ID!,
  clientKey: process.env.AMBA_CLIENT_KEY!,
  apiUrl: 'https://api.amba.dev',
});

Everything tracked, fetched, or mutated during local dev hits the same project as your deployed app. If you don't want that — see Use a separate dev project below.

What doesn't work (and the workaround)

Magic-link emails ship the verify URL pinned to your project's deployed app URL (https://your-app.app.amba.host or your verified custom domain). Clicking a link from a localhost run lands you in the deployed app, not your local dev server.

Workarounds:

  • Use email/password or anonymous auth during local dev. Magic-link is an intent verification flow — testing it on localhost is the same as testing it on production, since the verify URL is project-scoped.
  • Forward the verify URL to localhost. Click the link, then copy the ?token=… query param onto your localhost URL: http://localhost:3000/auth/callback?token=…. The token validates server-side; the redirect URL never reaches the API.

Cross-origin cookies

The SDK uses header authentication, not cookies — X-Api-Key on every request, Authorization: Bearer <session_token> after sign-in. So cross-origin cookie restrictions don't apply. If you're seeing cookie warnings in dev tools, those are from your own app, not the SDK.

Service workers + offline mode

If your local dev server doesn't run a service worker (vite dev / next dev usually don't), the SDK's offline event queue is still active but uses localStorage exclusively. Events written while you're disconnected from the network will be flushed on reconnect.

Use a separate dev project

Keep your live tenant clean by running local dev against a second Amba project — same SDK code, different keys, separate database.

  1. Sign up a sandbox project: npx @layers/amba init --sandbox (or via the agentic flow: amba_developer_signup then amba_projects_create with tier: "sandbox").

  2. Put its keys in .env.local:

    AMBA_PROJECT_ID=<sandbox project id>
    AMBA_CLIENT_KEY=<sandbox client key>
  3. Reset the sandbox at any time with the SDK helper:

    await Amba.dev.resetSandbox();

    This wipes every user, event, and collection row in the sandbox tenant — the project itself stays, so your keys keep working. Only callable against sandbox-tier projects; production tenants reject it with NOT_SANDBOX_TIER.

Security model recap

The SDK is always authenticated by X-Api-Key (your project's clientKey). The clientKey is browser-public by design — it's safe to ship in JavaScript bundles, embed in mobile apps, or paste into a dev environment. Every client request also carries either an anonymous device ID or, after sign-in, a Bearer session token.

CORS is defense-in-depth, not the security boundary. We allow localhost origins on the API because letting any origin with a valid clientKey call the API is the same posture as allowing every *.app.amba.host customer-app subdomain, which we already accept. The boundary that matters is the clientKey + Bearer token combination, not the request Origin header.

On this page