Sample audit: nyxxi.io
Top 10 issues, ranked by user impact
1. Social icons link to generic homepages
HighFixedWhat: The footer's GitHub, X, Discord and YouTube icons pointed to github.com, x.com, discord.com and youtube.com, not to Nyxxi's own accounts.
Repro: Scroll to the footer and tap the X icon. It opened x.com's homepage.
In the landing page footer social links array (GitHub, X, Discord, YouTube), replace the placeholder homepage URLs with Nyxxi's real profile URLs. Remove any icon we don't have an account for. Keep target="_blank" and add rel="noopener noreferrer".
2. Paid plans couldn't be bought
High (revenue)FixedWhat: The checkout link map was empty, so "Start Studio" and "Upgrade to Studio" only led to a waitlist, and "Talk to us" (Agency, $79/mo) had no contact route. The price cards and "Upgrade" wording overpromised.
Repro: Open the app, click "Upgrade to Studio". You landed on the homepage instead of a checkout.
Set the Studio monthly/yearly and Agency price links to real Stripe Payment Links so "Start Studio" and "Upgrade to Studio" open checkout. Until those exist, relabel the buttons "Join Studio waitlist", mark the price cards "Coming soon", and make "Talk to us" a mailto: link or contact form.
3. Fixed header overlapped content on mobile
MediumFixedWhat: At 390px, the big "OPEN NYXXI" button scrolled under the transparent fixed header and sat on top of the header's own button and logo.
Give the fixed header a solid or blurred background (e.g. background: rgba(5,5,10,.85); backdrop-filter: blur(8px)) and a z-index above page content, and add scroll-margin-top to sections so content never renders under it on mobile.
4. Missing share image and tags (og:image, Twitter card, canonical)
MediumPartly fixedWhat: Only og:title, og:description and og:type were set, so links shared on X, Discord or iMessage showed no preview image. No canonical link; the app page had no OG tags at all.
Add to the index.html head: og:image (1200x630 PNG), og:url, og:site_name, twitter:card=summary_large_image, twitter:image, and a canonical link. Add noindex to the app page.
Re-check Oct 18: canonical, og:url, og:site_name and Twitter tags are live and the app page is noindexed. No og:image yet, so shared links still show no preview image.
5. robots.txt and sitemap.xml returned the homepage
Medium (SEO)FixedWhat: Both files returned the landing page's HTML. Lighthouse reported robots.txt as invalid (SEO score 91).
Add public/robots.txt (User-agent: * / Allow: / / Sitemap: ...) and public/sitemap.xml listing / so Cloudflare Pages serves them as static files instead of the SPA fallback.
6. Unknown URLs returned the homepage instead of a 404
Low–MediumFixedWhat: Mistyped URLs returned 200 and the landing page, so users got no "not found" message and search engines could index junk URLs.
Add a public/404.html page with a link back home so Cloudflare Pages returns a real 404 for unknown paths, keeping SPA routing only under /app/* via a _redirects rule.
7. App form fields had no labels
Medium (accessibility)FixedWhat: The search box, character Name input, file input and Look textarea had no programmatic label, so screen readers announced them only as "edit text". The theme toggle's name was just an emoji.
Connect each visible label ("Name", "Character sheet", "Look") to its input with htmlFor/id, add aria-label="Search" to the search input, and give the theme toggle aria-label="Switch to light theme" (update it dynamically).8. Low-contrast text
Low–Medium (accessibility)FixedWhat: Lighthouse flagged tag labels (3.65:1), grey text (3.69:1) and gold text (3.36:1). WCAG AA needs 4.5:1 for small text.
Raise contrast for small text: lighten the tag color to about #9d93ee, the muted grey to about #a29db5, and the gold to about #d4a14e (verify each at ≥4.5:1 against the background).
9. Broken heading structure
Low (accessibility + SEO)FixedWhat: The H1 read as single letters "N Y X X I", several headings were empty, and heading levels skipped.
Make the H1 a single readable text node (aria-label="Nyxxi" with decorative spans aria-hidden), give every H2 real text or demote decorative ones, and fix heading levels so they don't skip.
10. Mobile main-thread work; missing CSP and clickjacking headers
LowPartly fixedWhat: Mobile Lighthouse performance was 87 (FCP 2.1s, Speed Index 4.5s, TBT 280ms) with about 23 KiB of unused animation JS; desktop scored 100. No Content-Security-Policy or frame-ancestors header. The waitlist form had no spam protection.
Add a _headers file with a Content-Security-Policy (including frame-ancestors 'none') and X-Frame-Options: DENY. Lazy-load scroll animations after first paint and respect prefers-reduced-motion. Reject duplicate/malformed waitlist emails and add a honeypot field.
Re-check Oct 18: Content-Security-Policy (with frame-ancestors 'none') and X-Frame-Options: DENY are live. Mobile Lighthouse performance is now 91, but main-thread blocking (about 340ms) remains, and the animation lazy-loading hasn't shipped.
What was already working well
- No console errors, failed requests or 4xx responses at either width.
- Light and fast: 167 KiB and 8 requests on the landing page. Desktop Lighthouse: Performance 100, Best Practices 100, Accessibility 94. Mobile CLS 0.
- Hashed assets cached for a year; HTML revalidates.
- No API keys or secrets in any JS bundle. HTTPS everywhere, no mixed content.
- Waitlist form validates email and confirms signup; "Create character" stays disabled until a name is entered.
- Visible keyboard focus, alt text on all images, no horizontal scroll on phones.
Want this for your app?
VibeCheck Daily
One vibe-coding security tip a day. Free, unsubscribe anytime.
We only use your email for VibeCheck Daily. Unsubscribe anytime.