i99dash docs
Develop

Beta testing

Publish a build to a small group of Telegram-verified testers before the public catalog. TestFlight-style workflow for i99dash mini-apps.

The CLI ships a beta track for every mini-app. You publish a build to a limited group of testers, iterate based on their feedback, then promote the same bundle to production when you're happy. This is the equivalent of TestFlight for i99dash mini-apps.

When to use it

  • You're shipping a behaviour change that's risky on the head-unit (UI rewrite, new bridge feature, backend dependency that just landed).
  • You want a sample of real users to validate before everyone gets it.
  • You need to demo a build to a stakeholder without flipping the production catalog.

If your release is documentation-only or copy-tweaks, skip beta and publish straight to production.

Limits

LimitWhy
25 testers per appIncluding yourself. Backend returns beta.tester_cap_reached (HTTP 422).
90-day beta expiryA beta build expires 90 days after promotion. Promote again or move to production before then.
One beta bundle at a timeThe beta track is a single pointer per app. Promoting a new build replaces the previous one.

Two ways to put a build on the beta track

Path 1 — publish directly to beta

sdk-i99dash publish --track beta --release-notes "Rebased on latest map tiles"

Same flow as a regular publish, except the bundle lands on the beta track instead of production. Testers see this build automatically the next time they launch the mini-app.

--release-notes is shown in the consent sheet the host pops up when a tester first opens a new beta build. Keep it short — one sentence is ideal.

Path 2 — publish to production, promote later

sdk-i99dash publish                                  # lands on production
sdk-i99dash beta promote com.example.myapp 2.0.0 --release-notes "Nightly build"

Use this when:

  • You publish on a CI tag and decide the beta cohort by hand later.
  • You want to roll back the beta to a prior version that's already in the catalog.

Manage the tester roster

Invite a tester

sdk-i99dash beta invite com.example.myapp @alice
sdk-i99dash beta invite com.example.myapp alice     # @ prefix is optional

The CLI strips a leading @ so you don't have to think about it.

Invite multiple testers in one shot

# Space-separated
sdk-i99dash beta invite-batch com.example.myapp alice bob charlie

# Comma-separated (also works)
sdk-i99dash beta invite-batch com.example.myapp "alice,bob,charlie"

Use this for the initial roster on a fresh beta — one round-trip instead of N.

List the roster

sdk-i99dash beta testers com.example.myapp

Output:

USER ID                              TELEGRAM           STATUS    INVITED AT          ACCEPTED AT
------------------------------------------------------------------------------------------------
01J9VWCB9G…                          @alice             accepted  2026-04-20 14:02 UTC 2026-04-20 14:11 UTC
01J9VWCB9H…                          @bob               invited   2026-04-20 14:02 UTC —

STATUS values:

StatusMeaning
invitedWe've recorded the invite. The user hasn't opened i99dash since the invite, or the username never existed (you can't tell which from this row — see Security below).
acceptedThe user has consented to receive beta builds. They'll see the beta on next launch.
revokedYou removed them via beta revoke. Stays in the table for audit.

Remove a tester

sdk-i99dash beta revoke com.example.myapp <user_id>

user_id is the first column of the beta testers table — copy it verbatim. The tester loses access on next launch; their pinned shortcut still works but reverts to the production build.

Promote the beta to production

Two ways:

# Copy the current beta bundle into the production track
sdk-i99dash beta promote-production com.example.myapp

This is the fast path when the beta passed review. The current beta bundle becomes the new production version with no rebuild — same SHA-256, same CDN URL, same (id, version) pair.

# Or pull the beta without promoting (e.g. you found a critical bug)
sdk-i99dash beta demote com.example.myapp

This clears the beta pointer. Testers fall back to production on next launch.

End-to-end example

Here's the full lifecycle of a single beta cycle:

# Tag a release in CI; it publishes to production on tag push
git tag v2.0.0 && git push --tags

# Decide which version to beta — pick a recent one
sdk-i99dash beta promote com.example.myapp 2.0.0 \
  --release-notes "v2: redesigned home, new fuel widget"

# Add your testers
sdk-i99dash beta invite-batch com.example.myapp \
  alice bob charlie diana eve

# Watch acceptance over the next day or two
sdk-i99dash beta testers com.example.myapp

# After feedback + a fix
git tag v2.0.1 && git push --tags
sdk-i99dash beta promote com.example.myapp 2.0.1 \
  --release-notes "v2.0.1: fixes the home-screen tap target"

# Once everyone's happy, ship to production
sdk-i99dash beta promote-production com.example.myapp

Security: account enumeration mitigation

The beta invite and beta invite-batch endpoints always return HTTP 200, regardless of whether the supplied Telegram username exists. The CLI prints Invite recorded either way. This is deliberate: a public-facing dev tool that returned different responses for "real account" vs "no such user" would let anyone enumerate i99dash's user base by guessing usernames.

Real status only shows in the beta testers table, which requires your developer API key — that gate is what stops enumeration. If you need to confirm an invite landed:

  1. Wait for the user to open i99dash.
  2. Run beta testers <app_id> and look for their row.
  3. If their status is still invited after 24 h, ask them to check the i99dash app's "Mini-apps" tab — there should be a notification.

How a tester actually receives the beta

From the user's side:

  1. Opens i99dash on their car or phone.
  2. Sees a Beta available card on the mini-app the dev invited them to.
  3. Taps the card → consent sheet (with your --release-notes text).
  4. Approves → next launch loads the beta bundle.

The tester can flip back to production at any time from the same card. You don't need to do anything for the rollback path — it's part of the host's beta UX.

Errors

CodeWhenFix
beta.tester_cap_reachedYou hit 25 testers + 1 dev.Revoke someone first, or wait until a tester accepts and replaces a stale invite.
beta.no_active_bundlebeta promote-production ran but no beta bundle exists.Promote a version to beta first.
beta.expiredThe beta has been live for >90 days.Promote a fresh version to refresh the timer.
beta.unknown_appapp_id doesn't exist or you don't own it.Check app_id matches your manifest.json.
beta.tester_not_foundbeta revoke ran with a user_id that isn't on the roster.Run beta testers and copy the user_id verbatim.

On this page