Pre-launch checklists for web developers, freelancers and agencies.
LaunchPreflight is the checklist you run before a website goes live. Every project starts with 42 curated checks across SEO, security, performance, DNS & SSL, analytics and backups — each one with a short explanation of why it matters and what to actually do about it. Track status per check, leave notes, add checks of your own, and watch a weighted readiness score tell you whether you are genuinely ready to ship or just close to it.
Everything runs in the browser. No account, no backend, no data leaving the machine.
The demo is the real application with the bundled example project. Live verification is the one
thing it cannot do there: that needs the companion process on your own machine, and the deployed
origin is deliberately not on its allowlist — otherwise a public web page could drive a local
service. Clone the repository and run npm run dev to see that part.
- Multiple projects — create, rename, reconfigure and delete website projects, each with its own URL, environment (Production / Staging / Development) and optional launch date.
- A real checklist, not a stub — 42 predefined checks written as guidance, not labels. Each carries a description, a "why this matters" explanation and two to four concrete steps.
- Weighted readiness score — Critical checks count 4×, Important 3×, Recommended 2×, Optional 1×. A check in progress earns half its weight, one needing attention a quarter. The result is a single honest percentage rather than a count of ticked boxes.
- Launch gate — any unresolved Critical check means Not ready to launch, however high the percentage is.
- Custom checks — add your own with a title, description, category and priority. They behave exactly like predefined ones, and unlike them they can be deleted.
- Filter and search — filter by status or category, search titles and descriptions, and clear it all in one click.
- Detail panel — a docked panel on wide screens, a drawer on smaller ones, with guidance, status actions and an autosaving notes field.
- Markdown export — a launch report grouped by category, with critical issues pulled to the top and your notes included, ready to hand to a client.
- Templates — four built-in checklists (standard, WordPress, headless/Jamstack, static), plus your own: save any project's checklist as a template, and share it as a file.
- Reports — every project side by side, a client-facing summary per project, readiness over time as a trend, and everything still outstanding grouped by priority.
- Settings — pick the default checklist and environment for new projects, choose a date format, and export or import all your data as a single JSON file.
- Live verification — a "Live verification" KPI sits beside the readiness score and opens the
full report; an Auto column in the checklist shows the automatic verdict per check. An
optional companion process on your own machine runs 30 real probes covering 30 of the 42
checks: HTTP status and redirect chains, security headers, the TLS certificate, DNS records and
TTL, SPF/DMARC, leftover
.envand.gitfiles, framework debug output, version disclosure, robots.txt, the sitemap, title, meta description, canonical, OpenGraph, favicon, 404 handling, compression, cache policy, mixed content, image weight and formats, lazy loading, third-party scripts, the analytics tag, a consent tool, search-engine verification and form spam protection. - Post-launch monitoring — every run is kept, and the Reports page shows what regressed or improved since the run before, so a certificate quietly expiring or a header disappearing after a deploy shows up.
- Dark by default, light on request — both themes are first-class, and the choice survives a reload without a flash of the wrong palette.
- Local persistence — everything lives in
localStorage, validated on read so a corrupt or hand-edited store recovers instead of white-screening.
| Concern | Choice |
|---|---|
| UI | React 19, TypeScript (strict) |
| Build | Vite 8 |
| Styling | Tailwind CSS v4 (CSS-first @theme tokens) |
| Components | shadcn/ui-style primitives on Radix UI, vendored into src/components/ui |
| Icons | Lucide |
| State | Zustand with the persist middleware |
| Validation | Zod 4 — schemas are the source of truth for the domain types |
| Tests | Vitest |
| Lint / format | oxlint, Prettier |
No backend, database, authentication or payment dependency — by design.
A browser cannot verify someone else's website. It is not allowed to read another origin's
response headers, status codes or HTML, and a no-cors request returns an opaque result with no
headers and an empty body — so the only thing the page itself could ever establish is "the host
answered". For a launch tool, a green tick that means nothing is worse than no tick at all.
So the real checks run in a small companion process on your machine. npm run dev starts it
alongside the app, and the app finds it by itself — there is nothing to configure and no token to
paste. Press Verify in the project header and it works.
npm run dev # app + verifier together
npm run verify https://your-site.com # one-off, prints a table
npm run verify:serve # just the daemonThe twelve checks with no probe — backups, restore drills, admin account audits, whether tracking actually records, the redirect map from the old site — are not observable from the public internet. They stay manual rather than getting a probe that guesses.
The daemon binds to the first free port among 4319-4321 and the app probes the same three, so a busy port is not a dead end. If it is not running, the app says so and keeps working without it; start it later and the page picks it up within a few seconds, no reload.
Results never overwrite your own status. The manual status remains the truth for the readiness score; the automatic verdict appears next to it, and the app warns you when the two disagree.
Monitoring is the same runs kept over time: the Reports page compares the newest run with the one
before and lists what regressed or improved. Schedule npm run verify from cron or launchd if you
want it to keep checking after launch without opening the app.
Safety. Four independent checks, because a local service that fetches arbitrary URLs is otherwise a convenient tool for probing your own network:
- It binds to
127.0.0.1, so nothing on the network can reach it. - It answers only requests addressed to a loopback hostname. Without this, DNS rebinding would
defeat everything else: an attacker points their own domain at
127.0.0.1, their page becomes same-origin with the daemon, and no CORS check ever runs. - It answers only browser origins on its allowlist, so another site's JavaScript gets a 403 before any work happens — on the preflight and on the request itself.
- It refuses to probe loopback, link-local and RFC1918 addresses, cloud metadata endpoints
included, unless you pass
--allow-private.
Point it at sites you are responsible for. One probe requests a short list of paths that
should never survive a deploy — /.env, /.git/HEAD, lockfiles — and reports whether they are
publicly readable. That is what makes the "secrets kept out of the repository" check verifiable at
all. It only issues GET requests and reads at most two kilobytes, but in someone else's logs it
looks like scanning, and running it against infrastructure you do not own may be unlawful where
you are. SECURITY.md has the detail.
--token <value> additionally requires a bearer token on every request. It is off by default:
those four checks are what actually keep other pages out, and requiring a paste step bought
nothing but setup friction. When it is on, /health advertises it and the app asks you for the
address under Settings → Live verification → Advanced.
Requires Node 20.19+ (or 22.12+) and npm.
npm installnpm run devThen open http://localhost:5173. On first run the app seeds a realistic demo project (example.com,
87% ready, two outstanding critical checks) so the dashboard is worth looking at immediately.
Its URL is a documentation domain, so live verification is deliberately unavailable for it — point
a project at a site you actually run.
Other scripts:
npm run build # typecheck + production build
npm run preview # serve the production build
npm run typecheck # app and verifier
npm run lint # oxlint
npm run format # prettier --write .
npm run dev:app # the app alone, without the verifier
npm run verify <url> # run the probes once
npm run verify:serve # start the verifier daemon alonenpm run test # single run
npm run test:watch # watch modeTests cover the logic that is easy to get quietly wrong: the weighted readiness score, per-category progress, checklist filtering, Markdown report generation, template capture and instantiation, the readiness history, date formatting, backup serialisation and validation, the store's actions, the persistence layer's recovery from malformed data, drift detection between verification runs, the verifier's HTML extraction and attribute parsing, its probe registry, and its refusal of private and loopback targets. One test pins the demo project to 87% and exactly two unresolved critical checks, so the seed cannot drift without failing the suite.
src/
├── components/
│ ├── ui/ Vendored shadcn/ui primitives (button, dialog, sheet, select, …)
│ ├── layout/ App chrome: sidebar, headers, logo, theme toggle, nav config
│ └── common/ Cross-feature pieces: empty states, coming-soon, badges
├── features/
│ ├── checklist/ The checklist itself: readiness, category cards, table, detail panel
│ ├── projects/ The projects section, and its create/settings/delete dialogs
│ ├── templates/ The templates section: list, preview, save and share
│ ├── reports/ Portfolio comparison, per-project report and the readiness trend
│ ├── settings/ Preferences and the local-data import/export tools
│ └── export/ Wiring the Markdown report to a browser download
├── data/ The 42 default checks, the platform-specific extras, the built-in
│ templates, and the demo project seed
├── hooks/ useMediaQuery, useTheme, useFormatDate, useDebouncedCallback
├── lib/ Pure domain logic: scoring, categories, filtering, markdown, templates,
│ history, backup serialisation, dates
├── store/ Zustand store, selectors and the validating localStorage adapter
└── types/ Zod schemas; every TypeScript type is inferred from one
verifier/ The optional local companion process
├── bin.ts CLI: verify once, or serve the daemon
├── server.ts Loopback HTTP daemon: CORS allowlist, token auth
├── safety.ts Refuses private, loopback and link-local targets
├── run.ts Fetches the page once, then runs every probe against it
└── probes/ One module per area: transport, headers, tls, dns, seo, assets,
analytics, exposure
The layering is deliberate:
types/holds Zod schemas, and the TypeScript types arez.inferof those schemas — so the runtime validation at the storage boundary and the compile-time types can never disagree.lib/is pure functions over those types.calcReadiness,calcCategoryProgress,filterItemsandbuildMarkdowntake data and return data, which is why they are cheap to test and why the tests run in milliseconds without a DOM.store/is the only place that mutates state or toucheslocalStorage. The side effect of actually downloading a file lives inlib/download.ts, kept separate from the purebuildMarkdownthat produces its contents.features/andcomponents/render that state. Presentation metadata — labels, icons, badge tints — lives once inlib/constants.tsrather than being spread across components.
Two conventions worth knowing:
ChecklistViewis mounted withkey={project.id}, so switching project resets filters and the selected check without a synchronising effect.- Dialog forms are mounted with their dialog, which resets their fields on open — again, no effect.
- A scheduled mode for the verifier, so monitoring does not depend on remembering to press Verify.
- Verifying automatically on open, rather than only when Verify is pressed.
- Alerting on a regression, via a webhook or mail from the verifier.
- Per-page probes rather than homepage-only, driven by the sitemap.
- Deep links per project and check (React Router), so a check can be shared as a URL.
- Bulk status actions and keyboard shortcuts for working through a long list quickly.
- PDF export alongside Markdown, and a printable client report.
- Editing a template's checks directly, rather than only capturing them from a project.
- Reordering checks, and grouping them into phases within a category.
Bug reports and pull requests are welcome. CONTRIBUTING.md covers the setup,
the layout of the code, and the two rules that matter when adding a probe: never guess, and check
your findings against a real site before trusting them.
Security issues should not go in a public issue — see SECURITY.md.
MIT © 2026 Florian Behrend
