View on GitHub

good-website-checklist

Everything that makes a website good in 2026.

Guidelines to create a strong website

Here you’ll find out all the things I could think of and find out, to create a “good” website.

From security, to performance, social sharing, analytics etc. I’m trying to not forget anything. This is not about which framework to use, but about everything that makes a “good” website in general: secured, performant, social compliant, SEO compliant, offline ready, and more.

This list is growing over time. Last full rewrite: July 2026 — the 2017 edition was full of HPKP, AMP, Google+ and polyfill.io. See Care about deleting ? for everything that got cut and why.

You know more ?

Don’t hesitate to PR! Let’s try to be concise: other resources on the web go further in details for each topic, let’s keep them one-liner here with a sample code when necessary.

Be strong

Summary

Care about security ?

Care about social ?

  - `twitter:card` is the only X-specific tag still worth shipping: X falls back to `og:*` for title/description/image, but *not* for the card type — omit it and you get the small thumbnail.
  - `og:image:width`/`height` aren't cosmetic: without them Discord may render a small thumbnail instead of a large embed.
  - `og:type=article` unlocks `article:published_time` / `article:author`, which LinkedIn and Discord surface as attribution. Slack ignores `og:type` entirely.
  - Discord colors the left border of the embed with `<meta name="theme-color">`. Nobody else does.
  - WhatsApp: hard cap 600 KB on the image, min 100px, cropped to a square in threads. Telegram: needs `og:title` minimum, image ≥200×200, no cache purge tool (append `?v=2` to force a refetch).
  - Bluesky reads Open Graph, no `twitter:*`, image ≤1 MB, always rendered landscape so square images get cropped.
  - Mastodon 4.3+ author attribution (also requires allow-listing the domain in Preferences → Public Profile → Verification)
```html
<meta name="fediverse:creator" content="@you@instance.social">
  - Generate OG images dynamically instead of hand-designing them: [@vercel/og](https://vercel.com/docs/og-image-generation) (Satori → SVG → resvg → PNG), `workers-og` on Cloudflare, or plain `satori` + `@resvg/resvg-js` at build time. Satori is flexbox-only, no CSS grid.
  - Validators that still work
    - [LinkedIn Post Inspector](https://www.linkedin.com/post-inspector/) — no login, forces a cache purge
    - [Facebook Sharing Debugger](https://developers.facebook.com/tools/debug/) — needs a FB developer account, "Scrape Again" is still the only FB cache purge
    - [opengraph.xyz](https://www.opengraph.xyz/) — no-login multi-platform preview
    - X: no validator anymore, post the link from a test account
  - Don't add share buttons. Third-party JS + trackers + CSP headaches for a link you can hand-write: `https://x.com/intent/post?url=…`, `https://bsky.app/intent/compose?text=…`, `mailto:`.

## Care about SEO ?

  - Serve HTTPS, one canonical host, stable URLs. A URL you change is a URL you lose in both search *and* AI training sets.
  - `robots.txt`: Google only supports `user-agent`, `allow`, `disallow`, `sitemap` ([RFC 9309](https://www.rfc-editor.org/rfc/rfc9309.html)). `crawl-delay`, `noindex`, `nofollow` are **ignored** there — `noindex` goes in a meta or an `X-Robots-Tag` header.

User-agent: * Disallow: /admin/ Allow: / Sitemap: https://example.com/sitemap_index.xml

  - `sitemap.xml`: 50k URLs / 50 MB max per file, else a sitemap index. Google **ignores `<priority>` and `<changefreq>`**, and uses `<lastmod>` only if verifiably accurate — a build-time `now()` on every URL gets the whole signal discarded. https://developers.google.com/search/docs/crawling-indexing/sitemaps/build-sitemap
  - Image/video/news sitemap extensions still exist and are still read. Skip them unless media *is* the product.
  - Push new URLs with [IndexNow](https://www.indexnow.org/documentation) — Bing, Yandex, Naver, Seznam, Yep. Google does not support it and never shipped it. Still matters: Bing's index feeds ChatGPT Search and Copilot.
```bash
curl "https://api.indexnow.org/indexnow?url=https://example.com/page&key=<32-128-char-key>"
# the key file must be readable at https://example.com/<key>.txt
  - `hreflang` must be reciprocal and include `x-default`. A missing return link voids the whole cluster.
```html
<link rel="alternate" hreflang="en-us" href="https://example.com/us/" />
<link rel="alternate" hreflang="fr"    href="https://example.com/fr/" />
<link rel="alternate" hreflang="x-default" href="https://example.com/" />

Care about AI assistants ?

Training/grounding opt-out tokens (not real crawlers, no effect on Search)

User-agent: Google-Extended User-agent: Applebot-Extended Disallow: /

Retrieval + user-triggered fetchers — ALLOW these if you want citations

User-agent: OAI-SearchBot User-agent: ChatGPT-User User-agent: Claude-SearchBot User-agent: Claude-User User-agent: PerplexityBot User-agent: Perplexity-User Allow: /

  - Know what each token gates: `Google-Extended` covers **Gemini training and grounding only — it does NOT remove you from AI Overviews**. AI Overviews are Search; the controls are `nosnippet` / `data-nosnippet` / `max-snippet` / `noindex`, which also kill your normal snippet. https://developers.google.com/search/docs/appearance/ai-features
```html
<span data-nosnippet>internal note, never quoted</span>
<meta name="robots" content="max-snippet:-1, max-image-preview:large" />

Care about metadata ?

...
  - Never `user-scalable=no` or `maximum-scale=1`: WCAG requires 200% zoom, browsers increasingly ignore it anyway, and audits still flag it.
  - `viewport-fit=cover` for notch/Dynamic Island edge-to-edge layouts, paired with `env(safe-area-inset-*)` padding. `interactive-widget=resizes-content` only if the virtual keyboard must resize your layout.
  - Declare color schemes in HTML, not CSS — the browser paints faster
```html
<meta name="color-scheme" content="light dark">
<meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)">
<meta name="theme-color" content="#111111" media="(prefers-color-scheme: dark)">
  - The sitemap belongs in `robots.txt` (`Sitemap: https://…`), not in a `<link>`.
  - Avoid Google's translation bar when you know it's not needed
```html
<meta name="google" content="notranslate">

Care about icons ?

  - Files: `favicon.ico` (32×32), `icon.svg` (embed `@media (prefers-color-scheme: dark)` *inside* the SVG), `apple-touch-icon.png` (180×180), plus `icon-192.png` / `icon-512.png` / `icon-mask.png` (512×512 maskable, safe zone = center 80%) referenced from the manifest only.
  - `sizes="32x32"` on the .ico is deliberate: `sizes="any"` makes Chrome download both the ICO and the SVG.
  - Generate with https://realfavicongenerator.net/ — it dropped Windows Metro and Touch Bar icons in Oct 2024, so its output is finally lean.

## Care about accessibility (a11y) ?

  - Build against **WCAG 2.2 AA** ([spec](https://www.w3.org/TR/WCAG22/) · [filterable quickref](https://www.w3.org/WAI/WCAG22/quickref/)). Nine criteria are new vs 2.1, and `4.1.1 Parsing` was removed.
    - **2.4.11 Focus Not Obscured (AA)**: sticky headers, cookie banners and chat widgets must not cover the focused element
    - **2.5.7 Dragging Movements (AA)**: every drag interaction needs a single-pointer alternative (tap-to-select → tap-to-place)
    - **2.5.8 Target Size Minimum (AA)**: 24×24 CSS px, or enough spacing between targets
    - **3.2.6 Consistent Help (A)**: help link/chat in the same relative order on every page
    - **3.3.7 Redundant Entry (A)**: don't re-ask for data already given in the same process
    - **3.3.8 Accessible Authentication (AA)**: allow paste into OTP/password fields, support passkeys, no puzzle CAPTCHA as the only path
  - WCAG 3.0 is not a target: [March 2026 Working Draft](https://www.w3.org/TR/wcag-3.0/), Bronze/Silver/Gold model, Candidate Rec not before ~2027. Track it, don't ship against it.
  - Legal deadlines already in force, not advice
    - **European Accessibility Act** applies since **28 June 2025** to consumer e-commerce, banking, telecom, transport booking, ebooks, AV media — including non-EU companies selling to EU consumers ([Directive 2019/882](https://eur-lex.europa.eu/eli/dir/2019/882/oj)). Microenterprise exemption: <10 staff **and** <€2M turnover.
    - **EN 301 549** is the harmonised standard; v3.2.1 maps to WCAG 2.1 AA, the next revision (2.2 AA) is in progress.
    - **ADA Title II (US)**: WCAG 2.1 AA. The DOJ's interim final rule of 20 Apr 2026 (91 Fed. Reg. 20902) pushed the deadlines to 26 Apr 2027 (population ≥50k) and 26 Apr 2028 (smaller entities) — only those dates moved, the nondiscrimination duty applies today. https://www.federalregister.gov/documents/2026/04/20/2026-07663
    - Publish an accessibility statement (conformance level, known gaps, contact, date) with the [W3C generator](https://www.w3.org/WAI/planning/statements/)
  - Automate what can be automated, and know the ceiling: [axe-core](https://github.com/dequelabs/axe-core) is the engine under Lighthouse and most scanners, and Deque's own figure is **57% of issues found automatically**. A 100 Lighthouse a11y score only proves the automatable subset passed.
  - Fail the build on violations with [`@axe-core/playwright`](https://github.com/dequelabs/axe-core-npm/tree/develop/packages/playwright) or [vitest-axe](https://github.com/chaance/vitest-axe)
```js
const results = await new AxeBuilder({ page }).withTags(['wcag2a','wcag2aa','wcag21a','wcag21aa','wcag22aa']).analyze();
expect(results.violations).toEqual([]);

Care about privacy ?

Care about style ?

Care about browser support ?

Care about performance ?

  - Speculation Rules replace `rel=prerender` and JS hacks like instant.page — real prerender, URL patterns, eagerness levels, silently ignored where unsupported
```html
<script type="speculationrules">
{"prerender":[{"where":{"and":[{"href_matches":"/*"},
  {"not":{"or":[{"href_matches":"/logout"},{"href_matches":"/cart*"},{"href_matches":"/account*"}]}}]},
  "eagerness":"moderate"}],
 "prefetch":[{"urls":["/checkout"],"eagerness":"immediate"}]}
</script>

Care about mobile ?

Care about offline ?

Care about analytics ?

Care about bugs ?

Care about ops ?

Care about misc ?

Care about deleting ?

Everything below was in the 2017 edition of this list, or is still being copy-pasted from old boilerplate. Delete it.

More tips