{"url":"https://larsen.ee/","date":"2026-06-10","siteName":"Larsen - The Coolest Accommodation in Tallinn","overall":50,"reasoning":"Site overall 50 is the mean of 5 pages. Scores range 45 (https://larsen.ee/) → 52 (https://larsen.ee/et). Weakest page: Mobile performance is catastrophic (PSI 48, LCP 47.1s) due to 69 MB page weight and 1.37 MB unused JavaScript, dragging the score into the 'Poor' band. Accessibility is compromised by 2 critical axe violations (button-name, image-alt) and 11 W3C errors including heading skips. Security headers are weak (40/100) with missing HSTS and X-Frame-Options, though no auth/payments signals reduce immediate exploitation risk. Desktop performance (43) is similarly poor, indicating systemic architectural issues rather than just mobile throttling.","confidence":"high","fixes":[{"priority":1,"title":"Reduce JavaScript bundle and media weight to fix LCP","impact":"LCP (47.1s), FCP (3.6s), Total Page Weight (69 MB)","problem":"Mobile LCP is 47.1s with 1.37 MB unused JS (app-889782a39d4314ef1bf6.js) and 55 MB media weight causing massive load delays.","solution":"- Split the 1.37 MB `app-*.js` bundle using code splitting (React.lazy or dynamic imports).\n- Compress media: Convert 55 MB of images/video to WebP/AVIF and implement lazy loading.\n- Defer non-critical third-party scripts (Hotjar, PostHog) until user interaction."},{"priority":1,"title":"Fix critical accessibility violations","impact":"WCAG 2.1 Compliance, Screen Reader Usability","problem":"axe-core reports 2 critical violations: buttons lack discernible text (slider dots) and images lack alt attributes.","solution":"- Add `aria-label` to all slider dot buttons (e.g., `aria-label=\"Slide 1\"`).\n- Add descriptive `alt` text to all content images; use `alt=\"\"` for purely decorative icons.\n- Ensure all interactive elements have accessible names."},{"priority":1,"title":"Reduce JavaScript bundle size and eliminate unused code","impact":"LCP, FCP, TBT, Performance Score","problem":"1.4 MB of unused JavaScript detected (app-889782a39d4314ef1bf6.js alone is 1397 KB wasted), contributing to LCP of 36.2 s.","solution":"- Implement code splitting to load only necessary JS for the About page.\n- Tree-shake dependencies and remove unused third-party scripts.\n- Defer non-critical scripts (e.g., analytics, hotjar) until after main content renders."},{"priority":1,"title":"Optimize and lazy-load images","impact":"Page Weight, LCP, CLS","problem":"Images total 3.75 MB with no srcset, 6 missing lazy loading, and 1 missing alt attribute. Hero image is a CSS background.","solution":"- Convert all images to WebP/AVIF with fallbacks.\n- Add `srcset` and `sizes` attributes for responsive loading.\n- Add `loading=\"lazy\"` to non-hero images.\n- Move hero CSS background to a real `<img>` tag with `fetchpriority=\"high\"`."},{"priority":1,"title":"Strengthen Content Security Policy (CSP)","impact":"XSS Defense, Security Score","problem":"CSP is weak (only frame-ancestors set). Site signals indicate user-generated content (reviews), elevating XSS risk to Priority 1 per rubric.","solution":"- Implement a strict CSP with `default-src` and `object-src 'none'`.\n- Use nonces or hashes for inline scripts rather than a permissive allowlist.\n- Example: `Content-Security-Policy: default-src 'self'; script-src 'nonce-{random}' 'strict-dynamic'; object-src 'none';`"},{"priority":1,"title":"Fix Core Web Vitals (LCP, CLS) and Reduce JavaScript","impact":"Performance, LCP, CLS, TBT","problem":"Mobile Performance 49, LCP 4.1s (>4s penalty), CLS 0.651 (>0.25 penalty), and 1.4MB wasted JS (app-889782a39d4314ef1bf6.js).","solution":"- **LCP:** Remove `loading=\"lazy\"` from the hero image and add `fetchpriority=\"high\"`.\n- **CLS:** Reserve space for dynamic content (cookies, ads) using CSS `min-height` or aspect-ratio.\n- **JS:** Code-split the 1.4MB `app-889782a39d4314ef1bf6.js` and defer non-critical third-party scripts (Hotjar, PostHog)."},{"priority":1,"title":"Harden Security Headers (CSP & HSTS)","impact":"XSS protection, Transport security","problem":"Security Headers grade 40/100. HSTS max-age too short (15552000s) and missing `includeSubDomains`. CSP is weak (missing `default-src`). UGC signal present increases XSS risk.","solution":"- **HSTS:** `Strict-Transport-Security: max-age=31536000; includeSubDomains; preload`\n- **CSP:** Implement nonce-based CSP with `strict-dynamic`:\n  ```\n  Content-Security-Policy: default-src 'self'; script-src 'nonce-{random}' 'strict-dynamic'; object-src 'none'; base-uri 'none';\n  ```\n- **X-Frame-Options:** Add `X-Frame-Options: SAMEORIGIN` as fallback."},{"priority":1,"title":"Reduce JavaScript bundle and defer non-critical scripts","impact":"TBT, LCP, FCP, Performance Score","problem":"1.4 MB of unused JavaScript (GTM, PostHog, Facebook) causes 6.09 s TBT and 16.0 s LCP on mobile.","solution":"- Audit third-party scripts; remove unused tracking codes.\n- Load critical scripts inline or defer non-critical ones.\n- Use `module`/`nomodule` pattern for modern/legacy JS.\n- Implement code splitting to reduce initial bundle size."},{"priority":1,"title":"Fix Hero Image Loading Strategy","impact":"LCP, Performance Score","problem":"Hero image is lazy-loaded (`loading=\"lazy\"`), delaying LCP to 16.0 s on mobile.","solution":"- Remove `loading=\"lazy\"` from the hero image.\n- Add `fetchpriority=\"high\"` to the hero image.\n- Ensure hero image is preloaded if it's not the first resource."},{"priority":1,"title":"Implement Strict Content Security Policy (CSP)","impact":"XSS Protection, Security Score","problem":"CSP is missing `default-src` and `object-src`, leaving the site vulnerable to XSS (site has user-generated content).","solution":"- Deploy a nonce-based CSP rather than a flat allowlist.\n- Example: `Content-Security-Policy: default-src 'self'; script-src 'nonce-{random}' 'strict-dynamic'; object-src 'none';`\n- Ensure all inline scripts use the nonce."},{"priority":1,"title":"Reduce page weight and optimize media delivery","impact":"LCP, Speed Index, Total Blocking Time","problem":"Total page weight is 69.19 MB (56 MB media); LCP is 10.5 s on mobile. Unused JavaScript alone is 1.37 MB.","solution":"- Compress and resize images; serve WebP/AVIF.\n- Implement lazy loading for below-fold media.\n- Remove or defer unused JavaScript (e.g., `app-889782a39d4314ef1bf6.js`).\n- Use a CDN with edge caching to reduce TTFB and transfer time."},{"priority":1,"title":"Harden security headers for UGC site","impact":"XSS, Clickjacking, Transport Security","problem":"Security grade is 40/100. HSTS max-age is short (15M s) and missing `includeSubDomains`. CSP lacks `default-src`. Site has user-generated content (reviews), increasing XSS risk.","solution":"- Update HSTS: `max-age=31536000; includeSubDomains; preload`.\n- Add `X-Frame-Options: SAMEORIGIN`.\n- Implement strict CSP with nonce/hash: `Content-Security-Policy: default-src 'self'; script-src 'nonce-{random}' 'strict-dynamic'; object-src 'none';`"},{"priority":2,"title":"Strengthen Security Headers (HSTS, X-Frame-Options)","impact":"Transport Security, Clickjacking Protection","problem":"HSTS max-age is too short (15552000s) and missing directives; X-Frame-Options is missing entirely.","solution":"- Update HSTS: `max-age=31536000; includeSubDomains; preload`.\n- Add `X-Frame-Options: SAMEORIGIN` (or use CSP `frame-ancestors` exclusively).\n- Ensure `X-Content-Type-Options: nosniff` is present (currently OK)."},{"priority":2,"title":"Implement Responsive Images (srcset)","impact":"Mobile Data Usage, LCP, CLS","problem":"16/16 raster images lack `srcset`, forcing mobile devices to download desktop-sized assets (55 MB total media).","solution":"- Generate multiple image sizes (e.g., 400w, 800w, 1200w) for all raster images.\n- Update HTML to use `<img srcset=\"...\" sizes=\"...\">` or `<picture>` elements.\n- Add explicit `width` and `height` attributes to prevent CLS."},{"priority":2,"title":"Fix HSTS and Accessibility violations","impact":"Transport Security, WCAG Compliance","problem":"HSTS max-age is too short (15552000s) and missing `includeSubDomains`. 5 axe violations including missing `lang` and `alt`.","solution":"- Update HSTS: `Strict-Transport-Security: max-age=31536000; includeSubDomains; preload`.\n- Add `lang=\"en\"` to `<html>`.\n- Add descriptive `alt` text to all content images (e.g., `Co-Liv.png`).\n- Ensure color contrast ratios meet 4.5:1 for text."},{"priority":2,"title":"Resolve W3C HTML Errors and Structure","impact":"SEO, Document Outline, Validation","problem":"18 W3C errors including obsolete `<font>` tags, missing `<h1>`, duplicate IDs, and charset placement issues.","solution":"- **Headings:** Add one `<h1>` at the top of the page content.\n- **Tags:** Replace `<font>` elements with CSS classes.\n- **IDs:** Ensure unique IDs (e.g., `what-are-the-prices-of-the-rooms-and-what-does-the-price-depend-on?`).\n- **Charset:** Move `<meta charset=\"UTF-8\">` within the first 1024 bytes."},{"priority":2,"title":"Optimize Image Delivery","impact":"Page Weight, CLS, Mobile Data","problem":"3 images lack `width`/`height` (causing CLS), 1 missing `alt`, and no `srcset` for responsive loading.","solution":"- **Dimensions:** Add explicit `width` and `height` attributes to all `<img>` tags.\n- **Responsive:** Add `srcset` with WebP/AVIF variants for all raster images.\n- **Alt:** Ensure all content images have descriptive `alt` text; decorative images use `alt=\"\"`."},{"priority":2,"title":"Add Responsive Images (srcset)","impact":"Page Weight, LCP, CLS","problem":"3/3 raster images lack `srcset`, preventing browsers from loading optimally sized variants.","solution":"- Generate multiple image sizes (e.g., 400w, 800w, 1200w).\n- Add `srcset` and `sizes` attributes to `<img>` tags.\n- Use `<picture>` for art direction if needed."},{"priority":2,"title":"Implement responsive images and dimensions","impact":"CLS, Mobile Data Usage, LCP","problem":"16/16 raster images lack `srcset` and explicit `width`/`height`, preventing browser optimization and risking layout shifts.","solution":"- Add `width` and `height` attributes to all `<img>` tags.\n- Generate `srcset` variants (e.g., 400w, 800w, 1200w) for all raster images.\n- Wrap hero images in `<picture>` elements for format switching."},{"priority":2,"title":"Fix SEO metadata and HTML structure","impact":"Search Visibility, Crawlability","problem":"Missing `canonical` tag, `robots.txt`, and heading hierarchy skips (h2 → h4). W3C reports 12 errors including nested buttons inside anchors.","solution":"- Add `<link rel=\"canonical\" href=\"...\">`.\n- Ensure `robots.txt` exists at root.\n- Fix heading order (h2 → h3 → h4).\n- Remove `<button>` elements nested inside `<a>` tags; use `<a>` styled as buttons or JS event handlers."},{"priority":3,"title":"Resolve W3C HTML Validation Errors","impact":"SEO, Code Maintainability","problem":"11 errors found including `button` inside `a` (x5) and heading skips (h2→h4).","solution":"- Remove `button` elements nested inside `a` tags; use `a` with `role=\"button\"` or separate the link and button.\n- Fix heading hierarchy: Ensure `h3` follows `h2` without skipping levels.\n- Add `lang=\"en\"` to the `<html>` tag."},{"priority":3,"title":"Enable proper caching and SEO metadata","impact":"Repeat Visit Performance, Search Indexing","problem":"No `Cache-Control` header (unpredictable caching), missing canonical tag, and missing `robots` meta.","solution":"- Set `Cache-Control: public, max-age=31536000` for static assets.\n- Add `<link rel=\"canonical\" href=\"https://larsen.ee/about\">`.\n- Add `<meta name=\"robots\" content=\"index, follow\">`."},{"priority":3,"title":"Add Missing SEO Meta Tags","impact":"Search Visibility, CTR","problem":"Missing meta description, canonical URL, and robots meta tag.","solution":"- Add `<meta name=\"description\" content=\"...\">`.\n- Add `<link rel=\"canonical\" href=\"...\">`.\n- Add `<meta name=\"robots\" content=\"index, follow\">`."}],"coverage":{"pct":100,"missing":[]},"siteSummary":{"pagesAudited":5,"pagesAttempted":5,"urls":["https://larsen.ee/","https://larsen.ee/about","https://larsen.ee/faq","https://larsen.ee/terms-of-service","https://larsen.ee/et"]},"psiSnapshot":{"rows":[{"pageUrl":"https://larsen.ee/","perfMobile":48,"perfDesktop":43,"lcpMobileMs":47077.595889590884,"lcpDesktopMs":5317.006574748135,"clsMobile":0.138644,"clsDesktop":0.000343},{"pageUrl":"https://larsen.ee/about","perfMobile":47,"perfDesktop":51,"lcpMobileMs":36153.163444934835,"lcpDesktopMs":5266.076434925122,"clsMobile":0,"clsDesktop":0.000213},{"pageUrl":"https://larsen.ee/faq","perfMobile":49,"perfDesktop":52,"lcpMobileMs":4058.016117410052,"lcpDesktopMs":3070.04221088875,"clsMobile":0.6507339999999999,"clsDesktop":0.000213},{"pageUrl":"https://larsen.ee/terms-of-service","perfMobile":27,"perfDesktop":55,"lcpMobileMs":15993.546572397969,"lcpDesktopMs":2818.602503121908,"clsMobile":0,"clsDesktop":0.054572},{"pageUrl":"https://larsen.ee/et","perfMobile":53,"perfDesktop":44,"lcpMobileMs":10502.51804992189,"lcpDesktopMs":4882.0323209257585,"clsMobile":0.001323,"clsDesktop":0.000566}]},"optimizationChecklist":{"items":[{"id":"caching","title":"Page caching plugin / CDN active","status":"fail","detail":"No WordPress cache plugin marker or CDN edge cache detected on the document response.","evidence":[]},{"id":"lazyload","title":"Images lazy-loaded","status":"fail","detail":"5 of 7 non-hero raster images are not lazy-loaded (threshold: 2).","evidence":["https://larsen.ee/images/features/about_and_contact/2.jpg","https://larsen.ee/images/features/about_and_contact/3.jpg","https://larsen.ee/images/features/about_and_contact/4.jpg","https://larsen.ee/images/features/about_and_contact/5.jpg","https://larsen.ee/client/Co-Liv.e0807b70.png"]},{"id":"heroEager","title":"Hero image eagerly loaded","status":"fail","detail":"Hero image has loading=\"lazy\", which delays LCP (inferred from DOM order/size — Lighthouse LCP element unavailable). Use loading=\"eager\" (or omit loading) and add fetchpriority=\"high\".","evidence":["hero: …256x0/filters:quality(90)/https://larsen.ee/production/media/2024/07/karl.png","loading: lazy","fetchpriority: (not set)"]},{"id":"heroBackground","title":"Hero is a real <img> (not a CSS background-image)","status":"warn","detail":"Hero element uses a CSS background-image (no image-set() variants), so the browser always loads the original asset regardless of viewport — there is no srcset equivalent. Move the hero to a real <img> with srcset/sizes (or <picture>) so smaller viewports can fetch a smaller file.","evidence":["selector: div.buildings-map__map-overlay","url: https://larsen.ee/client/Tallinn.d777459c.png","box: 520×1021px"]},{"id":"responsive","title":"Responsive images (srcset / <picture>)","status":"fail","detail":"16/16 raster images lack srcset and are not inside <picture>.","evidence":["https://larsen.ee/images/uus-logota-larsen-video-2-thumbnail.jpg","…ers:quality(90)/https://larsen.ee/production/media/2023/11/maja-fasssad-2.jpg","…:quality(90)/https://larsen.ee/production/media/2025/03/rocca-house-drone.png","…filters:quality(90)/https://larsen.ee/production/media/2021/12/img-1042-1.jpg","…ality(90)/https://larsen.ee/production/media/2024/09/dji-0044-enhanced-nr.jpg"]},{"id":"imageSizes","title":"Reasonable number of image sizes","status":"fail","detail":"No raster images use srcset; browsers cannot pick an optimally sized variant.","evidence":[]},{"id":"scriptsFooter","title":"JS scripts not blocking in <head>","status":"pass","detail":"No render-blocking scripts in <head>.","evidence":[]}],"summary":{"passed":1,"warned":1,"failed":5,"notApplicable":0},"priorities":[{"title":"Page caching plugin / CDN active","severity":"high","detail":"No WordPress cache plugin marker or CDN edge cache detected on the document response."},{"title":"Responsive images (srcset / <picture>)","severity":"high","detail":"16/16 raster images lack srcset and are not inside <picture>."},{"title":"Reasonable number of image sizes","severity":"high","detail":"No raster images use srcset; browsers cannot pick an optimally sized variant."},{"title":"Images lazy-loaded","severity":"medium","detail":"3 of 15 non-hero raster images are not lazy-loaded."},{"title":"Hero image eagerly loaded","severity":"medium","detail":"Hero image has no explicit loading or fetchpriority (inferred from DOM order/size — Lighthouse LCP element unavailable). Browser default is eager but adding fetchpriority=\"high\" helps LCP."},{"title":"Hero is a real <img> (not a CSS background-image)","severity":"medium","detail":"Hero element uses a CSS background-image (no image-set() variants), so the browser always loads the original asset regardless of viewport — there is no srcset equivalent. Move the hero to a real <img> with srcset/sizes (or <picture>) so smaller viewports can fetch a smaller file."}]},"perPageOverall":[{"url":"https://larsen.ee/","overall":45,"reasoning":"Mobile performance is catastrophic (PSI 48, LCP 47.1s) due to 69 MB page weight and 1.37 MB unused JavaScript, dragging the score into the 'Poor' band. Accessibility is compromised by 2 critical axe violations (button-name, image-alt) and 11 W3C errors including heading skips. Security headers are weak (40/100) with missing HSTS and X-Frame-Options, though no auth/payments signals reduce immediate exploitation risk. Desktop performance (43) is similarly poor, indicating systemic architectural issues rather than just mobile throttling.","confidence":"high","fixes":[{"priority":1,"title":"Reduce JavaScript bundle and media weight to fix LCP","impact":"LCP (47.1s), FCP (3.6s), Total Page Weight (69 MB)","problem":"Mobile LCP is 47.1s with 1.37 MB unused JS (app-889782a39d4314ef1bf6.js) and 55 MB media weight causing massive load delays.","solution":"- Split the 1.37 MB `app-*.js` bundle using code splitting (React.lazy or dynamic imports).\n- Compress media: Convert 55 MB of images/video to WebP/AVIF and implement lazy loading.\n- Defer non-critical third-party scripts (Hotjar, PostHog) until user interaction."},{"priority":1,"title":"Fix critical accessibility violations","impact":"WCAG 2.1 Compliance, Screen Reader Usability","problem":"axe-core reports 2 critical violations: buttons lack discernible text (slider dots) and images lack alt attributes.","solution":"- Add `aria-label` to all slider dot buttons (e.g., `aria-label=\"Slide 1\"`).\n- Add descriptive `alt` text to all content images; use `alt=\"\"` for purely decorative icons.\n- Ensure all interactive elements have accessible names."},{"priority":2,"title":"Strengthen Security Headers (HSTS, X-Frame-Options)","impact":"Transport Security, Clickjacking Protection","problem":"HSTS max-age is too short (15552000s) and missing directives; X-Frame-Options is missing entirely.","solution":"- Update HSTS: `max-age=31536000; includeSubDomains; preload`.\n- Add `X-Frame-Options: SAMEORIGIN` (or use CSP `frame-ancestors` exclusively).\n- Ensure `X-Content-Type-Options: nosniff` is present (currently OK)."},{"priority":2,"title":"Implement Responsive Images (srcset)","impact":"Mobile Data Usage, LCP, CLS","problem":"16/16 raster images lack `srcset`, forcing mobile devices to download desktop-sized assets (55 MB total media).","solution":"- Generate multiple image sizes (e.g., 400w, 800w, 1200w) for all raster images.\n- Update HTML to use `<img srcset=\"...\" sizes=\"...\">` or `<picture>` elements.\n- Add explicit `width` and `height` attributes to prevent CLS."},{"priority":3,"title":"Resolve W3C HTML Validation Errors","impact":"SEO, Code Maintainability","problem":"11 errors found including `button` inside `a` (x5) and heading skips (h2→h4).","solution":"- Remove `button` elements nested inside `a` tags; use `a` with `role=\"button\"` or separate the link and button.\n- Fix heading hierarchy: Ensure `h3` follows `h2` without skipping levels.\n- Add `lang=\"en\"` to the `<html>` tag."}]},{"url":"https://larsen.ee/about","overall":52,"reasoning":"PSI mobile performance is critically low at 47, driven by a catastrophic LCP of 36.2 s and FCP of 11.3 s. The page weight is excessive at 4.60 MB, with images contributing 3.75 MB and 1.4 MB of unused JavaScript. Accessibility has 5 violations including 1 critical (image-alt) and 3 serious (contrast, lang, link-name). Security headers score 40/100 with weak HSTS and incomplete CSP, which is elevated to P1 due to the inferred user-generated content signal. Mobile performance is significantly worse than desktop (LCP 36.2 s vs 5.3 s), indicating a mobile-specific bottleneck.","confidence":"high","fixes":[{"priority":1,"title":"Reduce JavaScript bundle size and eliminate unused code","impact":"LCP, FCP, TBT, Performance Score","problem":"1.4 MB of unused JavaScript detected (app-889782a39d4314ef1bf6.js alone is 1397 KB wasted), contributing to LCP of 36.2 s.","solution":"- Implement code splitting to load only necessary JS for the About page.\n- Tree-shake dependencies and remove unused third-party scripts.\n- Defer non-critical scripts (e.g., analytics, hotjar) until after main content renders."},{"priority":1,"title":"Optimize and lazy-load images","impact":"Page Weight, LCP, CLS","problem":"Images total 3.75 MB with no srcset, 6 missing lazy loading, and 1 missing alt attribute. Hero image is a CSS background.","solution":"- Convert all images to WebP/AVIF with fallbacks.\n- Add `srcset` and `sizes` attributes for responsive loading.\n- Add `loading=\"lazy\"` to non-hero images.\n- Move hero CSS background to a real `<img>` tag with `fetchpriority=\"high\"`."},{"priority":1,"title":"Strengthen Content Security Policy (CSP)","impact":"XSS Defense, Security Score","problem":"CSP is weak (only frame-ancestors set). Site signals indicate user-generated content (reviews), elevating XSS risk to Priority 1 per rubric.","solution":"- Implement a strict CSP with `default-src` and `object-src 'none'`.\n- Use nonces or hashes for inline scripts rather than a permissive allowlist.\n- Example: `Content-Security-Policy: default-src 'self'; script-src 'nonce-{random}' 'strict-dynamic'; object-src 'none';`"},{"priority":2,"title":"Fix HSTS and Accessibility violations","impact":"Transport Security, WCAG Compliance","problem":"HSTS max-age is too short (15552000s) and missing `includeSubDomains`. 5 axe violations including missing `lang` and `alt`.","solution":"- Update HSTS: `Strict-Transport-Security: max-age=31536000; includeSubDomains; preload`.\n- Add `lang=\"en\"` to `<html>`.\n- Add descriptive `alt` text to all content images (e.g., `Co-Liv.png`).\n- Ensure color contrast ratios meet 4.5:1 for text."},{"priority":3,"title":"Enable proper caching and SEO metadata","impact":"Repeat Visit Performance, Search Indexing","problem":"No `Cache-Control` header (unpredictable caching), missing canonical tag, and missing `robots` meta.","solution":"- Set `Cache-Control: public, max-age=31536000` for static assets.\n- Add `<link rel=\"canonical\" href=\"https://larsen.ee/about\">`.\n- Add `<meta name=\"robots\" content=\"index, follow\">`."}]},{"url":"https://larsen.ee/faq","overall":52,"reasoning":"Mobile performance is critically low at 49 due to LCP of 4.1s and CLS of 0.651, driven by 1.4MB of unused JavaScript and layout shifts from cookies. Accessibility has 7 violations including a critical image-alt failure and serious contrast issues, despite an 80 score. Security headers are weak (40/100) with missing HSTS directives and a permissive CSP, which is high risk given the inferred user-generated content signal. HTML validation shows 18 errors including obsolete tags and missing language attributes. Confidence is high as all audit tools returned complete data.","confidence":"high","fixes":[{"priority":1,"title":"Fix Core Web Vitals (LCP, CLS) and Reduce JavaScript","impact":"Performance, LCP, CLS, TBT","problem":"Mobile Performance 49, LCP 4.1s (>4s penalty), CLS 0.651 (>0.25 penalty), and 1.4MB wasted JS (app-889782a39d4314ef1bf6.js).","solution":"- **LCP:** Remove `loading=\"lazy\"` from the hero image and add `fetchpriority=\"high\"`.\n- **CLS:** Reserve space for dynamic content (cookies, ads) using CSS `min-height` or aspect-ratio.\n- **JS:** Code-split the 1.4MB `app-889782a39d4314ef1bf6.js` and defer non-critical third-party scripts (Hotjar, PostHog)."},{"priority":1,"title":"Harden Security Headers (CSP & HSTS)","impact":"XSS protection, Transport security","problem":"Security Headers grade 40/100. HSTS max-age too short (15552000s) and missing `includeSubDomains`. CSP is weak (missing `default-src`). UGC signal present increases XSS risk.","solution":"- **HSTS:** `Strict-Transport-Security: max-age=31536000; includeSubDomains; preload`\n- **CSP:** Implement nonce-based CSP with `strict-dynamic`:\n  ```\n  Content-Security-Policy: default-src 'self'; script-src 'nonce-{random}' 'strict-dynamic'; object-src 'none'; base-uri 'none';\n  ```\n- **X-Frame-Options:** Add `X-Frame-Options: SAMEORIGIN` as fallback."},{"priority":1,"title":"Fix Critical Accessibility Violations","impact":"WCAG 2.1 Compliance, Screen Reader Support","problem":"1 Critical (image-alt) and 3 Serious (color-contrast, html-has-lang, link-name) axe violations. HTML lacks `lang` attribute.","solution":"- **Image Alt:** Add descriptive `alt` text to `img[src$=\"Co-Liv.e0807b70.png\"]`.\n- **Lang:** Add `lang=\"en\"` to `<html>` tag.\n- **Contrast:** Increase contrast ratio for `a[href$=\"faq\"] > h2` to ≥4.5:1.\n- **Links:** Add `aria-label` to icon links (Facebook, Instagram)."},{"priority":2,"title":"Resolve W3C HTML Errors and Structure","impact":"SEO, Document Outline, Validation","problem":"18 W3C errors including obsolete `<font>` tags, missing `<h1>`, duplicate IDs, and charset placement issues.","solution":"- **Headings:** Add one `<h1>` at the top of the page content.\n- **Tags:** Replace `<font>` elements with CSS classes.\n- **IDs:** Ensure unique IDs (e.g., `what-are-the-prices-of-the-rooms-and-what-does-the-price-depend-on?`).\n- **Charset:** Move `<meta charset=\"UTF-8\">` within the first 1024 bytes."},{"priority":2,"title":"Optimize Image Delivery","impact":"Page Weight, CLS, Mobile Data","problem":"3 images lack `width`/`height` (causing CLS), 1 missing `alt`, and no `srcset` for responsive loading.","solution":"- **Dimensions:** Add explicit `width` and `height` attributes to all `<img>` tags.\n- **Responsive:** Add `srcset` with WebP/AVIF variants for all raster images.\n- **Alt:** Ensure all content images have descriptive `alt` text; decorative images use `alt=\"\"`."}]},{"url":"https://larsen.ee/terms-of-service","overall":48,"reasoning":"Mobile performance 27 with LCP 16.0 s and TBT 6.09 s is catastrophic, dragging the score into the poor band. Accessibility fails include a critical image-alt violation plus missing lang and h1 tags. Security headers are weak (HSTS max-age too short, incomplete CSP) despite user-generated content signals. Image handling is poor with lazy-loaded hero images and no srcset. Desktop performance (55) is significantly better than mobile, highlighting mobile optimization gaps.","confidence":"high","fixes":[{"priority":1,"title":"Reduce JavaScript bundle and defer non-critical scripts","impact":"TBT, LCP, FCP, Performance Score","problem":"1.4 MB of unused JavaScript (GTM, PostHog, Facebook) causes 6.09 s TBT and 16.0 s LCP on mobile.","solution":"- Audit third-party scripts; remove unused tracking codes.\n- Load critical scripts inline or defer non-critical ones.\n- Use `module`/`nomodule` pattern for modern/legacy JS.\n- Implement code splitting to reduce initial bundle size."},{"priority":1,"title":"Fix Hero Image Loading Strategy","impact":"LCP, Performance Score","problem":"Hero image is lazy-loaded (`loading=\"lazy\"`), delaying LCP to 16.0 s on mobile.","solution":"- Remove `loading=\"lazy\"` from the hero image.\n- Add `fetchpriority=\"high\"` to the hero image.\n- Ensure hero image is preloaded if it's not the first resource."},{"priority":1,"title":"Implement Strict Content Security Policy (CSP)","impact":"XSS Protection, Security Score","problem":"CSP is missing `default-src` and `object-src`, leaving the site vulnerable to XSS (site has user-generated content).","solution":"- Deploy a nonce-based CSP rather than a flat allowlist.\n- Example: `Content-Security-Policy: default-src 'self'; script-src 'nonce-{random}' 'strict-dynamic'; object-src 'none';`\n- Ensure all inline scripts use the nonce."},{"priority":1,"title":"Fix Critical Accessibility Violations","impact":"WCAG Compliance, Accessibility Score","problem":"Critical `image-alt` violation, missing `lang` attribute, and missing `h1` heading.","solution":"- Add `lang=\"en\"` (or appropriate) to `<html>` tag.\n- Add descriptive `alt` text to all content images (e.g., `alt=\"Karl\"`).\n- Ensure exactly one `<h1>` exists per page (e.g., `<h1>Terms of Service</h1>`)."},{"priority":2,"title":"Strengthen Security Headers (HSTS, X-Frame-Options)","impact":"Transport Security, Clickjacking Protection","problem":"HSTS max-age is too short (15552000s) and missing `includeSubDomains`; X-Frame-Options is missing.","solution":"- Update HSTS: `Strict-Transport-Security: max-age=31536000; includeSubDomains; preload`\n- Add `X-Frame-Options: SAMEORIGIN` (or rely on CSP `frame-ancestors`)."},{"priority":2,"title":"Add Responsive Images (srcset)","impact":"Page Weight, LCP, CLS","problem":"3/3 raster images lack `srcset`, preventing browsers from loading optimally sized variants.","solution":"- Generate multiple image sizes (e.g., 400w, 800w, 1200w).\n- Add `srcset` and `sizes` attributes to `<img>` tags.\n- Use `<picture>` for art direction if needed."},{"priority":3,"title":"Add Missing SEO Meta Tags","impact":"Search Visibility, CTR","problem":"Missing meta description, canonical URL, and robots meta tag.","solution":"- Add `<meta name=\"description\" content=\"...\">`.\n- Add `<link rel=\"canonical\" href=\"...\">`.\n- Add `<meta name=\"robots\" content=\"index, follow\">`."}]},{"url":"https://larsen.ee/et","overall":52,"reasoning":"Mobile performance is critically poor (PSI 53, LCP 10.5 s, 69 MB page weight), dragging the score into the 'Poor' band despite acceptable desktop metrics. Accessibility has 2 critical violations (missing lang, alt text) and 3 serious issues, preventing a higher score. Security headers are weak (Grade 40/100) with incomplete HSTS and missing X-Frame-Options, compounded by a permissive CSP despite user-generated content signals. Image optimization is absent (no srcset, missing dimensions), contributing to the massive payload and potential layout shifts. Confidence is high as all audit tools returned complete data.","confidence":"high","fixes":[{"priority":1,"title":"Reduce page weight and optimize media delivery","impact":"LCP, Speed Index, Total Blocking Time","problem":"Total page weight is 69.19 MB (56 MB media); LCP is 10.5 s on mobile. Unused JavaScript alone is 1.37 MB.","solution":"- Compress and resize images; serve WebP/AVIF.\n- Implement lazy loading for below-fold media.\n- Remove or defer unused JavaScript (e.g., `app-889782a39d4314ef1bf6.js`).\n- Use a CDN with edge caching to reduce TTFB and transfer time."},{"priority":1,"title":"Fix critical accessibility violations","impact":"WCAG 2.1 A/AA compliance, Screen Reader usability","problem":"axe-core reports 2 critical violations: missing `lang` on `<html>` and missing `alt` on images. Buttons (slider dots) lack accessible names.","solution":"- Add `lang=\"et\"` to the `<html>` tag.\n- Provide descriptive `alt` text for all content images; use `alt=\"\"` for decorative ones.\n- Add `aria-label` or visible text to slider dot buttons (e.g., `aria-label=\"Slide 1\"`)."},{"priority":1,"title":"Harden security headers for UGC site","impact":"XSS, Clickjacking, Transport Security","problem":"Security grade is 40/100. HSTS max-age is short (15M s) and missing `includeSubDomains`. CSP lacks `default-src`. Site has user-generated content (reviews), increasing XSS risk.","solution":"- Update HSTS: `max-age=31536000; includeSubDomains; preload`.\n- Add `X-Frame-Options: SAMEORIGIN`.\n- Implement strict CSP with nonce/hash: `Content-Security-Policy: default-src 'self'; script-src 'nonce-{random}' 'strict-dynamic'; object-src 'none';`"},{"priority":2,"title":"Implement responsive images and dimensions","impact":"CLS, Mobile Data Usage, LCP","problem":"16/16 raster images lack `srcset` and explicit `width`/`height`, preventing browser optimization and risking layout shifts.","solution":"- Add `width` and `height` attributes to all `<img>` tags.\n- Generate `srcset` variants (e.g., 400w, 800w, 1200w) for all raster images.\n- Wrap hero images in `<picture>` elements for format switching."},{"priority":2,"title":"Fix SEO metadata and HTML structure","impact":"Search Visibility, Crawlability","problem":"Missing `canonical` tag, `robots.txt`, and heading hierarchy skips (h2 → h4). W3C reports 12 errors including nested buttons inside anchors.","solution":"- Add `<link rel=\"canonical\" href=\"...\">`.\n- Ensure `robots.txt` exists at root.\n- Fix heading order (h2 → h3 → h4).\n- Remove `<button>` elements nested inside `<a>` tags; use `<a>` styled as buttons or JS event handlers."}]}]}