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 |
Footer
| 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 |
Footer
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.
Footer
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.
Footer
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.
Footer
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.
Footer
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.
Footer
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
-
"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. -
"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/aboutwill lose their scroll position on the about page and reload/. -
#waitlistanchor in PricingTeaser CTAs is a dead anchor on any page that is NOT/. ThePricingTeasercomponent (rendered only onLandingRoot) has three tier cards whose CTAs all readhref="#waitlist". These only exist on/. However,PricingTeaseris only rendered as part ofLandingRoot, so this is only triggered by the wildcard 404 case below. -
Wildcard 404 renders
LandingRootwith 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'sPricinghref resolves to#pricing(anchor-scroll behavior, sincelocation.pathnameis the unknown path, not/). This means theisRootguard inLandingNavfires on the unknown path —isRoot = location.pathname === '/'returnsfalsebecause the path is/404-test. So the nav actually rendersPricing→/pricingon the 404 page, not#pricing, even though theLandingRootcomponent is rendering. This is inconsistent — the 404 page renders landing content but nav behaves as a subpage. -
Contact page uses
placeholder-contact@raxx.appas the live email address. TheContactPagecomponent hasCONTACT_LOCAL = 'placeholder-contact'andCONTACT_DOMAIN = 'raxx.app', producingplaceholder-contact@raxx.app. This is visible on the live site athttps://getraxx.com/contactas 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. -
/waitlistshows$29/month for everything, locked for 6 monthspricing copy. TheWaitlistPagecontains a hardcoded Founders callout: "Waitlist sign-ups receive Founders pricing: $29/month for everything, locked for 6 months." Perproject_pricing_tiers_locked.md, Founders at $29 for 6 months is the locked price. However,PricingPageexplicitly showspriceLine: '3 months free on conversion.'for the Founders Promo tier — no dollar amount. These two surfaces describe the Founders offer differently:/waitlistsays "$29/month, locked 6 months";/pricingsays "3 months free on conversion." They are not describing the same offer in consistent terms to the same user. -
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. -
Aboutpage "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. -
Desktop nav links are present in DOM but inaccessible at mobile widths without the hamburger. The
[role="list"]div is CSS-hidden at< 640pxviadisplay: 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. -
docs.raxx.appfooter link has notarget="_blank"orrelattribute. 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:
-
placeholder-contact@raxx.appis live on production — operator-action required before any real user visits/contact. File asseverity:highbecause a user clicking that mailto will get a bounce or send to an incorrect destination. -
/waitlistand/pricingdescribe the Founders offer inconsistently — "$29/month for 6 months" vs "3 months free on conversion." These need to be reconciled before launch-ready status is claimed. Likely a copy decision for PM. -
All routes share one
<title>tag — no per-page meta titles or descriptions. Not a nav issue but a SEO/usability gap that should land before public launch. -
404-test/ wildcard returns HTTP 200 and renders LandingRoot with no "not found" indication. If the operator wants proper 404 handling, a dedicatedNotFoundPagecomponent is needed and the wildcard route should emit a non-200 signal (Cloudflare Pages supports_redirectswith 404 status code for specific patterns). Not urgent pre-launch but relevant once the site is public. -
"Get in touch" on
/aboutuses bare<a href="/contact">not<Link>— causes full page reload. One-line fix inAboutPage.jsx.