OpenTree DashboardSign in

$ npx storybook build && zip -qr sb.zip .

A private Storybook, in about ten lines of CI

A built Storybook is a folder of static files, which means hosting it is a solved problem right up until you need it to be private. The usual answers either publish it to the world or want you to adopt a whole review platform.

The pipeline

  1. Build: npx storybook build produces a static directory.
  2. Zip that directory — the archive is the upload unit for a multi-file site.
  3. Publish it, or replace the existing one so the URL your team bookmarked keeps working.
  4. Gate it to your work-email domain once, and every subsequent publish inherits the setting.

CI, in ten lines

- run: npx storybook build
- run: cd storybook-static && zip -qr ../storybook.zip .
- run: |
    curl -sS -X PUT "https://read.botook.ai/sites/$SITE_ID" \
      -H "Authorization: Bearer $PUBLISH_KEY" \
      -F file=@storybook.zip

The first run uses POST /sites and records the returned id; every run after that is the PUT above, so the address never moves.

Gating it to the team

curl -X PATCH https://read.botook.ai/sites/SITE_ID \
  -H "Authorization: Bearer otr_live_YOUR_KEY" \
  -H 'content-type: application/json' \
  -d '{"allowed_email_domain":"yourcompany.com"}'

Settings-only changes go through PATCH, which never touches the stored bytes — so a gate applied today survives tomorrow's build.

Why not a public static host

A Storybook is a fairly complete description of your unreleased interface: component names, states, empty-state copy, feature flags in the controls. Public-by-default is the wrong posture for that, and per-link gating is what most static hosts do not have — they express privacy at the plan level instead, which means paying for an organisation tier to hide one build.

What you end up with

One URL, on your own domain if you add one, that always shows the latest build; access limited to people with a company email; no per-seat cost because there are no seats; and the exact bytes retrievable with GET /sites/:idOrSlug/content if you ever leave.

Does the zip need a particular structure?

Only that index.html is at the archive root — which is what storybook build produces if you zip from inside the output directory.

Will interactions and controls still work?

Yes; it is a built front-end app. What it cannot do is load scripts from a third-party origin, because the viewer CSP blocks those.

Can several branches each have a URL?

Publish one site per branch and let the short-lived ones expire, or mint separate share tokens against one site so a reviewer's link can be revoked on its own.

How large can the build be?

Bounded by the size limit configured in this deployment rather than by a plan. Storybook builds are asset-heavy, so check yours before wiring the job.

Keep reading