API reference
This page documents version 0.1.0 of the @snap/web-lens-api package, generated from its type declarations. Web Lens API explains how to add the API to a Lens, and the Leaderboards, Bitmoji, and Storage guides show each capability in use.
Snapchat Web Lens API (window.snapchat) — one include for iOS, Android, and desktop development.
Put the built file in your game's zip (the one you upload to My Lenses, with index.html at its root):
the Lens CSP blocks runtime fetches by design.
await snapchat.init();
if (snapchat.isSupported('leaderboards')) {
await snapchat.leaderboards.submitScore({ leaderboardId: 'main', score: 42 });
await snapchat.leaderboards.show();
}
Variables
errors
const errors: WebLensAPIErrors;
Stable error codes. A rejected call's error.message is always one of these.
snapchat
const snapchat: SnapchatWebLensAPI;
The singleton also installed as window.snapchat.
Example
// With a bundler or native ES modules:
import snapchat from '@snap/web-lens-api';
// With a classic <script src="snap-api.js"> include, use window.snapchat directly.
Interfaces
WebLensAPIErrors
Stable error codes. A rejected call's error.message is always one of these; native error text
never crosses the bridge.
Example
try {
await snapchat.storage.set('replay', frames);
} catch (e) {
// The store is unchanged, so the previous save is still intact.
if (e.message !== snapchat.errors.QUOTA_EXCEEDED) throw e;
await snapchat.storage.remove('replay');
}
Properties
| Property | Modifier | Type | Description |
|---|---|---|---|
MALFORMED_REQUEST | readonly | "ERR_MALFORMED_REQUEST" | The request envelope or app://<capability>/<action> URI failed validation (API bug — file it). |
UNKNOWN_CAPABILITY | readonly | "ERR_UNKNOWN_CAPABILITY" | No handler is registered for the capability on this app version / surface. Check SnapchatWebLensAPI.isSupported first. |
INVALID_PARAMS | readonly | "ERR_INVALID_PARAMS" | The capability rejected the params against its allowlist. |
INTERNAL | readonly | "ERR_INTERNAL" | The capability failed internally; details stay in native logs. |
QUOTA_EXCEEDED | readonly | "ERR_QUOTA_EXCEEDED" | A storage write would exceed the per-Lens byte or key-count quota; the store is unchanged. |
STORAGE_UNAVAILABLE | readonly | "ERR_STORAGE_UNAVAILABLE" | storage has no durable backing on this device or session. |
UNSUPPORTED_HOST | readonly | "ERR_UNSUPPORTED_HOST" | API-only: the page runs inside Snapchat, but this app version or its WebView can't serve the API (the host injected no bridge). Every call rejects with it, so hide the feature. |
SubmitScoreParams
Properties
SubmitScoreResult
Properties
| Property | Type | Description |
|---|---|---|
bestScore? | number | The player's best score on this board, as the server acknowledged it; absent when the backend omits it. |
Get2DAvatarParams
Properties
| Property | Type | Description |
|---|---|---|
variant? | string | Variant id from BitmojiAPI.getVariants; omit for the default portrait. |
size? | "small" | "medium" | "large" | Defaults to 'medium'. |
MediaURL
Properties
| Property | Type | Description |
|---|---|---|
url | string | Same-origin, opaque and ephemeral (~5 min): fetch or render promptly, never parse, re-call on error. The shape differs between the stub and a device. |
StorageInfo
Properties
LeaderboardsAPI
Native leaderboards (leaderboards capability, v1). Only Lenses configured with the leaderboard
module see it in SnapchatWebLensAPI.init.
Methods
submitScore()
submitScore(params): Promise<SubmitScoreResult>;
Submits a score to one board.
Parameters
| Parameter | Type |
|---|---|
params | SubmitScoreParams |
Returns
Promise<SubmitScoreResult>
Example
// A time trial: lower is better, so say so on every submission.
const { bestScore } = await snapchat.leaderboards.submitScore({
leaderboardId: 'fastest-lap',
score: Math.round(lapSeconds * 1000), // integers only
ordering: 'ascending',
});
if (bestScore !== undefined) bestLabel.textContent = `Best: ${bestScore} ms`;
show()
show(): Promise<void>;
Opens the Lens's own native leaderboard panel. Submit first so it has data; rejects
ERR_INTERNAL when nothing can host it or no board data loads within the bounded wait.
Returns
Promise<void>
Example
await snapchat.leaderboards.submitScore({ leaderboardId: 'main', score });
await snapchat.leaderboards.show();
BitmojiAPI
The current user's own Bitmoji (bitmoji capability, v1). No avatar id ever crosses the bridge.
participant is a reserved parameter: every v1 action rejects it with ERR_INVALID_PARAMS.
Always keep a default Bitmoji as a fallback: hasAvatar may be false and any media call may reject
ERR_INTERNAL, and a game should never show an empty character in either case. Put the fallback GLB in
your game's zip: a Lens cannot fetch it from the network at runtime.
Methods
getAvatarInfo()
getAvatarInfo(): Promise<{
hasAvatar: boolean;
}>;
Whether the current user has a Bitmoji. Check it before the media calls, which reject
ERR_INTERNAL for a user without one.
Returns
Promise<{
hasAvatar: boolean;
}>
Example
const { hasAvatar } = await snapchat.bitmoji.getAvatarInfo();
if (!hasAvatar) useDefaultCharacter();
get2DAvatar()
get2DAvatar(params?): Promise<MediaURL>;
A head-and-shoulders 2D render of the avatar: the default portrait, or one of the variants from
BitmojiAPI.getVariants. Rejects ERR_INVALID_PARAMS for a variant outside the current
set (variants can retire server-side — fall back to the portrait) and ERR_INTERNAL when the
user has no Bitmoji.
Parameters
| Parameter | Type |
|---|---|
params? | Get2DAvatarParams |
Returns
Promise<MediaURL>
Example
let image;
try {
image = await snapchat.bitmoji.get2DAvatar({
variant: savedVariant,
size: 'large',
});
} catch (e) {
if (e.message !== snapchat.errors.INVALID_PARAMS) throw e;
// The variant has retired: show the portrait instead.
image = await snapchat.bitmoji.get2DAvatar({ size: 'large' });
}
avatarImg.src = image.url; // render promptly: the URL expires after ~5 min
get3DAvatar()
get3DAvatar(): Promise<MediaURL>;
The rigged avatar GLB (standard skeleton, no clips — bundle your own). Rejects ERR_INTERNAL
when the user has no Bitmoji or the model fetch fails; the URL is never empty.
Returns
Promise<MediaURL>
Example
// Keep a default avatar in your game's zip for users without a Bitmoji and for failed fetches.
let url = './assets/avatar_default.glb';
try {
const { hasAvatar } = await snapchat.bitmoji.getAvatarInfo();
if (hasAvatar) url = (await snapchat.bitmoji.get3DAvatar()).url;
} catch {
// ERR_INTERNAL: keep the default.
}
const glb = await (await fetch(url)).arrayBuffer(); // hand this to your engine's GLB loader
getVariants()
getVariants(): Promise<{
variants: string[];
}>;
The server-curated set of 2D variants: head-and-shoulders renders of the avatar, the same set the
native selfie picker offers. Ids are unnamed: build a visual picker by rendering each via
get2DAvatar({ variant, size: 'small' }) in small batches (~6), so the user's own avatar in each
variant is its label. Or pick ids at authoring time and keep them as data, falling back to the
portrait when one retires.
Returns
Promise<{
variants: string[];
}>
Example
const { variants } = await snapchat.bitmoji.getVariants();
for (let i = 0; i < variants.length; i += 6) {
const batch = variants.slice(i, i + 6);
const images = await Promise.all(
batch.map((variant) =>
snapchat.bitmoji.get2DAvatar({ variant, size: 'small' })
)
);
images.forEach(({ url }, j) => addVariantButton(batch[j], url));
}
StorageAPI
Account-bound key/value persistence for this Lens (storage capability, v1). Values are
JSON (≤ 32 KiB each); keys are non-empty strings (≤ 256 bytes). Writes past the store quota
reject ERR_QUOTA_EXCEEDED and leave the store unchanged; ERR_STORAGE_UNAVAILABLE means no
durable backing exists on this device or session. Lens Studio previews and the desktop stub
persist in memory only.
Methods
get()
get(key): Promise<StorageGetResult>;
Reads one key. found tells a missing key apart from a stored null.
Parameters
| Parameter | Type |
|---|---|
key | string |
Returns
Promise<StorageGetResult>
Example
const result = await snapchat.storage.get('save');
const save = result.found ? result.value : { level: 1, coins: 0 };
set()
set(key, value): Promise<void>;
Writes one key, replacing any previous value.
Parameters
| Parameter | Type | Description |
|---|---|---|
key | string | - |
value | unknown | Any JSON-serializable value. |
Returns
Promise<void>
Example
await snapchat.storage.set('save', { level: 3, coins: 120 });
remove()
remove(key): Promise<void>;
Idempotent: removing a missing key resolves.
Parameters
| Parameter | Type |
|---|---|
key | string |
Returns
Promise<void>
Example
await snapchat.storage.remove('save');
clear()
clear(): Promise<void>;
Deletes this Lens's whole store for the current account.
Returns
Promise<void>
Example
resetButton.onclick = () => snapchat.storage.clear();
keys()
keys(): Promise<{
keys: string[];
}>;
Stored keys in byte-lexicographic order.
Returns
Promise<{
keys: string[];
}>
Example
const { keys } = await snapchat.storage.keys();
const slots = keys.filter((key) => key.startsWith('slot:'));
getInfo()
getInfo(): Promise<StorageInfo>;
Usage against the store's limits, and whether it persists across sessions.
Returns
Promise<StorageInfo>
Example
const { usedBytes, maxBytes, persistenceMode } =
await snapchat.storage.getInfo();
if (persistenceMode === 'memory')
console.warn('Progress will not survive a restart here');
SnapchatWebLensAPI
The window.snapchat singleton: one include for iOS, Android, and desktop development.
Every call returns a Promise. Failures reject with an Error whose message is one of the
stable codes in SnapchatWebLensAPI.errors; there is no native error text to parse. Calls
never throw synchronously: a failure the API cannot classify, such as params that cannot be
serialized, rejects with ERR_INTERNAL.
Methods
init()
init(): Promise<CapabilityMap>;
Fetches and caches the capabilities this host serves. Call once at startup, before SnapchatWebLensAPI.isSupported.
Resolves {} (nothing supported) instead of rejecting when discovery itself is unavailable: no
bridge at all, or a host too old to answer sdk/getCapabilities. Genuine failures
(ERR_INTERNAL, ERR_INVALID_PARAMS) still reject.
Returns
Promise<CapabilityMap>
Example
await snapchat.init();
leaderboardButton.hidden = !snapchat.isSupported('leaderboards');
isSupported()
isSupported(capability, minVersion?): boolean;
Whether the host serves capability at contract version minVersion (default 1) or newer.
Always false before SnapchatWebLensAPI.init resolves.
A capability's contract only grows: its version goes up when it gains actions, and a breaking
change ships under a new capability name, so a minVersion check keeps working on newer hosts.
Parameters
| Parameter | Type |
|---|---|
capability | Capability |
minVersion? | number |
Returns
boolean
Example
snapchat.isSupported('bitmoji'); // false: init() has not resolved yet
await snapchat.init();
snapchat.isSupported('bitmoji'); // true where the host serves bitmoji v1 or newer
Properties
| Property | Modifier | Type | Description |
|---|---|---|---|
version | readonly | string | API version (semver). |
errors | readonly | WebLensAPIErrors | - |
isStub | readonly | boolean | True when running against the desktop stub instead of a Snapchat host. Example // The stub's 3D avatar is an empty placeholder GLB, so show the bundled default instead. const showUserAvatar = snapchat.isSupported('bitmoji') && !snapchat.isStub; |
leaderboards | public | LeaderboardsAPI | - |
bitmoji | public | BitmojiAPI | - |
storage | public | StorageAPI | - |
Type Aliases
WebLensAPIErrorCode
type WebLensAPIErrorCode = WebLensAPIErrors[keyof WebLensAPIErrors];
Union of every ERR_* string in WebLensAPIErrors.
Capability
type Capability = 'leaderboards' | 'bitmoji' | 'storage' | (string & object);
Capability names, as SnapchatWebLensAPI.init reports them and SnapchatWebLensAPI.isSupported takes them.
CapabilityMap
type CapabilityMap = Record<string, number>;
Capability name → contract version, as resolved by SnapchatWebLensAPI.init.
StorageGetResult
type StorageGetResult =
| {
found: true;
value: unknown;
}
| {
found: false;
};