Skip to content

App SDK overview

A Maypop app is static files running in the browser. The maypop SDK is how it reaches everything a backend would normally provide. Maypop runs those services; your app calls them through an authenticated session that the Maypop host sets up for whoever is looking at the app.

Capability Use it for
maypop.user, mode who is looking, and whether they can change things
maypop.kv shared, live JSON data — lists, votes, scores, settings
maypop.drive images, audio, video and documents
maypop.multiplayer presence, rooms and real-time messages
maypop.ai chat, images, video, audio and transcription
maypop.agent a conversational assistant with tools over your data
maypop.mcp external services linked to the app over MCP
maypop.members() everyone the app reaches, and who is online
maypop.share, link deep links and the share card
maypop.notify notifications to the app’s audience

There is no SQL database, server function, cron job or secret store. If your app needs one of those, keep that part on a server you host and call it from the browser.

From npm, with any bundler:

Terminal window
npm install @basilica-digital/maypop-sdk
import { maypop } from "@basilica-digital/maypop-sdk";

Or, in a plain HTML app, from Maypop:

<script src="https://api.app.maypop.ai/sdk/v1.js"></script>

Both give you the same window.maypop object — use one, not both. The TypeScript declarations ship in the package and at https://api.app.maypop.ai/sdk/v1.d.ts. The v1 contract only grows; a breaking change would get a new path.

await maypop.ready();

Nothing works until the host has handed the app its session. ready() is safe to call more than once. In Studio’s preview the session is real: data you write while building is real data.

interface MaypopUser {
id: string;
username: string;
role: string;
avatarUrl: string | null;
connected: boolean;
isAnonymous: boolean;
scopes: string;
}
readonly user: MaypopUser | null;
readonly mode: "read-write" | "read-only";
readonly permissions: string[];
readonly signInRequired: boolean;
signIn(): void;
  • user.id is stable for one person in one app, and different in every other app. It is not their Maypop account id. Use it for authorship and per-person keys.
  • role is admin, editor, writer or reader. The app’s creator is always admin. Treat it as a hint for what to show; Maypop enforces the real permissions on every request.
  • Gate editing controls on mode. People opening a link with view access, and anonymous visitors, are read-only.
  • Maypop owns sign-in, so don’t build a login page. When signInRequired is true, signing in would let this person write — show something like Sign in to save and call maypop.signIn(). The host handles it and reloads the app.
await maypop.ready();
if (maypop.mode === "read-only" && maypop.signInRequired) {
button.textContent = "Sign in to save";
button.onclick = () => maypop.signIn();
}
readonly theme: "light" | "dark";
setAmbientColor(rgb: [number, number, number] | null): void;
on(event: "modechange" | "revoked" | "themechange", callback: () => void): () => void;

The SDK mirrors the host theme onto <html data-theme> and color-scheme, so CSS can follow it. Add data-maypop-theme="manual" to <html> to opt out. setAmbientColor tints the glow Maypop draws behind your app.

Listen for modechange when permissions can change while the app is open — for example, someone signs in or is given edit access. revoked means the session ended.

Every SDK error is an Error with a code:

Code Meaning
maypop/read-only this viewer can’t write
maypop/sign-in-required signing in would allow it
maypop/forbidden not allowed for this viewer
maypop/not-found the file or item doesn’t exist
maypop/conflict a Drive file with that name already exists
maypop/file-too-large over the upload limit
maypop/ai-limit the viewer is out of AI credits
maypop/ai-blocked a generation was refused by moderation
maypop/not-connected the multiplayer peer is not connected
maypop/unsupported not available here, e.g. in the local dev host
maypop/revoked the session ended

@basilica-digital/maypop-sdk/react has hooks for the common cases: useMaypopSession, useMaypopViewer, useMaypopApp, useMaypopMode, useMaypopTheme, and useMaypopKV(key, fallback):

import { useMaypopKV, useMaypopMode } from "@basilica-digital/maypop-sdk/react";
function Counter() {
const mode = useMaypopMode();
const count = useMaypopKV("counter", 0);
return (
<button
disabled={mode === "read-only" || count.isMutating}
onClick={() => count.setValue(count.value + 1)}
>
{count.value}
</button>
);
}

maypop.launchPath is the path a person arrived on — from a shared link, a notification, or a share card — and is set before ready() resolves. Apps using a hash router get it applied automatically. See Deep links and sharing.