Most web apps have a handful of journeys that actually pay the bills: a user signs up, verifies their email, pays, and gets access to the premium thing. If one of those breaks, you hear about it from customers.

Yet when I look for where those journeys are written down, I usually find two things:

  • E2E test dumps (Cypress, Playwright, recorded scripts) — they exercise the journey, but they're long, selector-heavy, and hard for anyone outside the test author to read or review.
  • API specs (OpenAPI) — precise about each endpoint, but silent about the order things happen in and what "success" means for the business.

Neither one answers the simple question: "What is our signup-to-paid flow, step by step, and does it still work?"

That's the gap Flowbook tries to fill.

What Flowbook is

Flowbook is a small open-source CLI that runs versioned YAML playbooks of business journeys. A playbook is a short, reviewable file in your repo that describes a flow as a sequence of steps:

  • http — make a request, check the status, capture values from the response
  • assert — check status / JSON / captured variables
  • browser — drive Chromium via Playwright (goto, fill, click, waitFor, capture)

The idea is that the playbook is the shared artifact: product, backend and QA can all read it in a PR, and CI can run it.

The MVP focuses on one journey that almost every SaaS has: signup → email verify → checkout (Stripe-style test payment) → assert premium access, either via the API or through the UI.

Install

The npm package is flowbook-cli; the binary it installs is flowbook. Node 18+.

# one-shot, no global install npx flowbook-cli validate path/to/playbook.yaml npx flowbook-cli run path/to/playbook.yaml # or install it — the command is `flowbook` npm install -g flowbook-cli flowbook run path/to/playbook.yaml 

If you use browser steps, install Chromium once (it's not downloaded on install, to keep the package light):

npx playwright install chromium 

A playbook, end to end (HTTP)

Here's the HTTP version of the MVP journey, trimmed slightly from the repo:

name: auth-signup-checkout description: Signup → email verify → mock Stripe checkout → assert premium access baseUrl: ${BASE_URL:-http://127.0.0.1:3847} vars: email: demo+${TIMESTAMP}@example.com password: secret123 steps: - id: signup type: http method: POST path: /signup body: email: ${email} password: ${password} expect: status: 201 capture: verifyToken: $.verifyToken sessionToken: $.sessionToken - id: verify type: http method: POST path: /verify body: token: ${verifyToken} expect: status: 200 - id: checkout type: http method: POST path: /checkout headers: Authorization: Bearer ${sessionToken} expect: status: 200 - id: assert-premium type: assert http: method: GET path: /me headers: Authorization: Bearer ${sessionToken} expect: status: 200 json: plan: premium 

A few things worth noting:

  • ${var} pulls from vars, earlier captures, or environment variables; ${VAR:-default} gives a fallback.
  • ${TIMESTAMP} and ${UUID} are built in, so every run gets a fresh user.
  • capture uses simple JSONPath ($.field, $.a.b[0]) to carry tokens forward.

You can point the same file at another environment without editing it:

BASE_URL=https://staging.example.com npx flowbook-cli run playbooks/auth-signup-checkout.yaml # or npx flowbook-cli run playbooks/auth-signup-checkout.yaml --base-url https://staging.example.com 

The same journey through the UI

Some flows can't be trusted from the API alone — the button might be broken even if the endpoint works. A browser step runs the journey in headless Chromium:

steps: - id: ui-journey type: browser actions: - goto: / - fill: { selector: '#email', value: ${email} } - fill: { selector: '#password', value: ${password} } - click: '#signup-btn' - waitFor: '#verify-token' - capture: verifyToken: { selector: '#verify-token', attr: data-verify-token } - goto: /verify - fill: { selector: '#token', value: ${verifyToken} } - click: '#verify-btn' - waitFor: { url: '**/checkout' } - click: '#checkout-btn' - waitFor: { url: '**/account' } - capture: plan: { selector: '#account-plan', attr: data-plan } - id: assert-premium-plan type: assert expect: vars: plan: premium 

Set FLOWBOOK_HEADED=1 (or headed: true) to watch it run.

Try it locally in two minutes

The repo ships a tiny Express demo app (in-memory, no database, no real Stripe keys — checkout is mocked) so you can see a full run:

git clone https://github.com/WhoIsLoH/flowbook && cd flowbook npm install && npx playwright install chromium npm install --prefix examples/demo-app npm run demo # starts the demo app on :3847 # in another terminal npm run flowbook:http npm run flowbook:browser 

Both playbooks are validated and run in GitHub Actions on every push, and CI is green.

If you'd rather not install anything yet, there's an interactive demo in the browser: https://whoisloh.github.io/flowbook/demo.html

Where it fits (and where it doesn't)

Flowbook is not a replacement for your unit tests or your full E2E suite. Think of it as:

  • a living spec for the 3–10 journeys that matter most to the business,
  • a smoke check you can run against local, staging, or a preview deploy,
  • a place to encode payment test flows (e.g. a Stripe test-mode checkout) as steps someone can actually read in review.

It's an early 0.1.0. Right now that means sequential steps, http / assert / browser step types, and one reference journey. I'd love feedback on what the next step types or journeys should be — real Stripe test-mode examples, magic-link email verification, team invites, plan downgrades…

Links

Issues and PRs welcome. If you have a journey that keeps breaking in your app, open an issue describing it — that's exactly the kind of playbook I want to support.

🇫🇷 Petite note en français : Flowbook décrit vos parcours métier clés (inscription → vérification email → paiement → accès premium) en playbooks YAML versionnés, exécutables en HTTP ou dans un vrai navigateur (Playwright). Essayez npx flowbook-cli — retours bienvenus sur GitHub.