SDKsPreview · 3 min read

Browser SDK


Use @perkamo/browser only with short-lived browser tokens returned by your own backend after it calls Perkamo. Never put a Perkamo server API key in browser, mobile or embedded widget code. The browser package is preview and requires Perkamo client routes to be enabled for the integration.

Browser integrations are always a backend plus frontend implementation. The frontend package calls your backend first; your backend verifies the user's application session, calls Perkamo with a server key and returns a short-lived browser token. /api/perkamo/token below is your application route, not a Perkamo API route.

Install with a bundler

bash

npm install @perkamo/browser

ts

import {
createPerkamoBrowserClient,
mountPerkamoProgressWidget,
} from "@perkamo/browser";

const client = createPerkamoBrowserClient({
getToken: async () =>
(await fetch("/api/perkamo/token", { method: "POST" }))
.json()
.then((body) => body.token),
});

const customer = await client.getCustomerJson();
document.querySelector("#points").textContent = String(customer.wallets.points ?? 0);

mountPerkamoProgressWidget({ client, target: "#perkamo-progress" });

Load from CDN

For storefronts or widgets without a bundler, load the standalone browser build from the free jsDelivr npm CDN:

html

<script src="https://cdn.jsdelivr.net/npm/@perkamo/browser@0.6.0/dist/perkamo-browser.global.min.js"></script>

The CDN build exposes window.PerkamoBrowser. Pin the package version so production pages load a reviewed browser bundle. UNPKG serves the same npm package as an alternative: https://unpkg.com/@perkamo/browser@0.6.0/dist/perkamo-browser.global.min.js.

html

<script src="https://cdn.jsdelivr.net/npm/@perkamo/browser@0.6.0/dist/perkamo-browser.global.min.js"></script>
<script>
const client = PerkamoBrowser.createPerkamoBrowserClient({
getToken: () =>
fetch("/api/perkamo/token", { method: "POST", credentials: "include" })
.then((response) => response.json())
.then((body) => body.token),
});

PerkamoBrowser.mountPerkamoProgressWidget({
client,
target: "#perkamo-progress",
});
</script>

Backend token route

The browser package does not create tokens by itself. Your backend route should verify the logged-in user and ask Perkamo to issue a short-lived token. Browser key access policy is configured in Perkamo and enforced server-side. The token request does not send scopes or event allowlists. Use * on the browser key to allow all current and future configured events. New browser keys default to the full browser SDK policy: customer reads, allowed browser events and customer streams. The package then calls preview /v1/client/* routes with that token; until those routes are enabled, return already-filtered customer state from your own backend instead.

php

$token = $perkamo->createBrowserToken(
browserKey: getenv('PERKAMO_BROWSER_KEY'),
userId: $currentUser->id(),
ttlSeconds: 600,
);

Customer data

getCustomerJson() returns a JSON-safe customer snapshot for storefront or app UI code. It omits traits by default; pass { includeTraits: true } only for pages that explicitly need customer traits.

Customer streams require a separate getStreamToken provider so regular bearer tokens are not written into EventSource URLs. Browser client routes and stream verification are preview until enabled for a customer integration.

Handle API errors

Non-2xx client-route responses throw PerkamoApiError. The error includes the HTTP status, parsed body and operational metadata when available:

ts

try {
await client.emit("page.viewed", { path: location.pathname });
} catch (error) {
if (error instanceof PerkamoBrowser.PerkamoApiError) {
console.error(error.status, error.requestId, error.retryAfter, error.rateLimit);
}
}

Security defaults

The browser package accepts only getToken, never a server API key, and rejects secret-shaped runtime options before sending requests. It also rejects server-authoritative event context fields such as xp, wallet, wallets, level, perks, rewards and achievements.

The browser client defaults to the hosted Perkamo API. Set baseUrl only for a custom, staging or private endpoint.

Read Security and keys before shipping a browser or mobile integration.