Launch check: is this page ready?
Launch day brings most of a page's audience, and a fix on day 2 misses most of them. Get it right before the post goes out.
This checklist applies to any page. Keep it free of page names and page data: write a new lesson here as a general rule, and keep the page and its numbers in the project's own notes.
How to run it
- Name the page. Its type (article or story, tool or game, hub), its job in one sentence, and its steps: arrived → usable → first use → main action → it worked → next step. Collapse the steps that don't apply. Don't add inputs, numbers or actions just to satisfy a check.
- Serve a local build (
dist/or the dev server) with analytics blocked. Never open the live page. - Go through every check at the four screens below. Mark each pass, fail, unverified, or N/A with a reason. For a check that takes judgement, write what you saw (the sentence you retold, the screenshot you looked at), not just "pass".
- Blocker: fix it or get the user's explicit waiver, and verify it if unverified. Recommendation: report it; it doesn't stop the launch.
- Write the result in the project's notes or task board, counting all 29 checks:
Launch check: 25 pass, 1 fail, 1 unverified, 2 N/A; blocker: U1 fail; recommendation: S3 unverified; N/A: U2 (no input), U3 (no waits).
Screens: phone 390×844, tablet 820×1180, laptop 1366×768, large desktop 1920×1080. Check each one; a wide layout moves things as much as a narrow one. Confirm layout failures in a screenshot, since source alone can't show them.
Browser: a headless Chromium (Playwright) is enough, since a local build needs no login. Before loading the page,
block your analytics host on that tab (page.route(/your-analytics-host/, r => r.abort())), so checks never count
as visits.
By page type:
- Article or story: continuing to scroll is the next step, so U2 is N/A, and U3 if nothing waits.
- Tool or game: T2 covers whatever text the page has; the first use must give a real result.
- Hub: the payoff is finding the right thing, so T1 means each link does what it promises.
Hook
- H1 · Blocker. From the first screen alone, at every size, you can say in one sentence what the visitor gets. The payoff, not the topic. Write that sentence down. If you can't write it, or it only names the subject, this fails.
- H2 · Recommendation. The first screen gives a stranger a reason to continue: a specific finding, number, result or question, and a true one. It should still work for someone arriving from a post with no context.
- H3 · Recommendation. The link preview makes the same promise.
og:image, title and description say the payoff. Check the tags and the image in the build. - H4 · Blocker. The first action is visible without scrolling at every size, and clearly looks like one, with enough contrast. On a scroll story the first action is the scroll: a visible scroll cue passes.
Body
- T1 · Blocker. The body delivers what the hook promised, and early. The payoff doesn't wait for the end. If the page is long, a short version comes first and the rest is the visitor's choice.
- T2 · Blocker. It reads well from start to finish. Read all of it in order, as a stranger would. Each part follows from the one before and adds something, nothing is padding, and you can retell the whole thing in one sentence.
- T3 · Recommendation. One main point or number per screen. The rest goes in a table or behind "more". N/A if the page presents no numbers or findings.
- T4 · Blocker. Every number and claim has a source, and everything hidden works. Open every drawer, tab and accordion and follow every source link. A closed section is still part of the page.
- T5 · Recommendation. The copy passes the author's style rules and an AI-writing-tells check, with no placeholder, draft or debug text left. Page copy goes out under the user's name, so report problems and ask; don't reword it alone.
Screens
- S1 · Blocker. It looks right at all four screens, at every step. Take a screenshot after each step, and look at each one: nothing cut off, overlapping or unstyled (script-made elements can miss scoped CSS), no sideways scroll. After a search or pick that moves a map, check that the result lands in the part not covered by a panel, at every size.
- S2 · Blocker. All text is readable at its rendered size. Measure it, don't judge by eye, and aim for 12 px or more. For SVG charts: font size × rendered width ÷ viewBox width.
- S3 · Recommendation. Usable in under 2 s on a phone. Usable means the earliest point at which the first action works. Time it from when loading starts, with a cold cache and a stated phone CPU and network profile. An unthrottled desktop run can't show a phone pass.
- S4 · Blocker. Slow and failed loading both look right. Test slowed networks (CDP
Network.emulateNetworkConditions, 9 / 1.6 / 0.75 / 0.4 Mbps) and a failed load. Serve with compression like the CDN for timings; an uncompressed local server overstates every wait. Screenshot every 0.5 s across each loading handover from a cold start, and look at the frames. Keep the last good picture up with a loading label; a fallback is for failure only. Labels must be right during loading and after failure. N/A if nothing loads late.
Use
- U1 · Blocker. After each step, the next control is on screen at every size, where the page leaves the visitor. Test each way into a step separately (example, typed, tapped). Check every scroll target, sticky header and the fold.
- U2 · Recommendation. There's a one-tap way in (an example or preset) beside any free-form input, and the event says which was used. N/A without free-form input.
- U3 · Blocker. Any wait over 2 s shows progress and ends in a clear result or a clear error. Drive a delayed and a failed response locally. A spinner that never ends fails. N/A if no action waits. A control shown before its script has loaded (a form for a lazy map) must work or queue: use it during loading and after a failed load. An unhandled form submit reloads the page.
Next step
- N1 · Recommendation. At the moment of success there's one clear next thing: a related page, try another, play again. Put it where success happens, not in the footer.
- N2 · Recommendation. Share buttons that send the finding: WhatsApp, Facebook, X
and copy link, each carrying one written sentence with the finding, not only the title, placed where the result
appears. The sentence is public copy, so the user words it: ask. A hub without a finding
still needs a sentence from the user. Don't invent one or mark this N/A alone. The
shareevent sends the network only, never the text or the URL.
Search
Google's AI answers (AI Overviews, AI Mode) take pages from the ordinary Search index: a page that ranks with a snippet can be cited, and no AI-only file or markup is needed. Structured data must match what the page shows.
- F1 · Blocker. The page can be indexed: one canonical address, no stray
noindex, listed in the sitemap. A page too thin to rank (a stub that only links elsewhere, an empty list) is kept out of search instead:noindexand out of the sitemap, with no other language version pointing to it. - F2 · Recommendation. The title says what the page holds, not the site's name alone, with the name at the end; the description is the page's own and appears on no other page.
- F3 · Recommendation. A visible line says who made it, when it was published and how new its data is, with the same publish date in the structured data. Change the modified date only when the content really changes. N/A for a hub.
- F4 · Blocker. Every image in the HTML has a source and real alt text, including figures shown only without
JavaScript. An empty
<img>fails. - F5 · Recommendation. A page built on data offers the data: a CSV after a privacy check (only the fields the
page already shows), a licence line beside the download, and
Datasetmarkup. A video getsVideoObjectmarkup with a poster. N/A when the page has neither.
After launch: request indexing for the page in Search Console (the user's account, so ask), and add the question it answers to the project's AI-answer question list if it keeps one.
Measuring
The checks assume a privacy-friendly event tracker (Umami, Plausible or similar) with custom events.
- M1 · Blocker. The events are in the build that launches. One event per applicable step, one per action, success
is the effect and not the click, and a
*-leaveevent gives the furthest step and the time in view. - M2 · Blocker. The events fire through the real tracker. A stubbed tracker function can hide lost events.
Run the real tracker on the production hostname, with
context.routeserving the local build and catching the tracker's send endpoint so nothing leaves the machine. Drive every control, jump links too: each event describes its action, failure sends no success, and a jump past content sends no reading event. Follow a tracked outbound link in the same tab and check the*-leaveevent still arrives: a request started while the page unloads can be lost, so such links open in a new tab. - M3 · Blocker. Events are listed in the project's
docs/analytics.mdwith the go-live time, and a funnel spec is indocs/funnels/(saving it in the analytics tool needs the user's yes). - M4 · Blocker. Nothing a visitor typed or chose is sent to analytics: no hash in pageviews (exclude the hash), no query text, no places. Fixed labels and buckets only.
- M5 · Blocker. Targets are written down before launch (a number per step you expect to reach), so the review after launch has something to compare against.
- M6 · Blocker. Agents stay off the live page, because their visits count as real traffic. A check script that can point at the live page must block analytics itself.