Raxx · internal docs

internal · gated

getraxx.com Navigation Audit — 2026-05-27

Auditor: qa-agent Date: 2026-05-27 UTC Live site: https://getraxx.com Method: Playwright 1.58.0 — live site, no local dev server Viewports: Desktop 1440×900, Mobile 390×844 (iPhone UA) Screenshots: docs/qa/screenshots/getraxx-2026-05-27/ Scope: All 7 routes + wildcard 404, LandingNav, LandingFooter, all in-page CTAs


Route inventory

Pages audited: /, /pricing, /about, /contact, /waitlist, /privacy, /terms, wildcard (/404-test). All returned HTTP 200.


/ — LandingRoot

Screenshots: home-desktop.png, home-mobile.png

Top nav — desktop (1440px)

Label href rendered Actual click behavior
RAXX (wordmark) / Route to / (React Router Link)
Product #pillars Anchor scroll to #pillars section on same page
Pricing #pricing Anchor scroll to #pricing section on same page (scroll delta: 1900px measured)
About /about Route navigation to /about
Join the waitlist /waitlist Route navigation to /waitlist

Note: the hamburger button is present in DOM at desktop but hidden via display:none via scoped CSS. Its href is null (it is a <button>). The desktop [role="list"] div is hidden at mobile.

Top nav — mobile (390px) hamburger closed

At 390px the [role="list"] desktop nav is CSS-hidden. Only the hamburger button is visible. The desktop anchor links are still present in DOM but not accessible without opening the menu.

Top nav — mobile hamburger open

Screenshot: home-mobile-hamburger-open.png

Label href Behavior
Product #pillars Anchor scroll (closes menu first via onClick)
Pricing #pricing Anchor scroll (closes menu first via onClick)
About /about Route navigation
Join the waitlist /waitlist Route navigation
Label href Type
About /about React Router Link
Privacy /privacy React Router Link
Terms /terms React Router Link
Documentation https://docs.raxx.app External <a>
Contact mailto:support@raxx.app mailto

Note: Cookie preferences button is absent from DOM — REACT_APP_COOKIE_BANNER_ENABLED flag is off on the live deployment.

In-page CTAs

Section Label href Behavior
Hero (open state, data-testid="hero-cta-open") Join the waitlist #waitlist Anchor scroll to #waitlist on same page
Hero (open state) See pricing #pricing Anchor scroll to #pricing on same page
PricingTeaser — Paper trading, free. Join the waitlist #waitlist Anchor scroll
PricingTeaser — Pro. Your live book. Join the waitlist #waitlist Anchor scroll
PricingTeaser — Pro+. The full book. Join the waitlist #waitlist Anchor scroll
WaitlistSection Join (form submit button) N/A (form submit) POST to /api/waitlist/signup

Hero gate state at time of audit: open (founders gate open or fail-open). ClosedCTA (data-testid="hero-cta-closed") was not rendered.

All three anchors (#pillars, #pricing, #waitlist) were confirmed present in DOM.


/pricing — PricingPage

Screenshots: pricing-desktop.png, pricing-mobile.png

Top nav — desktop

Label href rendered Actual click behavior
RAXX / Route to /
Product /#pillars Full-page navigation to https://getraxx.com/#pillars
Pricing /pricing Route navigation to /pricing (stays on page — same route)
About /about Route to /about
Join the waitlist /waitlist Route to /waitlist

Same as /About, Privacy, Terms, Documentation, Contact.

In-page CTAs

Tier Label href Behavior
Paper Join the waitlist /waitlist Route navigation
Pro Join the waitlist /waitlist Route navigation
Founders Promo Join the waitlist (+ "Founders priority" subline) /waitlist Route navigation

Note: All three tier CTAs navigate to /waitlist as a full route — not an anchor. This is correct behavior for a standalone pricing page.

No FAQ CTAs. No comparison table CTAs.


/about — AboutPage

Screenshots: about-desktop.png, about-mobile.png

Top nav — desktop

Same as /pricing: Product/#pillars, Pricing/pricing, About/about, Join the waitlist/waitlist.

Same as all other pages.

In-page CTAs

Section Label href Behavior
"The team" section Get in touch /contact Plain <a href="/contact"> — causes full page navigation (not React Router Link)

/contact — ContactPage

Screenshots: contact-desktop.png, contact-mobile.png

Top nav

Same as all subpages.

Same as all other pages.

In-page CTAs

Section Label href Behavior
Contact section placeholder-contact@raxx.app mailto:placeholder-contact@raxx.app mailto

/waitlist — WaitlistPage

Screenshots: waitlist-desktop.png, waitlist-mobile.png

Top nav

Same as all subpages.

Same as all other pages.

In-page CTAs

Label href Behavior
Join (form submit) N/A POST to /api/waitlist/signup
support@raxx.app (consent copy) mailto:support@raxx.app mailto

Flag gate state: REACT_APP_FLAG_GETRAXX_WAITLIST — the form was rendered (not the "opening soon" message), confirming the flag is ON on the live deployment.


/privacy — PrivacyPage

Screenshots: privacy-desktop.png, privacy-mobile.png

Top nav

Same as all subpages.

Same as all other pages.

In-page CTAs

Label href Behavior
support@raxx.app (stub contact) mailto:support@raxx.app mailto

Content: stub "Coming soon" — no live policy text.


/terms — TermsPage

Screenshots: terms-desktop.png, terms-mobile.png

Top nav

Same as all subpages.

Same as all other pages.

In-page CTAs

Label href Behavior
support@raxx.app (stub contact) mailto:support@raxx.app mailto

Content: stub "Coming soon."


Wildcard / 404

Screenshots: 404-desktop.png, 404-mobile.png

Route /404-test and /completely-missing-page-xyz both: - Return HTTP 200 (Cloudflare Pages /* /index.html 200 rewrite) - Render LandingRoot — hero H1 is "Stack raxx. No guessing." - No "Page not found" copy anywhere

Nav and footer identical to / (same component rendered).


Inconsistencies

  1. "Pricing" nav link uses two different targets depending on source page. On / (and its 404 wildcard clone), href="#pricing" — anchor scroll. On every other page (/pricing, /about, /contact, /waitlist, /privacy, /terms), href="/pricing" — route navigation. Same visual button, split behavior. This is the primary operator-flagged gap.

  2. "Product" nav link uses two different targets depending on source page. On /, href="#pillars" — anchor scroll. On every subpage, href="/#pillars" — full-page navigation to the home page and then the anchor. This is intentional by design but creates an asymmetry: clicking "Product" on any subpage causes a full navigation, not in-page scroll. Users who click "Product" from /about will lose their scroll position on the about page and reload /.

  3. #waitlist anchor in PricingTeaser CTAs is a dead anchor on any page that is NOT /. The PricingTeaser component (rendered only on LandingRoot) has three tier cards whose CTAs all read href="#waitlist". These only exist on /. However, PricingTeaser is only rendered as part of LandingRoot, so this is only triggered by the wildcard 404 case below.

  4. Wildcard 404 renders LandingRoot with no "not found" signal. Any unknown URL returns HTTP 200 and renders the full landing page as if the user had navigated to /. The PricingTeaser tier CTAs on this rendered page point to #waitlist, which resolves on this render. However, the nav's Pricing href resolves to #pricing (anchor-scroll behavior, since location.pathname is the unknown path, not /). This means the isRoot guard in LandingNav fires on the unknown path — isRoot = location.pathname === '/' returns false because the path is /404-test. So the nav actually renders Pricing/pricing on the 404 page, not #pricing, even though the LandingRoot component is rendering. This is inconsistent — the 404 page renders landing content but nav behaves as a subpage.

  5. Contact page uses placeholder-contact@raxx.app as the live email address. The ContactPage component has CONTACT_LOCAL = 'placeholder-contact' and CONTACT_DOMAIN = 'raxx.app', producing placeholder-contact@raxx.app. This is visible on the live site at https://getraxx.com/contact as a clickable mailto link and display text. The code comment says "operator must confirm the real address before public launch" — it has not been confirmed.

  6. /waitlist shows $29/month for everything, locked for 6 months pricing copy. The WaitlistPage contains a hardcoded Founders callout: "Waitlist sign-ups receive Founders pricing: $29/month for everything, locked for 6 months." Per project_pricing_tiers_locked.md, Founders at $29 for 6 months is the locked price. However, PricingPage explicitly shows priceLine: '3 months free on conversion.' for the Founders Promo tier — no dollar amount. These two surfaces describe the Founders offer differently: /waitlist says "$29/month, locked 6 months"; /pricing says "3 months free on conversion." They are not describing the same offer in consistent terms to the same user.

  7. All pages share a single <title> tag: "Raxx — Know your structure. Know your process." Every route — /, /pricing, /about, /contact, /waitlist, /privacy, /terms, and unknown paths — returns the identical <title>. No per-page title differentiation. Users with multiple tabs open cannot identify the tab by title. Search engines receive no per-page title signal.

  8. About page "Get in touch" link is a bare <a href="/contact">, not a React Router <Link>. This causes a full browser navigation (page reload) rather than a client-side route transition. All other internal navigation uses React Router <Link>. This is inconsistent with the rest of the site's SPA navigation pattern.

  9. Desktop nav links are present in DOM but inaccessible at mobile widths without the hamburger. The [role="list"] div is CSS-hidden at < 640px via display: none !important. The links inside it remain in the DOM and are focusable via keyboard tab. A screen reader or keyboard user at mobile width can tab through hidden nav items. This is an accessibility gap.

  10. docs.raxx.app footer link has no target="_blank" or rel attribute. Clicking "Documentation" in the footer navigates the current tab away from getraxx.com. Every other internal link stays in the SPA. The inconsistency is not necessarily wrong (some operators prefer in-tab for docs) but it is worth a deliberate decision.


Recommendations

Single consistent pattern: Route Pricing in the top nav to /pricing on every page including /. Remove the isRoot ? '#pricing' : '/pricing' conditional for the Pricing nav item entirely. The PricingTeaser section on / is a scroll-destination for the hero's in-page "See pricing" CTA — that #pricing anchor scroll remains and is meaningful for users arriving from hero. The top nav Pricing link should always mean "go to the full pricing page" regardless of which page you are on. Apply the same treatment to Product: always /#pillars regardless of route (or, alternatively, always / since #pillars is a secondary concern — consider whether the "Product" nav item is pulling its weight at all).

This is a one-line code change: remove pricingHref and productHref computed vars from LandingNav, set Product href statically to /#pillars and Pricing href statically to /pricing.


Items outside nav scope — separate cards warranted

These were surfaced during the audit and are not navigation issues, but each warrants a card: