# Audit Report: Larsen - The Coolest Accommodation in Tallinn **URL:** https://larsen.ee/ **Date:** 2026-06-10 **Audit Coverage:** 100% โ€” all sources returned data **Pages Audited:** 5 of 5 discovered - https://larsen.ee/ - https://larsen.ee/about - https://larsen.ee/faq - https://larsen.ee/terms-of-service - https://larsen.ee/et **Overall Score:** 47 / 100 **Overall Status:** ๐ŸŸ  **Poor** **Confidence:** high ## Summary Site overall 47 is the mean of 5 pages. Scores range 42 (https://larsen.ee/) โ†’ 52 (https://larsen.ee/terms-of-service). Weakest page: Mobile PSI performance is critically low at 35 with an 18.9 s LCP, despite decent field data, indicating severe lab bottlenecks. The 69 MB total page weight (55 MB media) is unsustainable for mobile users and directly drives the TBT and LCP failures. Accessibility is blocked by 2 critical axe violations and 11 W3C errors including buttons inside anchors. Security headers are weak (HSTS/CSP) though no auth/payments exist, and image optimization is missing entirely (no srcset). ## Per-Page Scores | Page | Score | Status | Confidence | | --- | --- | --- | --- | | https://larsen.ee/ | 42 | ๐ŸŸ  **Poor** | high | | https://larsen.ee/about | 52 | ๐ŸŸ  **Poor** | high | | https://larsen.ee/faq | 45 | ๐ŸŸ  **Poor** | high | | https://larsen.ee/terms-of-service | 52 | ๐ŸŸ  **Poor** | high | | https://larsen.ee/et | 45 | ๐ŸŸ  **Poor** | high | ## PageSpeed Insights โ€” Mobile vs Desktop _Lower is worse for Performance; higher is worse for LCP and CLS. Worse value is **bolded**._ | URL | Performance (M / D) | LCP (M / D) | CLS (M / D) | | --- | --- | --- | --- | | https://larsen.ee/ | **35** / 54 | **18.90 s** / 4.71 s | **0.003** / 0.000 | | https://larsen.ee/about | **53** / 54 | **6.93 s** / 3.92 s | **0.137** / 0.000 | | https://larsen.ee/faq | **42** / 51 | **20.62 s** / 3.13 s | 0.000 / **0.000** | | https://larsen.ee/terms-of-service | 60 / **57** | **4.20 s** / 2.76 s | 0.001 / **0.063** | | https://larsen.ee/et | **43** / 55 | **18.91 s** / 4.71 s | **0.001** / 0.001 | ## Optimization Checklist **1 of 7 pass** โ€” 1 pass ยท 1 warn ยท 5 fail | Item | Status | Detail | | --- | --- | --- | | Page caching plugin / CDN active | โœ— fail | No WordPress cache plugin marker or CDN edge cache detected on the document response. | | Images lazy-loaded | โœ— fail | 5 of 7 non-hero raster images are not lazy-loaded (threshold: 2). | | Hero image eagerly loaded | โœ— fail | 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". | | Hero is a real (not a CSS background-image) | ! warn | 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 with srcset/sizes (or ) so smaller viewports can fetch a smaller file. | | Responsive images (srcset / ) | โœ— fail | 16/16 raster images lack srcset and are not inside . | | Reasonable number of image sizes | โœ— fail | No raster images use srcset; browsers cannot pick an optimally sized variant. | | JS scripts not blocking in | โœ“ pass | No render-blocking scripts in . | ## Fixes ### Priority 1: Critical *Immediate action โ€” impacts user experience, search rankings, or site safety.* **1A. Reduce page weight from 69 MB to under 5 MB** - **Impact:** LCP, TBT, Mobile Performance - **Problem:** Total page weight is 69 MB with 55 MB media and 1.3 MB unused JS (app-8897...), causing 18.9 s LCP and 1.03 s TBT on mobile. - **Solution:** - Remove unused JavaScript bundles (1.3 MB). - Compress and resize media assets (55 MB) to WebP/AVIF. - Implement lazy loading for off-screen media. - Use a CDN with edge caching to reduce TTFB. **1B. Fix critical accessibility violations** - **Impact:** WCAG Compliance, SEO - **Problem:** axe-core reports 2 critical violations: `button-name` (slider dots) and `image-alt` (Co-Liv image). W3C reports 5 errors of `button` inside `a`. - **Solution:** - Add `aria-label` to slider dot buttons. - Add descriptive `alt` text to the Co-Liv image. - Refactor HTML to remove `button` elements nested inside `a` tags (use `button` alone or `a` alone). **1C. Optimize images to reduce page weight and LCP** - **Impact:** LCP, Page Weight, CLS - **Problem:** Images consume 3.75 MB (82% of 4.6 MB total weight); LCP is 6.9 s on mobile. 8 images lack srcset/width/height, and 5 are not lazy-loaded. - **Solution:** 1. Convert all raster images to WebP/AVIF. 2. Add `srcset` and `sizes` attributes for responsive loading. 3. Add `width` and `height` attributes to prevent CLS. 4. Add `loading="lazy"` to non-hero images. 5. Use `fetchpriority="high"` on the LCP hero image. **1D. Strengthen Security Headers (CSP & HSTS)** - **Impact:** XSS Defense, Transport Security - **Problem:** Security grade is 40/100. HSTS max-age is too short (15552000s) and missing `includeSubDomains`. CSP only sets `frame-ancestors` (missing `default-src`). Site signals indicate User-Generated Content is present, elevating XSS risk. - **Solution:** 1. Update HSTS: `max-age=31536000; includeSubDomains; preload`. 2. Implement strict CSP with nonce/hash: `Content-Security-Policy: default-src 'self'; script-src 'nonce-{random}' 'strict-dynamic'; object-src 'none'; base-uri 'none';`. 3. Add `X-Frame-Options: SAMEORIGIN` as fallback. **1E. Fix Core Web Vitals (LCP/FCP) and Reduce JavaScript** - **Impact:** Performance, LCP, FCP, TBT - **Problem:** Mobile LCP is 20.6 s and FCP is 10.65 s; 1.4 MB of unused JavaScript identified (e.g., app-889782a39d4314ef1bf6.js). - **Solution:** 1. **Defer/Remove Unused JS:** Audit and remove the 1.4 MB `app-*.js` bundle or split it. Use `defer` for non-critical scripts. 2. **Fix Hero Image:** Ensure the LCP image (likely the hero) uses `loading="eager"` (or omit) and `fetchpriority="high"`. 3. **Preload Critical Resources:** Add `` for the hero image and critical CSS. **1F. Resolve Critical Accessibility Violations** - **Impact:** WCAG 2.1, Screen Reader Usability - **Problem:** axe-core reports 1 critical (`image-alt`) and 3 serious violations (`html-has-lang`, `color-contrast`, `link-name`). - **Solution:** 1. **Add `lang` attribute:** ``. 2. **Fix Image Alt:** Add descriptive `alt` text to all content images (e.g., `Co-Liv.png`). 3. **Fix Contrast:** Ensure text/background contrast ratio โ‰ฅ 4.5:1. 4. **Label Links:** Add `aria-label` to icon links (e.g., Facebook, Instagram) that lack visible text. **1G. Reduce JavaScript bundle size and eliminate unused code** - **Impact:** LCP, TBT, FCP, Performance Score - **Problem:** 1398 KB wasted JavaScript (app-889782a39d4314ef1bf6.js) contributes to 756 ms TBT and 4.2 s LCP on mobile. - **Solution:** - Implement code splitting to load only necessary JS for the Terms page. - Tree-shake unused dependencies. - Defer non-critical third-party scripts (GTM, PostHog) until after interaction. **1H. Fix critical accessibility violations and document structure** - **Impact:** WCAG 2.1 A/AA Compliance, Screen Reader Usability - **Problem:** 1 critical `image-alt` violation, 2 serious violations (`html-has-lang`, `link-name`), and missing `

` heading. - **Solution:** - Add `lang="en"` to `` tag. - Add descriptive `alt` text to all images (e.g., `alt="Larsen Hotel Logo"`). - Add a single `

` element describing the page (e.g., `

Terms of Service

`). - Ensure all links have discernible text or `aria-label`. **1I. Strengthen Security Headers (HSTS and CSP)** - **Impact:** Transport Security, XSS Defense - **Problem:** HSTS max-age is too short (15552000s) and missing directives; CSP lacks `default-src` despite UGC signals. - **Solution:** - Update HSTS: `max-age=31536000; includeSubDomains; preload`. - Implement strict CSP with nonce/hash: `default-src 'self'; script-src 'nonce-{random}' 'strict-dynamic'; object-src 'none';`. - Add `X-Frame-Options: SAMEORIGIN` as fallback. **1J. Reduce page weight and fix LCP** - **Impact:** Performance, LCP, FCP, TBT - **Problem:** Mobile Performance is 43/100; LCP is 18.9s; total page weight is 69MB (56MB media, 12MB images). - **Solution:** - Compress and resize media assets (videos/images) aggressively. - Implement lazy loading for below-fold content. - Remove unused JavaScript (1.37MB wasted in `app-889782a39d4314ef1bf6.js`). - Enable HTTP/2 or HTTP/3 server push for critical resources. **1K. Strengthen Content Security Policy (CSP)** - **Impact:** XSS protection, Data integrity - **Problem:** CSP is present but weak (only `frame-ancestors` set); site has user-generated content (reviews), elevating XSS risk per the rubric. - **Solution:** - Implement a strict CSP with `default-src 'self'`. - Use nonces or hashes for inline scripts. - Add `object-src 'none'` and `base-uri 'none'`. - Example: `Content-Security-Policy: default-src 'self'; script-src 'nonce-{random}' 'strict-dynamic'; object-src 'none';` ### Priority 2: Important *Essential for compliance, user reach, and search visibility.* **2A. Strengthen security headers (HSTS, CSP)** - **Impact:** Transport security, XSS defense - **Problem:** HSTS max-age is too short (15552000s) and missing directives; CSP lacks `default-src`. UGC signal is present but no auth/payments. - **Solution:** ``` Strict-Transport-Security: max-age=31536000; includeSubDomains; preload Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{random}' 'strict-dynamic'; ``` **2B. Implement responsive images (srcset)** - **Impact:** Page weight, CLS, Mobile Performance - **Problem:** 16/16 raster images lack `srcset` and `width/height` attributes, preventing browser optimization and risking layout shifts. - **Solution:** - Generate multiple image sizes (e.g., 400w, 800w, 1200w). - Add `srcset` and `sizes` attributes to `` tags. - Add explicit `width` and `height` to reserve space. **2C. Reduce JavaScript Bundle Size and Unused Code** - **Impact:** TBT, FCP, TTI - **Problem:** 1397 KB of unused JavaScript detected in `app-889782a39d4314ef1bf6.js`. Multiple third-party scripts (GTM, GA, PostHog) contribute to long tasks (179 ms, 114 ms). - **Solution:** 1. Code-split the main bundle to defer non-critical JS. 2. Audit third-party scripts; remove unused tracking pixels (e.g., duplicate GTM/GA instances). 3. Load non-critical scripts with `defer` or `async`. 4. Implement resource hints (`preconnect`) for critical third-party origins. **2D. Implement Proper Caching Policy** - **Impact:** Repeat Visit Performance, TTFB - **Problem:** Security Headers report shows `cache-control: not set`. Caching behavior is unpredictable, forcing re-downloads on repeat visits. - **Solution:** 1. Set `Cache-Control: public, max-age=31536000, immutable` for static assets (images, CSS, JS). 2. Set `Cache-Control: no-cache, must-revalidate` for HTML documents to ensure freshness. 3. Ensure Vary header is set correctly for content negotiation. **2E. Fix W3C HTML Validation Errors** - **Impact:** SEO, Rendering Consistency - **Problem:** 18 W3C errors including obsolete `` tags, duplicate IDs, and `