Quickstart
From zero to a running mini-app in five minutes. Copy-paste the commands; nothing else to configure.
This is the fast path. You'll scaffold a mini-app, run it locally with a simulated host, and publish it to the catalog. ~5 minutes if your machine already has Node 20+.
If anything fails: jump to Troubleshooting. If you want the longer reading first: What is a mini-app?.
Using React?
Skim this page for the CLI flow, then switch to the
Next.js guide — it shows the
i99dash/react setup (<MiniAppProvider> + hooks) you'll actually
ship with. Same init / dev / publish commands.
Prerequisites
| Tool | Version | Check |
|---|---|---|
| Node | ≥ 20 | node --version |
| pnpm | ≥ 9 | pnpm --version |
| Git | any | git --version |
If your machine is fresh, see Installation for a full prereq walkthrough.
1 — Scaffold
pnpm dlx i99dash init my-app
cd my-app
pnpm installinit prompts you to pick a catalog category — it lists the 10
canonical slugs (navigation, media, vehicle, productivity,
communication, entertainment, services, lifestyle, developer, other);
press 1–10 or type a slug. Skip the prompt with --yes (defaults
to other) or pre-answer with --category media.
You get:
my-app/
├── package.json
├── manifest.json ← the row the catalog stores
├── sdk.config.json ← dev-server config
├── src/
│ ├── index.html ← your app
│ └── assets/
│ └── icon.svg ← placeholder; swap with your real artwork
└── mocks/
└── fuel-stations.GET.json2 — Run locally
pnpm devThe dev-server boots at http://127.0.0.1:5173. Open it — you'll see a
hello-world page. The control panel at http://127.0.0.1:5173/_sdk/ui lets
you toggle driving state, device ID, locale, and theme live.
Your first real edit
Open src/main.ts and replace its body with:
import { MiniAppClient } from 'i99dash';
const root = document.querySelector('#root')!;
const ctx = await MiniAppClient.fromWindow().getContext();
root.innerHTML = `
<h1>Hello from your first mini-app</h1>
<p>App: <code>${ctx.appId}</code></p>
<p>Locale: <code>${ctx.locale}</code> · Dark: <code>${ctx.isDark}</code></p>
`;Save. The dev-server hot-reloads. Open /_sdk/ui and flip the locale —
the page re-renders the new value when you reload. That's the bridge
working: getContext() reads from the dev-server's shim, the same way
it reads from the real host in production.
3 — Validate the manifest
manifest.json is the catalog row for your app. The scaffold creates a
minimal one:
{
"id": "my-app",
"name": { "en": "My App", "ar": "تطبيقي" },
"icon": "./assets/icon.svg",
"url": "https://your-cdn.example.com/my-app/",
"version": "0.1.0",
"category": "other"
}icon is a bundle-relative path (starts with ./) — the file
ships in your tarball and the publish flow rewrites the path to a
versioned CDN URL automatically. No separate icon upload, no ops
ticket. See App icons recipe for the full
specs (formats, dimensions, where the file goes per framework).
category must be one of 10 canonical slugs — the head-unit chip
rail uses these for navigation. See Categories + tags.
Three rules the backend won't let you bend after publish:
idis forever — it's the deep-link suffix every pinned shortcut carries.versionmust increment on every publish.urlmust be on the host's allow-list (miniapps.i99dash.appin v1) — coordinate with ops if you need a custom origin.
Full details: MiniAppManifest.
pnpm validateCI-friendly: exit 0 on valid, exit 3 on schema failure. Catches
missing locales, http:// URLs, and other paper cuts before they hit
the backend.
4 — Log in
pnpm dlx i99dash logini99dash login signs the server's one-time challenge with your local SSH
ed25519 private key and stores a short-lived access token in your OS keychain.
Full flow (incl. CI / headless): Authentication.
5 — Publish
pnpm publish # validate → build → tarball → upload → submit
# or
pnpm publish --dry-run # all of the above without uploadingThe CLI prints a status URL you can share to track review / rollout. Full reference: Publishing.
That's it
Your app is live in the i99dash catalog. Users who install it from the Store tab get your bundle on next launch.
What just happened?
You connected your code to the host bridge, made a backend-style call
through it (well, just getContext() — but every call uses the same
mechanism), and shipped a bundle to a CDN catalog. The next page goes
deep on the mental model — read it once and the rest of the SDK clicks.
Next
The bridge
What `MiniAppClient` actually wraps, and why your code never touches it directly.
Calling an external API
Declare an origin in `manifest.network`, then `fetch()` it. Mental model + working example.
Fetch and render a list
The simplest real recipe — declare an origin, fetch JSON, render a list, handle errors. ~10 minutes.
Best practices
The non-obvious rules that prevent production incidents. Read before shipping.