Build
SDK docs
Updated October 24, 2026
Your app saves student progress by calling kitequad, a tiny API KiteQuad adds to every published app. There's nothing to install — it's already there when your app runs.
Start with the KiteQuad-ready prompt
The quickest way to get an app that works here: paste this at the top of your request to Claude, Gemini, ChatGPT or AI Studio, then describe the app you want. It tells the AI how to save progress and which few things to avoid so your app passes KiteQuad's checks the first time.
Build this as a single-page web app that will run on KiteQuad, a safe host for classroom apps. Follow these rules so it works and passes KiteQuad's checks.
SAVING PROGRESS
- Save and load with KiteQuad's built-in "kitequad" API instead of your own server or a database.
Call await kitequad.ready() once at the start, then:
await kitequad.store.set("level", 4) // value can be any JSON, up to 64 KB
const level = await kitequad.store.get("level") // null if nothing is saved yet
Pass { scope: "class" } as the last argument to share data across the whole class; the default is per-student.
- For a scoreboard use kitequad.board.post(score) and kitequad.board.top().
- Do NOT ask students for their name, email, or anything else that identifies them.
NO OUTSIDE CONNECTIONS
- Do NOT call fetch, XMLHttpRequest, WebSocket or EventSource to any other website — network access is blocked.
- Do NOT load fonts, images, scripts or styles from other websites. Use system fonts, or include the files with the app.
- Do NOT navigate to another page or open pop-up windows.
HOW TO WRITE SCRIPTS
- Put your JavaScript inside <script> tags in the page, or in .js files. Both are fine.
- If your code creates a <script> element, set its text BEFORE you add it to the page; don't add an empty one and fill it in later.
- Do NOT use import() from inside a <script> that your code adds while the app is running.
- Do NOT put a <script> inside the srcdoc of a sandboxed <iframe>.
- Use at most one document.write() per <script>.
TEST IT FIRST
- Add <script src="https://kitequad.com/sdk/v1.js"></script> to the top of the page to try "kitequad" on your own computer before publishing. KiteQuad replaces this line with the real version when you publish.
Saving progress
Wait for kitequad.ready(), then read and write with kitequad.store. A value is anything JSON can hold.
await kitequad.ready();
// save (per student by default)
await kitequad.store.set("level", 4);
// load — null if nothing is saved yet
const level = await kitequad.store.get("level");
// share across the class
await kitequad.store.set("teamScore", 120, { scope: "class" });
The kitequad API
kitequad.ready()
ready(): Promise<void>
Resolves once KiteQuad has signed the student in and the app can start. Call it before anything else.
kitequad.me()
me(): Promise<KiteQuadMe>
Who's using the app. In anonymous mode you get a nickname, an avatar, a per-app id and classId, and role ("student", or "preview" when you're trying it from the dashboard). There's no real name unless a school has turned on authorized mode and allowed it for the app.
kitequad.store.set() / get() / remove() / list()
set(key, value, opts?): Promise<void> get(key, opts?): Promise<value | null> remove(key, opts?): Promise<void> list(opts?): Promise<Array<{ key, value, updatedAt }>>
Save and load a student's progress. opts is { scope: "me" | "class" } — "me" (the default) is private to the student, "class" is shared across the class. list also takes { prefix }.
Calls to set the same key within half a second are merged into one write, so a game loop that saves every frame costs one save.
kitequad.board.post() / top()
post(score, opts?): Promise<void> top(opts?): Promise<Array<{ nickname, avatar, score, label, at, me }>>
A class leaderboard. post records a score for the student; top returns the best (up to 50), newest-tie first, with me true on the student's own row. opts is { label } to keep separate boards (e.g. per level), and top takes { limit }.
kitequad.submit() Authorized mode
submit(payload, opts?): Promise<{ id }>
Hands a piece of student work to the teacher. In anonymous mode it's turned off and rejects with not_authorized; it works once a school turns on authorized mode.
kitequad.ai.chat() Coming later
ai.chat({ messages, system?, maxTokens? }): Promise<{ text }>
A safe path to an AI model, routed through KiteQuad so no key or student data leaves the platform. Not in this release: it rejects with ai_unavailable. It arrives in a later release, only where a school turns AI on, with a per-student opt-out.
kitequad.on()
on("signout" | "mode", handler): () => void
Runs handler when the student signs out, or when the mode changes. Returns a function that removes the listener.
kitequad.version / kitequad.inKiteQuad
readonly version: string readonly inKiteQuad: boolean
version is the SDK version; inKiteQuad is true on KiteQuad and false under the local mock, so an app can tell where it's running.
Errors
Every method rejects with a kitequad.KiteQuadError whose code is one of: not_signed_in, not_authorized, ai_unavailable, quota_exceeded, rate_limited, invalid_input, not_found, timeout, internal. Catch it to show your own message.
try {
await kitequad.store.set("level", 4);
} catch (err) {
if (err instanceof kitequad.KiteQuadError && err.code === "quota_exceeded") {
// too much saved — clear something first
}
}
Limits
| What | Limit |
|---|---|
| Store key | 1–128 characters |
| Store value | Up to 64 KB of JSON |
| Saved per student, per app | Up to 1 MB |
| Saved per class, per app (shared) | Up to 5 MB |
| SDK calls | 60 a minute (short bursts of 20) |
board.post | 10 a minute |
board.top | Up to 50 rows |
submit (authorized mode) | Up to 256 KB; 20 an hour per student |
Test on your own computer
Before publishing, add this one line to the top of your page and open the file in a browser. kitequad then works with a fake student called “Test Student” and saves to that browser's storage, through the same code as the real SDK — and makes no network requests of any kind.
<script src="https://kitequad.com/sdk/v1.js"></script>
When you publish, KiteQuad removes that line and wires in the real SDK, so you can leave it in while you build.
A note on scripts
When you publish, KiteQuad moves the code written inside your pages into files so each page can run under a stricter safety rule. Most apps work exactly as before. A few patterns behave a little differently — a script that builds another script and uses it at once, or a short timer that expects a later script to already be on the page — and the publish check tells you when it spots one. The prompt above steers your AI clear of them. There's more on the help page.