recommend — flow discovery for new apps
No Playwright tests yet? Point Specreel at your running app and it will crawl it, suggest demo-worthy flows, and scaffold a runnable Playwright script — so you go from "an app" to "a gallery" without writing the first flow by hand.
specreel recommend http://localhost:3000 --max 10
crawling http://localhost:3000 (max 10 pages, server HTML) ...
found 6 pages → 5 suggested flows:
1. [form] Fill the Sign up form (http://localhost:3000/signup · 2 field(s))
type "demo@example.com" into "Email"; type a password into "Password"; stop there: the form is NOT submitted and nothing is sent
2. [form] Fill the Trip calculator form (http://localhost:3000/calculator · 2 field(s))
type the date 60 days ago into "Entry date"; type the date 40 days ago into "Exit date"; stop there: …
3. [search] Search on Docs (http://localhost:3000/docs · 1 field(s))
type "Webhooks" into "Search docs"; press Enter and show the search results
4. [nav] Open Blog (http://localhost:3000/blog)
click the first item listed under /blog/ (at crawl time: "Launch week recap") and show its page; scroll down that page
5. [nav] Open Pricing (http://localhost:3000/pricing)
scroll down the page
scaffolded -> specreel_flows.py
edit the TODOs, then: python specreel_flows.py && specreel test-results -o site --bundle
What it does
- Crawls the app, same-origin, breadth-first (stdlib
urllib+html.parser). - Maps each page: title, headings, forms (+ fields and their labels), inputs outside any form, search boxes, links (and which ones are page chrome).
- Ranks candidate flows: forms > search > nav.
- Scaffolds a Playwright script with tracing on, real selectors, and the
values each flow types — each flow writes
test-results/<slug>/trace.zip.
What each flow shows
Every suggestion should show the product doing something, and stay read-only:
- Values come from the site. A search types something the site itself lists
(the first item of its biggest list of products / categories / articles), so the
demo lands on results, not "No matching results". A field types the example its
placeholder or label gives ("e.g. eggs, spinach, rice" → eggs, spinach, rice),
or a value of the kind its label asks for. Never test or Sample text. Dates
are relative to the day the flow runs (a calculator demo doesn't age), and a
field that already holds a value (a default) keeps it.
- A page's tool is a flow. Inputs outside any <form> — a calculator, an
ingredients box, a chat prompt — are filled in like a form (never on a
settings/profile page, where such inputs tend to autosave).
- A page visit opens one real item. When the page lists same-site items, the
flow clicks the first one (a[href^="/blog/"]:visible — whichever is first on the
day, so a new post doesn't break tomorrow's run), checks it landed, and scrolls
it. Never page chrome, a new tab, or a link that acts (cart, sign-out, delete…).
- Nothing is submitted. Forms are filled and left — the submit click is a TODO
only you can decide. A site-wide header search or footer form becomes one flow,
not a reason to skip every page's own visit.
- A page that is a bot check (Cloudflare's "Just a moment...") is never a flow;
if that is all the crawl sees, recommend says so instead of demoing it.
--json reports each flow's does (these steps) and its fields' values.
The full loop
specreel recommend http://localhost:3000 # 1. suggest + scaffold
# (edit the TODOs in specreel_flows.py — add assertions / clicks you care about)
python specreel_flows.py # 2. run -> test-results/*/trace.zip
specreel test-results -o site --bundle # 3. render the gallery
Options
--max N— pages to crawl (default 12).--lang py|js— scaffold language (auto-detected:package.json→js, elsepy).-o FILE— output path.--ai[--api-key KEY]— curate & rename the suggestions with AI (BYO key). It reorders and retitles the discovered flows and may pick better values for their fields — it never invents new ones. Titles describe what the recording shows ("Tour the Schengen calculator", not "Calculate your Schengen days"); a title that still promises more than its flow does is not taken.
Server HTML vs. rendered DOM
By default recommend reads the server HTML (fast, zero-dep). For
client-rendered SPAs (React/Vue/etc., where the initial HTML is near-empty),
add --browser to render each page with Playwright first and read the live DOM:
specreel recommend http://localhost:5173 --browser
Needs Playwright (pip install playwright && playwright install chromium) — the
same thing you need to run the scaffold. If a static crawl finds nothing, the CLI
tells you to retry with --browser. Use --wait <ms> to give a slow SPA more time.
Logged-in crawls
Public pages crawl out of the box. For pages behind a login, pass your session as a
cookie (or a Playwright storage state, --storage-state auth.json) — it works in both
static and --browser mode and reaches the app's own host only, never a site the app
redirects to (an OAuth provider gets nothing; a storage state's Google / GitHub cookies
are dropped). Any other header is sent with every request:
specreel recommend http://localhost:3000 --cookie "session=abc; csrf=xyz"
specreel recommend http://localhost:3000 --header "Authorization: Bearer <token>"
Grab the cookie from your browser's devtools (Application → Cookies) after logging in.
The scaffold is a starting point, not a finished suite — it leaves TODOs for the
assertions and submit clicks only you can decide — but it turns a blank page into
editable, runnable flows in one command.