Audit Date: 2026-02-19
Audited By: Claude Code (Opus 4)
Scope: Full codebase (36 source files, 15 CSS files, 110+ assets, 8 components, 22 pages)
Live Site: https://urwhats.com (all 8 public pages fetched and analyzed)
| Category | Score | Key Issues |
|---|
| Architecture & Packages | 8/10 | Lean dependencies, clean structure |
| UI/UX Design | 7/10 | CTA hidden on mobile, no 404 page |
| Content Quality | 5/10 | Legal contradictions, thin FAQs, fake reviews |
| SEO | 4/10 | CRITICAL: Meta descriptions broken on live site |
| Accessibility | 5/10 | Color contrast fails WCAG, no skip link |
| Performance | 7/10 | Unused CSS bloat (style.css 8000 lines) |
| Security | 8/10 | Good CSP, but unsafe-inline/eval in CSP |
| i18n / Localization | 7/10 | Good Arabic, but duplicated page files |
These are actively hurting the website RIGHT NOW:
- Severity: CRITICAL (SEO destroyed)
- URL: Every page except homepage
- Evidence:
<meta name="description" content="meta.services.html.description">
- Cause:
SEO.astro builds translation key with .html in the path (e.g., meta.services.html.description instead of meta.services.description)
- Impact: Google indexes gibberish descriptions, OG/Twitter sharing broken, AI crawlers get nonsense
- Fix: Debug page name extraction in
SEO.astro — the Astro pathname includes .html on some pages
- Severity: CRITICAL
- URL:
/ar (Arabic homepage)
- Evidence:
<a href="/.html">EN</a> in the navigation
- Cause:
getLanguageSwitchLink() in page.config.ts generates empty slug + .html for the homepage
- Impact: Arabic users cannot switch to English from the homepage
- Severity: CRITICAL (SEO)
- URL: All Arabic pages
- Evidence:
<link rel="alternate" hreflang="ar" href="https://urwhats.com/ar/.html">
- Cause: Same slug extraction bug as BUG 1
- Impact: Google cannot properly index bilingual pages, may cause duplicate content penalties
- Severity: HIGH
- URL:
/ar
- Evidence:
<link rel="canonical" href="https://urwhats.com/ar.html">
- Expected:
https://urwhats.com/ar
- Severity: HIGH
- File:
public/assets/images/logos/urWhats-og-image.png (referenced in SEO.astro but does not exist)
- Impact: Social sharing on Facebook, Twitter, LinkedIn shows no preview image
- Minimal dependency footprint (3 prod + 3 dev npm packages)
- Astro 5.16 + static output — excellent for marketing site
- Clean separation: config, components, layouts, models, utils
- TypeScript strict mode with path aliases
- Comprehensive CSS design token system in custom-overrides.css
| # | Issue | Severity | File |
|---|
| 1 | No ESLint or Prettier configured | Medium | Root |
| 2 | Alpine.js loaded from CDN with wildcard @3.x.x — no version pin | Medium | Layout.astro |
| 3 | Duplicate sitemap: static public/sitemap.xml AND dynamic src/pages/sitemap-index.xml.ts | Medium | Both |
| 4 | Service Worker cache stuck at v1 with no auto-busting | Medium | sw.js |
| 5 | Plans.astro (583 lines) is dead code — fully commented out | Low | Plans.astro |
| 6 | Unused CSS files: 4 color themes (red, sky, yellow), 4 font CSS files never loaded | Low | public/assets/css/ |
- Professional design system with CSS custom properties (18 colors, 8 spacing tokens)
- Consistent green brand identity (#45b33d)
- 5 responsive breakpoints
- Full RTL support
- Scroll animations via IntersectionObserver
- Floating WhatsApp FAB on all pages
| # | Issue | Severity | File |
|---|
| 1 | ”Start Free Trial” CTA hidden on mobile (d-none d-md-block) | HIGH | Navigation.astro |
| 2 | Solution cards “Learn More” all link to /faqs instead of /services | Medium | index.astro |
| 3 | No 404 page exists | Medium | Missing |
| 4 | Mobile nav drawer has no backdrop/overlay | Medium | Navigation.astro |
| 5 | Duplicate illustrations: platform.png used for 2 different services | Medium | services.astro |
| 6 | No CTA buttons on /services, /use-cases, /faqs pages | Medium | Multiple |
| 7 | ”Choose Plan” links go to /contact, not app.urwhats.com/register | HIGH | DynamicPlans.astro |
| 8 | Inconsistent breakpoints (768px vs 767px for same threshold) | Low | Multiple |
- Arabic translation quality is above average (not machine-translated for main sections)
- Good hero statistics (10x results, 98% delivery, 5x conversion)
- FAQ structure covers 5 categories
| # | Issue | Severity | Details |
|---|
| 1 | Privacy Policy says Dubai/UAE, Terms say Saudi Arabia | CRITICAL | Contradictory legal jurisdiction |
| 2 | AggregateRating 4.8/5 from 150 reviews — no source | HIGH | Risk of Google manual action |
| 3 | Pricing page (en.json) shows different model than homepage | HIGH | 3 plans with “Projects” vs 4 plans with “Users” |
| 4 | Meta Technical Provider not mentioned anywhere | HIGH | Biggest trust signal missing |
| 5 | 30+ compound word typos in byIndustry/byRole sections | Medium | ”highintent”, “nocode”, “followups” etc. |
| 6 | ”7/24” instead of “24/7” (3 instances) | Medium | en.json lines 345, 352, 358 |
| 7 | Arabic apps page title says “urWave” instead of “urWhats” | Medium | ar.json line 576 |
| 8 | Arabic phone number formatted backwards in privacy policy | Medium | ar.json line 75: 971-509056326+ |
| 9 | Duplicate FAQ content between homepage and FAQs page | Low | Same questions copy-pasted |
| 10 | Trailing spaces in multiple translation values | Low | en.json lines 98, 127, 130 |
- 7 JSON-LD schemas per page
- Per-page unique titles in both languages
- Proper hreflang structure (when URLs aren’t broken)
- AI-specific meta tags and llms.txt files
- Comprehensive robots.txt
| # | Issue | Severity |
|---|
| 1 | All meta descriptions show raw i18n keys on live site | CRITICAL |
| 2 | Broken hreflang URLs (append .html) | CRITICAL |
| 3 | Broken canonical URL on Arabic pages | HIGH |
| 4 | Missing OG image | HIGH |
| 5 | Fake AggregateRating could trigger Google manual action | HIGH |
| 6 | Duplicate robots meta tag in head | Medium |
| 7 | URL casing inconsistency: /Privacy and /Terms vs lowercase everything else | Medium |
| 8 | Duplicate sitemaps | Medium |
| 9 | Static dateModified in WebPage schema (hardcoded, never updates) | Medium |
| 10 | SearchAction target points to /contact?q= (not a real search) | Low |
<html lang> and dir set correctly per language
- Form accessibility: labels, aria-required, role=“alert”
prefers-reduced-motion support
- 44px minimum touch targets on mobile
:focus-visible styles defined
| # | Issue | WCAG | Severity |
|---|
| 1 | No skip navigation link (CSS exists, HTML missing) | 2.4.1 | HIGH |
| 2 | Green #45b33d fails WCAG AA on white (3.2:1 ratio, needs 4.5:1) | 1.4.3 | HIGH |
| 3 | Alpine.js price updates not announced to screen readers | 4.1.3 | Medium |
| 4 | Accordion buttons missing aria-expanded | 4.1.2 | Medium |
| 5 | Mobile hamburger doesn’t trap focus | 2.4.3 | Medium |
| 6 | Images without width/height cause CLS | N/A | Medium |
| 7 | Pricing toggle has no aria-pressed | 4.1.2 | Medium |
- Static HTML (no server runtime)
- Vendor chunk splitting (Bootstrap separate)
- 1-year immutable cache on static assets
- Service Worker with stale-while-revalidate
- Lazy image loading
| # | Issue | Severity |
|---|
| 1 | style.css is 8000+ lines of unoptimized theme CSS (~200KB) | HIGH |
| 2 | Bootstrap CSS fully loaded (~200KB) but only ~30% used | Medium |
| 3 | Alpine.js loaded on every page but only used on /prices | Low |
| 4 | 5 CSS files loaded sequentially in head | Medium |
| 5 | PNG illustrations could be WebP (50-70% smaller) | Medium |
- Comprehensive CSP header
- HSTS with preload (1 year)
- X-Frame-Options: DENY
- Contact info obfuscation
- Cloudflare Turnstile CAPTCHA
noopener noreferrer on external links
| # | Issue | Severity |
|---|
| 1 | ’unsafe-inline’ and ‘unsafe-eval’ in CSP script-src | HIGH |
| 2 | Formspree endpoint exposed (expected for client-side, but noted) | Low |
- Full bilingual EN/AR with mirrored page structure
- RTL support in every component
- Language switcher preserves current page
- Arabic font (Tajawal) loaded for RTL only
| # | Issue | Severity |
|---|
| 1 | 11 duplicated page files (Arabic mirrors) — could use dynamic [lang] route | Medium |
| 2 | No fallback if translation key missing (shows raw key path) | Medium |
| 3 | Translation files in public/ — exposed at /assets/i18n/en.json | Low |
| 4 | HTML mixed into translation strings | Low |