# Embeducate > Embeducate turns an AI-generated educational activity into a tracked class assignment: publish a > self-contained web app, get a safe embeddable link, and see how every student did — no setup, no code. Embeducate hosts static (HTML/CSS/JS) educational apps in a sandbox, gives each a shareable and embeddable URL, captures learner analytics through a small SDK, and turns them into a teacher's class report. It works with an activity made in **any** AI tool (Gemini, Claude, ChatGPT, Bolt, …) or one you describe — it is not a fixed-template generator, and what you publish stays teacher-owned and portable. An AI tool (or agent) builds the activity with the SDK included; publishing is a simple drag of the file onto the site, and the class report is viewable **without signing in**. ## Key facts - **Free to start, no account needed.** Drop an app on the site to get a live link, an embed code, and a **private report link only its owner can open** (no account needed — the publishing browser is recognized; sign in to view it anywhere). Unclaimed apps stay live for about 1 hour; claiming it (sign-in) keeps it permanently and lets you assign it to a class. - Free for teachers; school- and district-wide features (roster sync, LMS gradebook, admin controls) are paid. - Content is a **self-contained static web app** (HTML/CSS/JS) — no backend, no external data calls. - The **SDK** (loaded from `/sdk/v1.js`; global `edu`) reports learning analytics (attempts, events, skill mastery, completion/score); the platform projects them into a class report and (later) LMS grades. - Learners are **pseudonymous** — a class code and a first name, never PII. - Apps run **sandboxed** on an isolated per-activity origin with no data egress — they can't reach the teacher's session or any student data. ## For AI agents If you are an AI building an app for a user's class, **you are the builder — generate the code directly; there is nothing to paste.** Build a single self-contained static web app and bake in the SDK: 1. Include the SDK once in ``: `` 2. `edu.signal.event("hint_used")` (any name) for notable interactions; `edu.signal.mastery("skill-id", 0.8)` when a skill is demonstrated. 3. On finish: `edu.signal.complete({ score, maxScore, items: [{ id, skill, label, value, display, correct, score, attempts }] })` — include `score`/`items` only when the activity is actually graded (e.g. a quiz); omit them for open-ended activities. Give each answer a friendly `display` string (never raw JSON); `display: null` flags an answer that can't be shown as text — pair it with `elementId: "someId"`, the id of the visible element holding that answer, and the platform captures a picture of it for the report. 4. Declare in `` (as ``): `task:title`; `submit` (self|host — who submits; defaults to host); `submit-policy` (at-will|conditional, host mode); `sdk` ("0.1.0"); `build` (Date.now()); `viewmodes` (read-only summary — recommended: enables submission review); and optionally `lang` (ISO 639-1), `dir` (ltr|rtl|both). 6. Make it **snapshot-able**: `edu.handlers.register("getState", fn)` returns `{ domain, interaction, ui }` — `domain` is what the learner did and where they are (answers, attempts, current step, seeds), `interaction` is entered-but-not-committed, `ui` is presentation (open dialogs, panels). `edu.handlers.register("setState", fn)` receives that same object and rebuilds the whole view from it, idempotently — tear down any later-state end-screens/overlays. Optionally `register("reset", fn)`. A captured snapshot restored after a reload must look identical — store inputs and seeds. Call `edu.state.sync()` when your state changes. The snapshot is never the submission: grading goes in `complete({score, maxScore, items})`, or `register("getResult", fn)` in `host` mode. Then hand the file to the user to publish: they drop it on embeducate.com and get a live URL, an embed code, and a report link. (There is no programmatic publish API today — publishing is a human drag-and-drop; an upload API / MCP server is planned.) Notes: loading CDN libraries (React, Tailwind, …) is fine, but no `fetch`/XHR to third parties (the SDK is the only channel out). The SDK queues calls before it loads and no-ops outside Embeducate, so it never breaks a preview. Instrument what the activity does — build the scoring the activity calls for, but don't bolt a quiz/score/submit button onto an activity that isn't one. Keep the UI **neutral** — no Embeducate branding or platform mentions in what the learner sees. ## Links - [Home](https://embeducate.com/): what Embeducate is, for teachers. - [Publishing spec](https://embeducate.com/ai-docs.md): full instructions for making an AI-built app publish-ready.