About this audit
linear.app scored 6.7/10
Genuinely strong engineering, undercut by two site-wide defects: a canonical that hands a product page to a login stub, and a mobile menu no screen reader can name.
This is a full example audit — 10 evidence-led findings across accessibility, performance, SEO, structured data, privacy and security, each with a measurement, a screenshot and a concrete fix. The headline issue: /build tells Google its canonical version is a login page returning 200.
What we found
critical/build tells Google its canonical version is a login page returning 200
The server HTML for https://linear.app/build contains <link rel="canonical" href="https://linear.app/build-rewrite"/> — verified in the raw response, not injected by JavaScript, so crawlers see it on first byte. Fetching https://linear.app/build-rewrite returns 200 OK and renders the login screen: title Linear, H1 Log
criticalThe mobile menu button has no accessible name — on 5 of 6 pages
button.TZTsQG_mobileMenuTrigger is a 64×64 px control containing a bare <svg> hamburger icon with no aria-label, no title, no text and no <title> in the SVG. Measured live at 375 px, its accessible name is empty. axe reports it under button-name (critical, WCAG 2.0 A, criterion 4.1.2) on the homepage, /customers, /codi
warningOne muted-text token fails AA at 3.45:1 — 78 flagged elements across 5 pages
The design token --color-text-quaternary: #62666d measures 3.45:1 against the page background --color-bg-primary: #08090a. WCAG AA requires 4.5:1 for normal text, and this token is used at 12–13 px — far below the 18.66 px large-text exemption. axe reports it under color-contrast (serious, WCAG 2.1 AA, criterion 1.4.3)
warningThe login screen disables pinch-zoom and its primary button misses AA at 3.93:1
/login ships <meta name="viewport" content="...,maximum-scale=1,user-scalable=no,...">, confirmed live. axe flags this under meta-viewport (WCAG 2.1 AA, criterion 1.4.4 Resize Text): it prevents a low-vision user from pinch-zooming the one screen where they are typing credentials and reading error messages. On the same
warningA 3,526 px carousel scrolls in a 1,440 px window with zero keyboard access
On /coding-sessions at 1440 px, .NAY0wa_content.Fzcv4W_hideScrollbars has scrollWidth: 3526 inside clientWidth: 1440 with overflow-x: scroll — 2,086 px of content sits outside the visible area. Measured live, the element has no tabindex, no role, and contains zero focusable children. That combination means a keyboard-o
warningThe customer-logo wall is a tabbable link wrapping 24 graphics with no name
a.MR81zG_logosLink on the homepage points to /customers, is in the tab order, wraps 24 customer logo graphics, and has no accessible text — no inner text, no aria-label, no title. axe reports it under link-name (serious, WCAG 2.0 A, criteria 2.4.4 and 4.1.2). It is the only unnamed visible link on the page. A screen-re
warning/build paints its hero at 8,328 ms — the video carries no poster frame
Lighthouse (mobile, lab) records /build at a Performance score of 67, with LCP 8,328 ms against FCP 3,355 ms. The 4,973 ms gap between first and largest paint is the hero region resolving long after the rest of the page. Measured live, the hero <video> is BUILD-v3.output.av1.crf24.mp4 — 1920×1080, autoplay, preload="me
warning/customers ships 10,702 KiB — three MP4s, two of them below the fold
Lighthouse records the total transfer for /customers at 10,702 KiB on mobile. Three MP4s account for the bulk of it: 3,064,081, 2,787,072 and 2,393,731 bytes — about 8.2 MB of video, or roughly three-quarters of the page. Measured live, all three <video> elements use preload="metadata" with no poster, no loading="lazy"
warningZero JSON-LD on all 6 pages — no Organization, WebSite or Article markup anywhere
Every audited page returns 0 structured-data blocks. The crawler's-eye no-JavaScript view of the homepage confirms 0 JSON-LD blocks in the raw HTML too, so this is not a hydration artifact — there is simply none. The gaps map cleanly onto page type: the homepage has no Organization (no logo, no sameAs profiles) and no
warningThe OpenAI case study's 316-character description contradicts the page's own data
/customers/openai carries a meta description of 316 characters — roughly double what search engines render, so it will be truncated mid-sentence. The same string is reused verbatim as og:description and twitter:description. More consequentially, its content disagrees with the page. The description states OpenAI has "ov