Audit

20260720T095133Z-c941

← Back to kodudembachee
Audited URL
https://kodud.embach.ee/
Timestamp
2026-07-20T09:56:40.505Z
Kind
site
Pages
5
Audit summary
https://kodud.embach.ee/
5 of 5 pages audited
Pagespeed scores
Other checks
LLM Report

Weighted audit summary

74
Overall site quality
Needs Improvementhigh confidence

Site overall 74 is the mean of 5 pages. Scores range 72 (https://kodud.embach.ee/hello-world) → 78 (https://kodud.embach.ee/sample-page). Weakest page: Mobile performance (77) is dragged down by LCP 3.7 s and CLS 0.208, while desktop is excellent (99). Security headers are completely absent (0/100), which is critical given the inferred user-generated content signal. Accessibility is strong (94) but fails on the missing H1 heading structure. SEO metadata is missing (description, structured data). Confidence is high due to complete data coverage.

Per-page scores
74
Home
high
72
/hello-world
high
78
/sample-page
high
72
/koik-arendused
high
72
/kontakt
high

Audit Report: Kodud

Website: https://kodud.embach.ee/
Date: 2026-07-20

Overall Score: 74 / 100
Status: 🟡 Needs Improvement
Confidence: high
Audit Coverage: 100% — all sources returned data

Pages Audited (5 of 5):

Summary

Site overall 74 is the mean of 5 pages. Scores range 72 (https://kodud.embach.ee/hello-world) → 78 (https://kodud.embach.ee/sample-page). Weakest page: Mobile performance (77) is dragged down by LCP 3.7 s and CLS 0.208, while desktop is excellent (99). Security headers are completely absent (0/100), which is critical given the inferred user-generated content signal. Accessibility is strong (94) but fails on the missing H1 heading structure. SEO metadata is missing (description, structured data). Confidence is high due to complete data coverage.

Per-Page Scores

Page Score Status Confidence
https://kodud.embach.ee/ 74 🟡 Needs Improvement high
https://kodud.embach.ee/hello-world 72 🟡 Needs Improvement high
https://kodud.embach.ee/sample-page 78 🟡 Needs Improvement high
https://kodud.embach.ee/koik-arendused 72 🟡 Needs Improvement high
https://kodud.embach.ee/kontakt 72 🟡 Needs Improvement 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://kodud.embach.ee/ 76 / 77 3.35 s / 1.01 s 0.287 / 0.571
https://kodud.embach.ee/hello-world 77 / 99 3.74 s / 858 ms 0.208 / 0.007
https://kodud.embach.ee/sample-page 82 / 99 3.71 s / 926 ms 0.000 / 0.007
https://kodud.embach.ee/koik-arendused 76 / 97 5.18 s / 1.21 s 0.000 / 0.000
https://kodud.embach.ee/kontakt 82 / 99 4.50 s / 915 ms 0.000 / 0.000

Optimization Checklist

1 of 3 passing — 1 pass · 1 warn · 1 fail · 4 n/a

Item Status Detail
Page caching plugin / CDN active Pass Caching plugin detected (WP Rocket)
Images lazy-loaded N/A No raster <img> elements found.
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 <img> (not a CSS background-image) N/A No CSS background-images detected on raster-image-eligible elements.
Responsive images (srcset / <picture>) N/A Only 0 raster images on the page — responsive-image rule does not apply.
Reasonable number of image sizes N/A Too few raster images to evaluate srcset width variety.
JS scripts not blocking in <head> Warn 2 render-blocking scripts in <head>. Move to footer or add defer/async.

Fixes

Priority 1: Critical

Immediate action — impacts user experience, search rankings, or site safety.

1A. Fix Cumulative Layout Shift (CLS) on Carousel

  • Impact: Core Web Vitals, User Experience
  • Problem: CLS is 0.287 (mobile) and 0.571 (desktop), exceeding the 0.25 threshold. The shift source is identified as 'div.projects-carousel__slider'.
  • Solution: Reserve space for the carousel container using min-height or aspect-ratio in CSS to prevent layout shifts during image loading.
    .projects-carousel__slider {
      min-height: 400px; /* Adjust to actual content height */
      aspect-ratio: 16 / 9;
    }
    

1B. Implement Missing Security Headers

  • Impact: Security, Transport Integrity
  • Problem: Security Headers grade is 0/100. HSTS, X-Frame-Options, X-Content-Type-Options, and CSP are all missing. UGC signal is 'yes', elevating CSP to Priority 1.
  • Solution: Add the following headers to the server response (Apache example):
    Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set Content-Security-Policy "default-src 'self'; script-src 'nonce-{random}' 'strict-dynamic';"
    

1C. Optimize Largest Contentful Paint (LCP)

  • Impact: Performance, LCP Metric
  • Problem: LCP is 3.3 s on mobile, exceeding the 2.5 s good threshold. 6 render-blocking scripts and 109 KB unused JS contribute to delay.
  • Solution:
    1. Defer non-critical scripts (add defer or async to 6 render-blocking scripts).
    2. Preload the hero image resource.
    3. Remove or tree-shake the 109 KB unused JavaScript (global.04cbabbf7670bc75.js).
    <link rel="preload" as="image" href="/path/to/hero.jpg">
    <script src="..." defer></script>
    

1D. Add a single H1 heading to the page

  • Impact: SEO, Accessibility (WCAG 1.3.1)
  • Problem: HTML Inventory reports 0 H1 elements; axe-core flags 'page-has-heading-one' as a moderate violation.
  • Solution: Ensure the main title of the post/page is wrapped in a single <h1> tag.
    <h1>Hello world!</h1>
    

1E. Implement baseline security headers (HSTS, CSP, X-Frame-Options)

  • Impact: Transport security, XSS defense, Clickjacking
  • Problem: Security Headers grade is 0/100; HSTS and CSP are missing despite UGC signal (yes) increasing XSS risk.
  • Solution: Add to server config (Apache example):
    Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set X-Content-Type-Options "nosniff"
    Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'nonce-{random}' 'strict-dynamic';"
    

1F. Implement Critical Security Headers (HSTS, CSP)

  • Impact: Security, XSS protection, Clickjacking
  • Problem: Security Headers grade is 0/100; HSTS and CSP are missing. Site signals indicate user-generated content (UGC), elevating XSS risk.
  • Solution: Add the following headers to your server configuration (e.g., Apache .htaccess or Nginx):
    Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'nonce-{random}' 'strict-dynamic'; object-src 'none'; base-uri 'none';"
    
    Ensure CSP uses nonces/hashes for scripts rather than a permissive allowlist.

1G. Fix Hero Image Loading for LCP

  • Impact: LCP, FCP, Performance Score
  • Problem: LCP is 5.2 s on mobile; checklist confirms hero image has loading='lazy' which delays rendering.
  • Solution: Remove loading="lazy" from the hero image and add fetchpriority="high":
    <img src="hero.jpg" alt="..." fetchpriority="high" width="..." height="...">
    

1H. Implement HSTS and CSP Headers

  • Impact: Security Headers Grade, XSS/Clickjacking Defense
  • Problem: Security grade is 0/100; HSTS and CSP are missing. UGC signal is 'yes', raising CSP priority per rubric.
  • Solution: Add HSTS and a strict CSP (nonce-based) to server config:
    Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
    Header always set Content-Security-Policy "default-src 'self'; script-src 'nonce-{random}' 'strict-dynamic';"
    

1I. Implement Baseline Security Headers

  • Impact: Security, Transport Integrity
  • Problem: Security Headers grade is 0/100; HSTS, X-Frame-Options, and X-Content-Type-Options are missing.
  • Solution: Add these headers via server config (Apache example):
    Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains"
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set X-Content-Type-Options "nosniff"
    

1J. Add Content-Security-Policy (CSP)

  • Impact: XSS Defense
  • Problem: CSP is missing and Site Signals infer User-Generated Content (anchor href contains "post"), elevating XSS risk.
  • Solution: Deploy a strict CSP with nonces rather than a flat allowlist:
    Header always set Content-Security-Policy "default-src 'self'; script-src 'nonce-{random}' 'strict-dynamic';"
    

Priority 2: Important

Essential for compliance, user reach, and search visibility.

2A. Add Meta Description and Structured Data

  • Impact: SEO, Search Visibility
  • Problem: PSI SEO audit fails on metaDescription and structuredData. HTML inventory confirms no meta description or JSON-LD present.
  • Solution: Add a unique meta description (150-160 chars) and relevant JSON-LD (e.g., RealEstateAgent or LocalBusiness).
    <meta name="description" content="Embach kodud: kaasaegne kinnisvaraarendus Tartu piiril.">
    <script type="application/ld+json">
    {
      "@context": "https://schema.org",
      "@type": "RealEstateAgent",
      "name": "Embach"
    }
    </script>
    

2B. Reduce Cumulative Layout Shift (CLS) caused by footer

  • Impact: Core Web Vitals (CLS), User Experience
  • Problem: CLS is 0.208 (warning zone); PSI identifies footer div as the primary shift source (0.197).
  • Solution: Reserve space for dynamic footer content or ensure footer elements have explicit dimensions.
    footer.footer {
      min-height: 200px; /* Reserve space */
    }
    

2C. Defer non-critical render-blocking scripts

  • Impact: LCP, FCP, Performance Score
  • Problem: 6 render-blocking scripts detected; 117 KB unused JS identified in global.js.
  • Solution: Add defer or async to script tags in <head> unless they are critical for initial render.
    <script src="..." defer></script>
    

2D. Defer Render-Blocking Scripts

  • Impact: LCP, FCP, Performance Score
  • Problem: 6 render-blocking scripts identified in PSI and HTML Inventory; LCP is 3.7 s and FCP is 3.23 s on mobile.
  • Solution: Move non-critical scripts to the footer or add defer/async attributes. For WordPress, use a plugin like WP Rocket (already detected) to delay JS execution or minify/combine scripts.
    <!-- Change from -->
    <script src="..."></script>
    <!-- To -->
    <script src="..." defer></script>
    

2E. Remove Unused JavaScript

  • Impact: Page Weight, TBT, Performance Score
  • Problem: 117 KB of unused JavaScript detected in global.04cbabbf7670bc75.js.
  • Solution: Audit global.js and core.js for unused functions. Use code splitting or tree-shaking in your build process. If using WordPress, disable unused theme/plugin scripts via a performance plugin.

2F. Add H1 Heading Element

  • Impact: Accessibility (Axe), SEO (W3C)
  • Problem: W3C warns no H1; Axe reports 'page-has-heading-one' violation. Page uses H2s for main titles.
  • Solution: Ensure the primary page title is wrapped in <h1>:
    <h1>Kõik arendused</h1>
    

2G. Add Meta Description

  • Impact: SEO (PSI Score 0)
  • Problem: PSI SEO audit fails 'metaDescription'; HTML inventory confirms description is not set.
  • Solution: Add a unique description tag in <head>:
    <meta name="description" content="Vaadake kõiki meie arendusi ja koduvalikuid Eestis.">
    

2H. Fix Accessibility Violations

  • Impact: WCAG 2.4.4, 2.5.8
  • Problem: PSI flags button-name and target-size with 0.00 scores; touch targets are too small and buttons lack accessible names.
  • Solution:
    • Ensure all buttons have visible text or aria-label.
    • Increase touch target padding to at least 44×44 px per WCAG 2.5.8.

2I. Defer Render-Blocking JavaScript

  • Impact: FCP, TBT, Performance
  • Problem: 6 render-blocking scripts detected; 117 KB unused JS contributes to long tasks.
  • Solution: Add defer or async to non-critical scripts in <head>:
    <script src="/js/core.js" defer></script>
    

Priority 3: Best Practice

Recommended for long-term maintainability.

3A. Ensure Lazy Loading on All Below-Fold Images

  • Impact: Page Weight, Load Time
  • Problem: HTML inventory shows 1 image missing loading="lazy" despite being below the fold. Total page weight is 795.5 KB.
  • Solution: Audit all images below the fold and add loading="lazy" attribute. Ensure hero images remain eager or fetchpriority="high".
    <img src="image.jpg" loading="lazy" alt="Description" width="300" height="200">
    

3B. Add meta description and structured data

  • Impact: SEO (Search Appearance)
  • Problem: PSI SEO audit fails on metaDescription and structuredData; HTML Inventory confirms 0 Open Graph/Twitter tags.
  • Solution: Add meta description and JSON-LD schema to the <head>:
    <meta name="description" content="Brief summary of the page content for search engines.">
    <script type="application/ld+json">
    {
      "@context": "https://schema.org",
      "@type": "BlogPosting",
      "headline": "Hello world!"
    }
    </script>
    

3C. Verify Button Accessibility Names

  • Impact: Accessibility, WCAG 2.4.4
  • Problem: PSI reports button-name failure (score 0.00) despite axe-core showing 0 violations; manual check needed.
  • Solution: Inspect all <button> and icon links. Ensure they have visible text or aria-label attributes.
    <button aria-label="Close modal">&times;</button>
    

3D. Add Meta Description and Open Graph Tags

  • Impact: SEO, Social Sharing
  • Problem: SEO audit fails metaDescription; no Open Graph or Twitter tags present.
  • Solution: Add to <head>:
    <meta name="description" content="Contact details for real estate services.">
    <meta property="og:title" content="Kontakt">
    <meta property="og:image" content="/path/to/og-image.jpg">
    

3E. Fix W3C HTML Validation Errors

  • Impact: Maintainability, Rendering Consistency
  • Problem: 2 errors found: srcset missing width specification and stray </p> end tag.
  • Solution:
    • Update srcset to include width descriptors (e.g., image.jpg 400w).
    • Remove the extra </p> tag at line 538.
▸Raw Markdown sent to the LLM
# Site Audit — https://kodud.embach.ee/
Run: 2026-07-20T09:51:33.797Z

Audited **5** of 5 discovered pages.
Average per-page audit coverage: **100%**

Pages audited:
- https://kodud.embach.ee/
- https://kodud.embach.ee/hello-world
- https://kodud.embach.ee/sample-page
- https://kodud.embach.ee/koik-arendused
- https://kodud.embach.ee/kontakt

---

# Page 1 of 5 — https://kodud.embach.ee/

Run: 2026-07-20T09:51:34.944Z

## Audit Coverage
**100%** of audit sources returned data.

_All sources OK._

## Methodology

Each tool below contributes data to a single overall 0–100 site quality score. Performance dominates the weighting (~40%), followed by accessibility (~30%), image assets (~15%), and SEO/security (~15%). These weights are informative — the score is judged holistically, not from a fixed formula.

Severity scale in `priorities[]`:
- **high** — blocking issue / vulnerability / fail.
- **medium** — significant degradation.
- **low** — minor improvement.

Each tool section below lists: scores → priority fixes → findings → manual checks the tool cannot verify.

## Site Signals (inferred)

Heuristic site-shape signals derived from the audit data. Use these to calibrate the priority of security-header recommendations (see system rubric). Override when the evidence is clearly wrong.

- Auth surface: no
- Payments: no
- User-generated content: **yes** — anchor href contains "post"
- E-commerce: no

## PageSpeed Insights
_Captured in 14048 ms (mobile + desktop in parallel)._

**Lighthouse scores (mobile vs desktop; worse value bolded):**
| Category | Mobile | Desktop |
| --- | --- | --- |
| Performance | **76** | 77 |
| Accessibility | **95** | 96 |
| Best Practices | 100 | 100 |
| SEO | 92 | 92 |

**Core Web Vitals — lab (Lighthouse) / field (CrUX p75); worse lab value bolded:**
| Metric | Mobile | Desktop |
| --- | --- | --- |
| LCP | **3.3 s** | 1.0 s |
| CLS | 0.287 | **0.571** |
| TBT | **21 ms** | 0 ms |
| FCP | **1.82 s** | 496 ms |
| Speed Index | **1.85 s** | 715 ms |
| TTFB | 2 ms | **4 ms** |

### Priority fixes
1. **cumulative-layout-shift** (high) — 0.287
2. **largest-contentful-paint** (medium) — 3.3 s
3. **first-contentful-paint** (low) — 1.8 s
4. **cls-culprits-insight** (high)
5. **font-display-insight** (high) — Est savings of 60 ms

### Findings (mobile)

#### Unused JavaScript
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/global.04cbabbf7670bc75.js — 109 KB wasted

#### Layout-shift sources
- div#section-1779103439914-0 > div.section__container > div.section__container-inner > div.projects-carousel__slider — shift 0.287

#### Long tasks
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/global.04cbabbf7670bc75.js — 92 ms

#### DOM size
- Total nodes: 0

#### Failing modeled audits
- SEO: `metaDescription`
- SEO: `tapTargets`
- SEO: `structuredData`

#### All failing PSI audits (sorted by weight × failure margin)
- `cumulative-layout-shift` (performance, score 0.42, weight 25) — Cumulative Layout Shift — 0.287
- `button-name` (accessibility, score 0.00, weight 10) — Buttons do not have an accessible name
- `largest-contentful-paint` (performance, score 0.68, weight 25) — Largest Contentful Paint — 3.3 s
- `first-contentful-paint` (performance, score 0.89, weight 10) — First Contentful Paint — 1.8 s
- `cls-culprits-insight` (performance, score 0.00, weight 0) — Layout shift culprits
- `network-dependency-tree-insight` (performance, score 0.00, weight 0) — Network dependency tree
- `meta-description` (seo, score 0.00, weight 1) — Document does not have a meta description
- `interactive` (performance, score 0.86, weight 0) — Time to Interactive — 4.2 s

### Manual checks
- Real-device behavior on slow 3G / low-tier mobile hardware (Lighthouse is throttled simulation).
- Sustained INP under typical user interaction, not just initial load.
- CrUX data interpretation if site is low-traffic and field data falls back to origin or is missing.

## Security Headers & HTTP
_Captured in 22 ms._

**Transport:**
- Final URL: https://kodud.embach.ee/
- Status: 200
- Redirected: false
- HTTPS redirect: HTTP → HTTPS ✓

**Caching:**
- cache-control: `max-age=0`
- etag: n/a
- last-modified: Mon, 20 Jul 2026 07:40:15 GMT
- expires: Mon, 20 Jul 2026 09:51:34 GMT
- pragma: n/a
- vary: Accept-Encoding

**Compression:**
- content-encoding: gzip
- content-length: 18594
- Decoded body: 95.9 KB
- Compression ratio: 0.189

### Priority fixes
1. **strict-transport-security missing** (high) — Add HSTS with max-age >= 1 year, includeSubDomains, and preload
2. **content-security-policy missing** (high) — Add a CSP with default-src and script-src restrictions
3. **x-frame-options missing** (medium) — Prefer CSP frame-ancestors; X-Frame-Options as fallback
4. **x-content-type-options missing** (medium) — Send X-Content-Type-Options: nosniff
5. **referrer-policy missing** (low) — Set a Referrer-Policy such as strict-origin-when-cross-origin
6. **permissions-policy missing** (low) — Declare Permissions-Policy to disable unused features
7. **cross-origin-opener-policy missing** (low) — Set COOP to same-origin to isolate browsing context
8. **cross-origin-resource-policy missing** (low) — Set CORP to same-origin or same-site to prevent cross-origin reads
9. **x-permitted-cross-domain-policies missing** (low) — Set to none to prevent Flash/PDF cross-domain requests
10. **server header discloses technology** (low) — Server: Apache / ZoneOS

### Findings

#### Tracked headers
- **strict-transport-security** (missing, high)
- **content-security-policy** (missing, high)
- **x-frame-options** (missing, medium)
- **x-content-type-options** (missing, medium)
- **referrer-policy** (missing, low)
- **permissions-policy** (missing, low)
- **cross-origin-opener-policy** (missing, low)
- **cross-origin-resource-policy** (missing, low)
- **x-permitted-cross-domain-policies** (missing, low)

#### Info disclosure
- Server: `Apache / ZoneOS`


#### All response headers
```
cache-control: max-age=0
connection: Keep-Alive
content-encoding: gzip
content-length: 18594
content-type: text/html; charset=UTF-8
date: Mon, 20 Jul 2026 09:51:34 GMT
expires: Mon, 20 Jul 2026 09:51:34 GMT
keep-alive: timeout=5, max=95
last-modified: Mon, 20 Jul 2026 07:40:15 GMT
server: Apache / ZoneOS
vary: Accept-Encoding
```

### Manual checks
- Cookie attributes set via JavaScript (not visible in HTTP response).
- CORS preflight behavior under non-GET methods (only GET response headers checked).
- HSTS preload list inclusion (check hstspreload.org).
- WAF / DDoS posture beyond what static headers reveal.

## W3C HTML Validator
_Captured in 747 ms._

**Scoring:** 0 errors · 1 warnings · 16 cosmetic (suppressed)

### Issue groups
- (×1) [warning] The “type” attribute is unnecessary for JavaScript resources. — first at line 1291 `/noscript><script nowprocket type="text/javascript">var el`

### Manual checks
- Whether each `<section>` / `<article>` wraps semantically meaningful content.
- Language tag accuracy for multi-language pages or quoted content.
- Whether structural choices align with the document outline algorithm in screen readers.

## axe-core (Accessibility)
_Captured in 1648 ms._

**Scoring:** 0 violations · 38 passes · critical 0 · serious 0 · moderate 0 · minor 0

### Incomplete (axe could not determine)
- [Elements must meet minimum color contrast ratio thresholds](https://dequeuniversity.com/rules/axe/4.11/color-contrast?application=playwright) — 8 nodes

### Manual checks
- Keyboard-only navigation flow + visible focus indicators on every interactive element.
- Screen reader output (NVDA, VoiceOver) for actual auditory experience.
- Modal focus trapping and restoration on close.
- Touch target sizes (44×44 px minimum per WCAG 2.5.8).
- Color contrast for elements with alpha-transparency or gradients (axe skips these).

## Browser Runtime
_Captured in 1656 ms._

**Capture summary:** 0 console events · 0 mixed-content requests · 25 network requests · 795.5 KB total

**Network bytes by resource type:**
| Type | Count | Bytes |
| --- | --- | --- |
| image | 6 | 645.2 KB |
| script | 7 | 53.6 KB |
| stylesheet | 5 | 36.9 KB |
| font | 2 | 27.6 KB |
| document | 1 | 18.2 KB |
| xhr | 3 | 7.7 KB |
| other | 1 | 6.4 KB |

**Third-party origins (by bytes):**
- https://cdn.jsdelivr.net — 6 requests, 28.6 KB
- https://fonts.googleapis.com — 2 requests, 0 B

**Slowest requests (top 5):**
- https://kodud.embach.ee/ (document) — 170 ms, 18.2 KB
- https://fonts.googleapis.com/css?family=Open%20Sans%3A400%2C400i%2C600%2C700%2C700i&subset=cyrillic&display=swap (xhr) — 154 ms, 0 B
- https://fonts.googleapis.com/css?family=Open%20Sans%3A400%2C400i%2C600%2C700%2C700i&subset=cyrillic&display=swap (stylesheet) — 142 ms, 0 B
- https://kodud.embach.ee/wp-content/plugins/sitepress-multilingual-cms/res/js/cookies/language-cookie.js (script) — 51 ms, 187 B
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/global.04cbabbf7670bc75.js (script) — 51 ms, 0 B

### Manual checks
- Console output during user interaction (load-only capture).
- Behavior on slow networks and constrained devices.
- WebGL / canvas FPS profiling via DevTools Layers panel.
- Service worker / cache behavior on repeat visits.

## HTML Inventory
_Captured in 1656 ms._

**Document:**
- Lang: et
- Title: Kodud
- Canonical: https://kodud.embach.ee/
- Viewport: width=device-width, initial-scale=1
- Charset: UTF-8
- HTML bytes: 95863

**Meta tags:**
- Description: not set
- Robots: max-image-preview:large
- Theme color: #ffffff
- Open Graph tags: 0 (none)
- Twitter tags: 0
- hreflang:
  - et → https://kodud.embach.ee/
  - x-default → https://kodud.embach.ee/
- JSON-LD: none

**Heading outline:**
- Counts: h1 ×1, h2 ×3, h3 ×0, h4 ×0, h5 ×0, h6 ×0
- Sequence (first 20):
  - h1: Embach kodud
  - h2: Pärnasalu - kaasaegne, roheline ja kasvava väärtusega kodu Tartu piiril.
  - h2: Kinnisvaraarendus numbrites
  - h2: Idee on hea, aga oskustest jääb puudu?

**Landmarks:**
- nav: present
- main: present
- header: present
- footer: present
- Skip-to-content link: present

**Scripts:** 16 total — 1 defer, 0 async, 6 render-blocking. Speculation rules: yes.

External scripts (first 15):
- https://cdn.jsdelivr.net/gh/orestbida/iframemanager@1.3.0/dist/iframemanager.js
- https://cdn.jsdelivr.net/gh/orestbida/cookieconsent@3.0.1/dist/cookieconsent.umd.js
- https://kodud.embach.ee/wp-content/plugins/sitepress-multilingual-cms/res/js/cookies/language-cookie.js (defer)
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/jquery.d34d86e241c9422e.js
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/core.f01dd0977277031a.js
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/global.04cbabbf7670bc75.js
- https://kodud.embach.ee/wp-includes/js/jquery/jquery-migrate.min.js

**Stylesheets:** 5 external, 3 inline (9.4 KB)

**Images:** 20 total — **0 without alt**, **0 without width/height**, 1 without loading="lazy"

Image inventory (first 15):
| src | alt | w×h | loading | srcset |
| --- | --- | --- | --- | --- |
| /uploads/sites/3/2026/07/elutuba2-pakett-1-beige-320x180.jpg | _(empty)_ | 320×180 | eager | ✓ |
| tes/3/2026/05/vannituba1-pakett-2-grey-scaled-1-300x200.webp | _(empty)_ | 300×200 | lazy | ✓ |
| es/3/2026/05/magamistuba-pakett-2-grey-scaled-1-300x200.webp | _(empty)_ | 300×200 | lazy | ✓ |
| sites/3/2026/05/elutuba2-pakett-2-grey-scaled-1-300x200.webp | _(empty)_ | 300×200 | lazy | ✓ |
| sites/3/2026/05/elutuba1-pakett-2-grey-scaled-1-300x200.webp | _(empty)_ | 300×200 | lazy | ✓ |
| es/3/2026/05/vannituba1-pakett-1-beige-scaled-1-300x200.webp | _(empty)_ | 300×200 | lazy | ✓ |
| s/3/2026/05/magamistuba-pakett-1-beige-scaled-1-300x200.webp | _(empty)_ | 300×200 | lazy | ✓ |
| ites/3/2026/05/elutuba2-pakett-1-beige-scaled-1-300x200.webp | _(empty)_ | 300×200 | lazy | ✓ |
| ites/3/2026/05/elutuba1-pakett-1-beige-scaled-1-300x200.webp | _(empty)_ | 300×200 | lazy | ✓ |
| ch.ee/wp-content/uploads/sites/3/2026/05/maja-3-300x200.webp | _(empty)_ | 300×200 | lazy | ✓ |
| ch.ee/wp-content/uploads/sites/3/2026/05/maja-2-300x200.webp | _(empty)_ | 300×200 | lazy | ✓ |
| ch.ee/wp-content/uploads/sites/3/2026/05/maja-1-300x200.webp | _(empty)_ | 300×200 | lazy | ✓ |
| sites/3/2026/05/parna_kesk_rgb_0050001-scaled-1-300x200.webp | _(empty)_ | 300×200 | lazy | ✓ |
| sites/3/2026/05/parna_kesk_rgb_0040001-scaled-1-300x200.webp | _(empty)_ | 300×200 | lazy | ✓ |
| sites/3/2026/05/parna_kesk_rgb_0030001-scaled-1-300x200.webp | _(empty)_ | 300×200 | lazy | ✓ |

**Links:** 24 anchors — 9 external, 1 preconnect, 2 preload.

Vague repeated link text:
- "kõik arendused" ×2
- "kontakt" ×2

### Priority fixes
1. **6 render-blocking external scripts** (medium) — Only 1 defer, 0 async; add defer/async to non-critical scripts

### Manual checks
- Visual rendering of detected mojibake (browser may auto-correct for display).
- Whether decorative images correctly use empty `alt=""` (vs. content images missing it).
- Whether headings reflect actual document hierarchy semantically.
- Whether vague link text is disambiguated by `aria-label` or surrounding context.

## Optimized-Web Checklist
_Captured in 0 ms._

**Summary:** 5 pass · 1 warn · 0 fail · 1 n/a

**Checklist:**
| Item | Status | Detail |
| --- | --- | --- |
| Page caching plugin / CDN active | ✓ pass | Caching plugin detected (WP Rocket) |
| Images lazy-loaded | ✓ pass | All non-hero raster images use loading="lazy". |
| Hero image eagerly loaded | ✓ pass | Hero image is eagerly loaded with fetchpriority="high" (inferred from DOM order/size — Lighthouse LCP element unavailable). |
| Hero is a real <img> (not a CSS background-image) | – n/a | No CSS background-images detected on raster-image-eligible elements. |
| Responsive images (srcset / <picture>) | ✓ pass | 20/20 raster images use srcset or <picture> (100%). |
| Reasonable number of image sizes | ✓ pass | 7 distinct srcset widths. |
| JS scripts not blocking in <head> | ! warn | 2 render-blocking scripts in <head>. Move to footer or add defer/async. |

**Evidence:**
- Page caching plugin / CDN active:
  - `HTML markers: WP Rocket`
  - `generator: WP Rocket 3.23`
- Hero image eagerly loaded:
  - `hero: …ach.ee/wp-content/uploads/sites/3/2026/07/elutuba2-pakett-1-beige-320x180.jpg`
  - `loading: eager`
  - `fetchpriority: high`
- Reasonable number of image sizes:
  - `widths: 300, 320, 600, 640, 1200, 1600, 3200`
- JS scripts not blocking in <head>:
  - `https://cdn.jsdelivr.net/gh/orestbida/iframemanager@1.3.0/dist/iframemanager.js`
  - `…//cdn.jsdelivr.net/gh/orestbida/cookieconsent@3.0.1/dist/cookieconsent.umd.js`

### Priority fixes
1. **JS scripts not blocking in <head>** (medium) — 2 render-blocking scripts in <head>. Move to footer or add defer/async.

### Manual checks
- Cart / checkout / logged-in pages must bypass the page cache or load dynamic regions via AJAX.
- Verify the cache is warmed for the canonical URL on initial deploy (first visitor should not pay the cold-start cost).
- Inspect "hero" image visually — heuristic above picks the first/largest <img>, which may not match the actual LCP element on JS-heavy pages.
- Confirm scripts marked as defer/async actually tolerate deferred execution (some legacy snippets break when reordered).

---

# Page 2 of 5 — https://kodud.embach.ee/hello-world

Run: 2026-07-20T09:51:34.946Z

## Audit Coverage
**100%** of audit sources returned data.

_All sources OK._

## Methodology

Each tool below contributes data to a single overall 0–100 site quality score. Performance dominates the weighting (~40%), followed by accessibility (~30%), image assets (~15%), and SEO/security (~15%). These weights are informative — the score is judged holistically, not from a fixed formula.

Severity scale in `priorities[]`:
- **high** — blocking issue / vulnerability / fail.
- **medium** — significant degradation.
- **low** — minor improvement.

Each tool section below lists: scores → priority fixes → findings → manual checks the tool cannot verify.

## Site Signals (inferred)

Heuristic site-shape signals derived from the audit data. Use these to calibrate the priority of security-header recommendations (see system rubric). Override when the evidence is clearly wrong.

- Auth surface: no
- Payments: no
- User-generated content: **yes** — anchor href contains "post"
- E-commerce: no

## PageSpeed Insights
_Captured in 11771 ms (mobile + desktop in parallel)._

**Lighthouse scores (mobile vs desktop; worse value bolded):**
| Category | Mobile | Desktop |
| --- | --- | --- |
| Performance | **77** | 99 |
| Accessibility | **94** | 96 |
| Best Practices | 100 | 100 |
| SEO | 92 | 92 |

**Core Web Vitals — lab (Lighthouse) / field (CrUX p75); worse lab value bolded:**
| Metric | Mobile | Desktop |
| --- | --- | --- |
| LCP | **3.7 s** | 0.9 s |
| CLS | **0.208** | 0.007 |
| TBT | **49 ms** | 0 ms |
| FCP | **2.14 s** | 632 ms |
| Speed Index | **2.28 s** | 633 ms |
| TTFB | 3 ms | 3 ms |

### Priority fixes
1. **largest-contentful-paint** (medium) — 3.7 s
2. **cumulative-layout-shift** (medium) — 0.208
3. **first-contentful-paint** (low) — 2.1 s
4. **cls-culprits-insight** (high)
5. **document-latency-insight** (high) — Est savings of 260 ms

### Findings (mobile)

#### Unused JavaScript
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/global.04cbabbf7670bc75.js — 117 KB wasted

#### Layout-shift sources
- div#page > div.main > div.main__footer > footer.footer — shift 0.197
- div#page > div.main > div.main__footer > footer.footer — shift 0.011

#### Long tasks
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/core.f01dd0977277031a.js — 99 ms

#### DOM size
- Total nodes: 0

#### Failing modeled audits
- SEO: `metaDescription`
- SEO: `tapTargets`
- SEO: `structuredData`

#### All failing PSI audits (sorted by weight × failure margin)
- `largest-contentful-paint` (performance, score 0.57, weight 25) — Largest Contentful Paint — 3.7 s
- `cumulative-layout-shift` (performance, score 0.60, weight 25) — Cumulative Layout Shift — 0.208
- `button-name` (accessibility, score 0.00, weight 10) — Buttons do not have an accessible name
- `first-contentful-paint` (performance, score 0.80, weight 10) — First Contentful Paint — 2.1 s
- `cls-culprits-insight` (performance, score 0.00, weight 0) — Layout shift culprits
- `network-dependency-tree-insight` (performance, score 0.00, weight 0) — Network dependency tree
- `meta-description` (seo, score 0.00, weight 1) — Document does not have a meta description

### Manual checks
- Real-device behavior on slow 3G / low-tier mobile hardware (Lighthouse is throttled simulation).
- Sustained INP under typical user interaction, not just initial load.
- CrUX data interpretation if site is low-traffic and field data falls back to origin or is missing.

## Security Headers & HTTP
_Captured in 990 ms._

**Transport:**
- Final URL: https://kodud.embach.ee/hello-world/
- Status: 200
- Redirected: false
- HTTPS redirect: HTTP → HTTPS ✓

**Caching:**
- cache-control: `max-age=0`
- etag: n/a
- last-modified: Mon, 20 Jul 2026 09:51:35 GMT
- expires: Mon, 20 Jul 2026 09:51:35 GMT
- pragma: n/a
- vary: Accept-Encoding

**Compression:**
- content-encoding: gzip
- content-length: 13887
- Decoded body: 62.5 KB
- Compression ratio: 0.217

### Priority fixes
1. **strict-transport-security missing** (high) — Add HSTS with max-age >= 1 year, includeSubDomains, and preload
2. **content-security-policy missing** (high) — Add a CSP with default-src and script-src restrictions
3. **x-frame-options missing** (medium) — Prefer CSP frame-ancestors; X-Frame-Options as fallback
4. **x-content-type-options missing** (medium) — Send X-Content-Type-Options: nosniff
5. **referrer-policy missing** (low) — Set a Referrer-Policy such as strict-origin-when-cross-origin
6. **permissions-policy missing** (low) — Declare Permissions-Policy to disable unused features
7. **cross-origin-opener-policy missing** (low) — Set COOP to same-origin to isolate browsing context
8. **cross-origin-resource-policy missing** (low) — Set CORP to same-origin or same-site to prevent cross-origin reads
9. **x-permitted-cross-domain-policies missing** (low) — Set to none to prevent Flash/PDF cross-domain requests
10. **server header discloses technology** (low) — Server: Apache / ZoneOS

### Findings

#### Tracked headers
- **strict-transport-security** (missing, high)
- **content-security-policy** (missing, high)
- **x-frame-options** (missing, medium)
- **x-content-type-options** (missing, medium)
- **referrer-policy** (missing, low)
- **permissions-policy** (missing, low)
- **cross-origin-opener-policy** (missing, low)
- **cross-origin-resource-policy** (missing, low)
- **x-permitted-cross-domain-policies** (missing, low)

#### Info disclosure
- Server: `Apache / ZoneOS`


#### All response headers
```
cache-control: max-age=0
connection: Keep-Alive
content-encoding: gzip
content-length: 13887
content-type: text/html; charset=UTF-8
date: Mon, 20 Jul 2026 09:51:35 GMT
expires: Mon, 20 Jul 2026 09:51:35 GMT
keep-alive: timeout=5, max=94
last-modified: Mon, 20 Jul 2026 09:51:35 GMT
server: Apache / ZoneOS
vary: Accept-Encoding
```

### Manual checks
- Cookie attributes set via JavaScript (not visible in HTTP response).
- CORS preflight behavior under non-GET methods (only GET response headers checked).
- HSTS preload list inclusion (check hstspreload.org).
- WAF / DDoS posture beyond what static headers reveal.

## W3C HTML Validator
_Captured in 1834 ms._

**Scoring:** 0 errors · 1 warnings · 16 cosmetic (suppressed)

### Issue groups
- (×1) [warning] The “type” attribute is unnecessary for JavaScript resources. — first at line 441 `/noscript><script nowprocket type="text/javascript">var el`

### Manual checks
- Whether each `<section>` / `<article>` wraps semantically meaningful content.
- Language tag accuracy for multi-language pages or quoted content.
- Whether structural choices align with the document outline algorithm in screen readers.

## axe-core (Accessibility)
_Captured in 1739 ms._

**Scoring:** 1 violations · 27 passes · critical 0 · serious 0 · moderate 1 · minor 0

### Priority fixes
1. **page-has-heading-one** (medium) — Page should contain a level-one heading

### Findings

#### `page-has-heading-one` (moderate)
[Page should contain a level-one heading](https://dequeuniversity.com/rules/axe/4.11/page-has-heading-one?application=playwright)
- `html`

### Incomplete (axe could not determine)
- [Elements must meet minimum color contrast ratio thresholds](https://dequeuniversity.com/rules/axe/4.11/color-contrast?application=playwright) — 1 node

### Manual checks
- Keyboard-only navigation flow + visible focus indicators on every interactive element.
- Screen reader output (NVDA, VoiceOver) for actual auditory experience.
- Modal focus trapping and restoration on close.
- Touch target sizes (44×44 px minimum per WCAG 2.5.8).
- Color contrast for elements with alpha-transparency or gradients (axe skips these).

## Browser Runtime
_Captured in 1744 ms._

**Capture summary:** 0 console events · 0 mixed-content requests · 21 network requests · 153.6 KB total

**Network bytes by resource type:**
| Type | Count | Bytes |
| --- | --- | --- |
| script | 8 | 61.6 KB |
| stylesheet | 5 | 36.9 KB |
| font | 2 | 27.6 KB |
| document | 2 | 13.5 KB |
| xhr | 3 | 7.7 KB |
| other | 1 | 6.4 KB |

**Third-party origins (by bytes):**
- https://cdn.jsdelivr.net — 6 requests, 28.6 KB
- https://fonts.googleapis.com — 2 requests, 0 B

**Slowest requests (top 5):**
- https://kodud.embach.ee/hello-world/ (document) — 255 ms, 13.5 KB
- https://kodud.embach.ee/hello-world (document) — 196 ms, 0 B
- https://fonts.googleapis.com/css?family=Open%20Sans%3A400%2C400i%2C600%2C700%2C700i&subset=cyrillic&display=swap (stylesheet) — 139 ms, 0 B
- https://fonts.googleapis.com/css?family=Open%20Sans%3A400%2C400i%2C600%2C700%2C700i&subset=cyrillic&display=swap (xhr) — 96 ms, 0 B
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/global.04cbabbf7670bc75.js (script) — 44 ms, 0 B

### Manual checks
- Console output during user interaction (load-only capture).
- Behavior on slow networks and constrained devices.
- WebGL / canvas FPS profiling via DevTools Layers panel.
- Service worker / cache behavior on repeat visits.

## HTML Inventory
_Captured in 1744 ms._

**Document:**
- Lang: et
- Title: Hello world! – Kodud
- Canonical: https://kodud.embach.ee/hello-world/
- Viewport: width=device-width, initial-scale=1
- Charset: UTF-8
- HTML bytes: 63584

**Meta tags:**
- Description: not set
- Robots: max-image-preview:large
- Theme color: #ffffff
- Open Graph tags: 0 (none)
- Twitter tags: 0
- hreflang:
  - et → https://kodud.embach.ee/hello-world/
  - x-default → https://kodud.embach.ee/hello-world/
- JSON-LD: none

**Heading outline:**
- Counts: h1 ×0, h2 ×0, h3 ×0, h4 ×0, h5 ×0, h6 ×0

**Landmarks:**
- nav: present
- main: present
- header: present
- footer: present
- Skip-to-content link: present

**Scripts:** 18 total — 1 defer, 1 async, 6 render-blocking. Speculation rules: yes.

External scripts (first 15):
- https://cdn.jsdelivr.net/gh/orestbida/iframemanager@1.3.0/dist/iframemanager.js
- https://cdn.jsdelivr.net/gh/orestbida/cookieconsent@3.0.1/dist/cookieconsent.umd.js
- https://kodud.embach.ee/wp-content/plugins/sitepress-multilingual-cms/res/js/cookies/language-cookie.js (defer)
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/jquery.d34d86e241c9422e.js
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/core.f01dd0977277031a.js
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/global.04cbabbf7670bc75.js
- https://kodud.embach.ee/wp-includes/js/jquery/jquery-migrate.min.js
- https://kodud.embach.ee/wp-content/plugins/wp-rocket/assets/js/wpr-beacon.min.js (async)

**Stylesheets:** 5 external, 3 inline (9.4 KB)

**Images:** 0 total — **0 without alt**, **0 without width/height**, 0 without loading="lazy"

**Links:** 22 anchors — 8 external, 1 preconnect, 1 preload.

Vague repeated link text:
- "kõik arendused" ×2
- "kontakt" ×2

### Priority fixes
1. **Document has 0 <h1> elements** (high) — A page should have exactly one h1; multiple h1s break document outline
2. **6 render-blocking external scripts** (medium) — Only 1 defer, 1 async; add defer/async to non-critical scripts

### Manual checks
- Visual rendering of detected mojibake (browser may auto-correct for display).
- Whether decorative images correctly use empty `alt=""` (vs. content images missing it).
- Whether headings reflect actual document hierarchy semantically.
- Whether vague link text is disambiguated by `aria-label` or surrounding context.

## Optimized-Web Checklist
_Captured in 0 ms._

**Summary:** 1 pass · 1 warn · 0 fail · 5 n/a

**Checklist:**
| Item | Status | Detail |
| --- | --- | --- |
| Page caching plugin / CDN active | ✓ pass | Caching plugin detected (WP Rocket) |
| Images lazy-loaded | – n/a | No raster <img> elements found. |
| Hero image eagerly loaded | – n/a | No raster <img> elements found. |
| Hero is a real <img> (not a CSS background-image) | – n/a | No CSS background-images detected on raster-image-eligible elements. |
| Responsive images (srcset / <picture>) | – n/a | Only 0 raster images on the page — responsive-image rule does not apply. |
| Reasonable number of image sizes | – n/a | Too few raster images to evaluate srcset width variety. |
| JS scripts not blocking in <head> | ! warn | 2 render-blocking scripts in <head>. Move to footer or add defer/async. |

**Evidence:**
- Page caching plugin / CDN active:
  - `HTML markers: WP Rocket`
  - `generator: WP Rocket 3.23`
- JS scripts not blocking in <head>:
  - `https://cdn.jsdelivr.net/gh/orestbida/iframemanager@1.3.0/dist/iframemanager.js`
  - `…//cdn.jsdelivr.net/gh/orestbida/cookieconsent@3.0.1/dist/cookieconsent.umd.js`

### Priority fixes
1. **JS scripts not blocking in <head>** (medium) — 2 render-blocking scripts in <head>. Move to footer or add defer/async.

### Manual checks
- Cart / checkout / logged-in pages must bypass the page cache or load dynamic regions via AJAX.
- Verify the cache is warmed for the canonical URL on initial deploy (first visitor should not pay the cold-start cost).
- Inspect "hero" image visually — heuristic above picks the first/largest <img>, which may not match the actual LCP element on JS-heavy pages.
- Confirm scripts marked as defer/async actually tolerate deferred execution (some legacy snippets break when reordered).

---

# Page 3 of 5 — https://kodud.embach.ee/sample-page

Run: 2026-07-20T09:51:56.658Z

## Audit Coverage
**100%** of audit sources returned data.

_All sources OK._

## Methodology

Each tool below contributes data to a single overall 0–100 site quality score. Performance dominates the weighting (~40%), followed by accessibility (~30%), image assets (~15%), and SEO/security (~15%). These weights are informative — the score is judged holistically, not from a fixed formula.

Severity scale in `priorities[]`:
- **high** — blocking issue / vulnerability / fail.
- **medium** — significant degradation.
- **low** — minor improvement.

Each tool section below lists: scores → priority fixes → findings → manual checks the tool cannot verify.

## Site Signals (inferred)

Heuristic site-shape signals derived from the audit data. Use these to calibrate the priority of security-header recommendations (see system rubric). Override when the evidence is clearly wrong.

- Auth surface: no
- Payments: no
- User-generated content: **yes** — anchor href contains "post"
- E-commerce: no

## PageSpeed Insights
_Captured in 18098 ms (mobile + desktop in parallel)._

**Lighthouse scores (mobile vs desktop; worse value bolded):**
| Category | Mobile | Desktop |
| --- | --- | --- |
| Performance | **82** | 99 |
| Accessibility | **94** | 96 |
| Best Practices | 100 | 100 |
| SEO | 92 | 92 |

**Core Web Vitals — lab (Lighthouse) / field (CrUX p75); worse lab value bolded:**
| Metric | Mobile | Desktop |
| --- | --- | --- |
| LCP | **3.7 s** | 0.9 s |
| CLS | 0.000 | **0.007** |
| TBT | **101 ms** | 42 ms |
| FCP | **3.23 s** | 579 ms |
| Speed Index | **3.23 s** | 711 ms |
| TTFB | 2 ms | 2 ms |

### Priority fixes
1. **largest-contentful-paint** (medium) — 3.7 s
2. **first-contentful-paint** (high) — 3.2 s
3. **document-latency-insight** (high) — Est savings of 250 ms
4. **font-display-insight** (high) — Est savings of 50 ms
5. **legacy-javascript-insight** (medium) — Est savings of 13 KiB

### Findings (mobile)

#### Unused JavaScript
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/global.04cbabbf7670bc75.js — 117 KB wasted

#### Long tasks
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/core.f01dd0977277031a.js — 151 ms
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/jquery.d34d86e241c9422e.js — 69 ms

#### DOM size
- Total nodes: 0

#### Failing modeled audits
- SEO: `metaDescription`
- SEO: `tapTargets`
- SEO: `structuredData`

#### All failing PSI audits (sorted by weight × failure margin)
- `largest-contentful-paint` (performance, score 0.58, weight 25) — Largest Contentful Paint — 3.7 s
- `button-name` (accessibility, score 0.00, weight 10) — Buttons do not have an accessible name
- `first-contentful-paint` (performance, score 0.42, weight 10) — First Contentful Paint — 3.2 s
- `network-dependency-tree-insight` (performance, score 0.00, weight 0) — Network dependency tree
- `meta-description` (seo, score 0.00, weight 1) — Document does not have a meta description
- `max-potential-fid` (performance, score 0.83, weight 0) — Max Potential First Input Delay — 150 ms

### Manual checks
- Real-device behavior on slow 3G / low-tier mobile hardware (Lighthouse is throttled simulation).
- Sustained INP under typical user interaction, not just initial load.
- CrUX data interpretation if site is low-traffic and field data falls back to origin or is missing.

## Security Headers & HTTP
_Captured in 222 ms._

**Transport:**
- Final URL: https://kodud.embach.ee/sample-page/
- Status: 200
- Redirected: false
- HTTPS redirect: HTTP → HTTPS ✓

**Caching:**
- cache-control: `max-age=0`
- etag: n/a
- last-modified: Mon, 20 Jul 2026 07:35:05 GMT
- expires: Mon, 20 Jul 2026 09:51:56 GMT
- pragma: n/a
- vary: Accept-Encoding

**Compression:**
- content-encoding: gzip
- content-length: 13944
- Decoded body: 63.0 KB
- Compression ratio: 0.216

### Priority fixes
1. **strict-transport-security missing** (high) — Add HSTS with max-age >= 1 year, includeSubDomains, and preload
2. **content-security-policy missing** (high) — Add a CSP with default-src and script-src restrictions
3. **x-frame-options missing** (medium) — Prefer CSP frame-ancestors; X-Frame-Options as fallback
4. **x-content-type-options missing** (medium) — Send X-Content-Type-Options: nosniff
5. **referrer-policy missing** (low) — Set a Referrer-Policy such as strict-origin-when-cross-origin
6. **permissions-policy missing** (low) — Declare Permissions-Policy to disable unused features
7. **cross-origin-opener-policy missing** (low) — Set COOP to same-origin to isolate browsing context
8. **cross-origin-resource-policy missing** (low) — Set CORP to same-origin or same-site to prevent cross-origin reads
9. **x-permitted-cross-domain-policies missing** (low) — Set to none to prevent Flash/PDF cross-domain requests
10. **server header discloses technology** (low) — Server: Apache / ZoneOS

### Findings

#### Tracked headers
- **strict-transport-security** (missing, high)
- **content-security-policy** (missing, high)
- **x-frame-options** (missing, medium)
- **x-content-type-options** (missing, medium)
- **referrer-policy** (missing, low)
- **permissions-policy** (missing, low)
- **cross-origin-opener-policy** (missing, low)
- **cross-origin-resource-policy** (missing, low)
- **x-permitted-cross-domain-policies** (missing, low)

#### Info disclosure
- Server: `Apache / ZoneOS`


#### All response headers
```
cache-control: max-age=0
connection: Upgrade, Keep-Alive
content-encoding: gzip
content-length: 13944
content-type: text/html; charset=UTF-8
date: Mon, 20 Jul 2026 09:51:56 GMT
expires: Mon, 20 Jul 2026 09:51:56 GMT
keep-alive: timeout=5, max=100
last-modified: Mon, 20 Jul 2026 07:35:05 GMT
server: Apache / ZoneOS
vary: Accept-Encoding
```

### Manual checks
- Cookie attributes set via JavaScript (not visible in HTTP response).
- CORS preflight behavior under non-GET methods (only GET response headers checked).
- HSTS preload list inclusion (check hstspreload.org).
- WAF / DDoS posture beyond what static headers reveal.

## W3C HTML Validator
_Captured in 964 ms._

**Scoring:** 0 errors · 1 warnings · 16 cosmetic (suppressed)

### Issue groups
- (×1) [warning] The “type” attribute is unnecessary for JavaScript resources. — first at line 459 `/noscript><script nowprocket type="text/javascript">var el`

### Manual checks
- Whether each `<section>` / `<article>` wraps semantically meaningful content.
- Language tag accuracy for multi-language pages or quoted content.
- Whether structural choices align with the document outline algorithm in screen readers.

## axe-core (Accessibility)
_Captured in 1480 ms._

**Scoring:** 0 violations · 30 passes · critical 0 · serious 0 · moderate 0 · minor 0

### Incomplete (axe could not determine)
- [Elements must meet minimum color contrast ratio thresholds](https://dequeuniversity.com/rules/axe/4.11/color-contrast?application=playwright) — 1 node

### Manual checks
- Keyboard-only navigation flow + visible focus indicators on every interactive element.
- Screen reader output (NVDA, VoiceOver) for actual auditory experience.
- Modal focus trapping and restoration on close.
- Touch target sizes (44×44 px minimum per WCAG 2.5.8).
- Color contrast for elements with alpha-transparency or gradients (axe skips these).

## Browser Runtime
_Captured in 1486 ms._

**Capture summary:** 0 console events · 0 mixed-content requests · 21 network requests · 153.7 KB total

**Network bytes by resource type:**
| Type | Count | Bytes |
| --- | --- | --- |
| script | 8 | 61.6 KB |
| stylesheet | 5 | 36.9 KB |
| font | 2 | 27.6 KB |
| document | 2 | 13.6 KB |
| xhr | 3 | 7.7 KB |
| other | 1 | 6.4 KB |

**Third-party origins (by bytes):**
- https://cdn.jsdelivr.net — 6 requests, 28.6 KB
- https://fonts.googleapis.com — 2 requests, 0 B

**Slowest requests (top 5):**
- https://kodud.embach.ee/sample-page (document) — 207 ms, 0 B
- https://fonts.googleapis.com/css?family=Open%20Sans%3A400%2C400i%2C600%2C700%2C700i&subset=cyrillic&display=swap (stylesheet) — 140 ms, 0 B
- https://fonts.googleapis.com/css?family=Open%20Sans%3A400%2C400i%2C600%2C700%2C700i&subset=cyrillic&display=swap (xhr) — 139 ms, 0 B
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/global.04cbabbf7670bc75.js (script) — 47 ms, 0 B
- https://kodud.embach.ee/wp-content/plugins/sitepress-multilingual-cms/res/js/cookies/language-cookie.js (script) — 47 ms, 187 B

### Manual checks
- Console output during user interaction (load-only capture).
- Behavior on slow networks and constrained devices.
- WebGL / canvas FPS profiling via DevTools Layers panel.
- Service worker / cache behavior on repeat visits.

## HTML Inventory
_Captured in 1486 ms._

**Document:**
- Lang: et
- Title: Sample Page – Kodud
- Canonical: https://kodud.embach.ee/sample-page/
- Viewport: width=device-width, initial-scale=1
- Charset: UTF-8
- HTML bytes: 64087

**Meta tags:**
- Description: not set
- Robots: max-image-preview:large
- Theme color: #ffffff
- Open Graph tags: 0 (none)
- Twitter tags: 0
- hreflang:
  - et → https://kodud.embach.ee/sample-page/
  - x-default → https://kodud.embach.ee/sample-page/
- JSON-LD: none

**Heading outline:**
- Counts: h1 ×1, h2 ×0, h3 ×0, h4 ×0, h5 ×0, h6 ×0
- Sequence (first 20):
  - h1: Sample Page

**Landmarks:**
- nav: present
- main: present
- header: present
- footer: present
- Skip-to-content link: present

**Scripts:** 18 total — 1 defer, 1 async, 6 render-blocking. Speculation rules: yes.

External scripts (first 15):
- https://cdn.jsdelivr.net/gh/orestbida/iframemanager@1.3.0/dist/iframemanager.js
- https://cdn.jsdelivr.net/gh/orestbida/cookieconsent@3.0.1/dist/cookieconsent.umd.js
- https://kodud.embach.ee/wp-content/plugins/sitepress-multilingual-cms/res/js/cookies/language-cookie.js (defer)
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/jquery.d34d86e241c9422e.js
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/core.f01dd0977277031a.js
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/global.04cbabbf7670bc75.js
- https://kodud.embach.ee/wp-includes/js/jquery/jquery-migrate.min.js
- https://kodud.embach.ee/wp-content/plugins/wp-rocket/assets/js/wpr-beacon.min.js (async)

**Stylesheets:** 5 external, 3 inline (9.4 KB)

**Images:** 0 total — **0 without alt**, **0 without width/height**, 0 without loading="lazy"

**Links:** 22 anchors — 8 external, 1 preconnect, 1 preload.

Vague repeated link text:
- "kõik arendused" ×2
- "kontakt" ×2

### Priority fixes
1. **6 render-blocking external scripts** (medium) — Only 1 defer, 1 async; add defer/async to non-critical scripts

### Manual checks
- Visual rendering of detected mojibake (browser may auto-correct for display).
- Whether decorative images correctly use empty `alt=""` (vs. content images missing it).
- Whether headings reflect actual document hierarchy semantically.
- Whether vague link text is disambiguated by `aria-label` or surrounding context.

## Optimized-Web Checklist
_Captured in 0 ms._

**Summary:** 1 pass · 1 warn · 0 fail · 5 n/a

**Checklist:**
| Item | Status | Detail |
| --- | --- | --- |
| Page caching plugin / CDN active | ✓ pass | Caching plugin detected (WP Rocket) |
| Images lazy-loaded | – n/a | No raster <img> elements found. |
| Hero image eagerly loaded | – n/a | No raster <img> elements found. |
| Hero is a real <img> (not a CSS background-image) | – n/a | No CSS background-images detected on raster-image-eligible elements. |
| Responsive images (srcset / <picture>) | – n/a | Only 0 raster images on the page — responsive-image rule does not apply. |
| Reasonable number of image sizes | – n/a | Too few raster images to evaluate srcset width variety. |
| JS scripts not blocking in <head> | ! warn | 2 render-blocking scripts in <head>. Move to footer or add defer/async. |

**Evidence:**
- Page caching plugin / CDN active:
  - `HTML markers: WP Rocket`
  - `generator: WP Rocket 3.23`
- JS scripts not blocking in <head>:
  - `https://cdn.jsdelivr.net/gh/orestbida/iframemanager@1.3.0/dist/iframemanager.js`
  - `…//cdn.jsdelivr.net/gh/orestbida/cookieconsent@3.0.1/dist/cookieconsent.umd.js`

### Priority fixes
1. **JS scripts not blocking in <head>** (medium) — 2 render-blocking scripts in <head>. Move to footer or add defer/async.

### Manual checks
- Cart / checkout / logged-in pages must bypass the page cache or load dynamic regions via AJAX.
- Verify the cache is warmed for the canonical URL on initial deploy (first visitor should not pay the cold-start cost).
- Inspect "hero" image visually — heuristic above picks the first/largest <img>, which may not match the actual LCP element on JS-heavy pages.
- Confirm scripts marked as defer/async actually tolerate deferred execution (some legacy snippets break when reordered).

---

# Page 4 of 5 — https://kodud.embach.ee/koik-arendused

Run: 2026-07-20T09:52:02.265Z

## Audit Coverage
**100%** of audit sources returned data.

_All sources OK._

## Methodology

Each tool below contributes data to a single overall 0–100 site quality score. Performance dominates the weighting (~40%), followed by accessibility (~30%), image assets (~15%), and SEO/security (~15%). These weights are informative — the score is judged holistically, not from a fixed formula.

Severity scale in `priorities[]`:
- **high** — blocking issue / vulnerability / fail.
- **medium** — significant degradation.
- **low** — minor improvement.

Each tool section below lists: scores → priority fixes → findings → manual checks the tool cannot verify.

## Site Signals (inferred)

Heuristic site-shape signals derived from the audit data. Use these to calibrate the priority of security-header recommendations (see system rubric). Override when the evidence is clearly wrong.

- Auth surface: no
- Payments: no
- User-generated content: **yes** — anchor href contains "post"
- E-commerce: no

## PageSpeed Insights
_Captured in 16277 ms (mobile + desktop in parallel)._

**Lighthouse scores (mobile vs desktop; worse value bolded):**
| Category | Mobile | Desktop |
| --- | --- | --- |
| Performance | **76** | 97 |
| Accessibility | **95** | 96 |
| Best Practices | 100 | 100 |
| SEO | 92 | 92 |

**Core Web Vitals — lab (Lighthouse) / field (CrUX p75); worse lab value bolded:**
| Metric | Mobile | Desktop |
| --- | --- | --- |
| LCP | **5.2 s** | 1.2 s |
| CLS | 0.000 | **0.000** |
| TBT | **12 ms** | 0 ms |
| FCP | **2.78 s** | 669 ms |
| Speed Index | **3.28 s** | 865 ms |
| TTFB | **3 ms** | 2 ms |

### Priority fixes
1. **largest-contentful-paint** (high) — 5.2 s
2. **first-contentful-paint** (medium) — 2.8 s
3. **document-latency-insight** (high) — Est savings of 300 ms
4. **font-display-insight** (high) — Est savings of 40 ms
5. **image-delivery-insight** (high) — Est savings of 480 KiB

### Findings (mobile)

#### Unused JavaScript
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/global.04cbabbf7670bc75.js — 117 KB wasted

#### Long tasks
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/core.f01dd0977277031a.js — 67 ms
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/jquery.d34d86e241c9422e.js — 53 ms

#### DOM size
- Total nodes: 0

#### Failing modeled audits
- SEO: `metaDescription`
- SEO: `tapTargets`
- SEO: `structuredData`

#### All failing PSI audits (sorted by weight × failure margin)
- `largest-contentful-paint` (performance, score 0.23, weight 25) — Largest Contentful Paint — 5.2 s
- `button-name` (accessibility, score 0.00, weight 10) — Buttons do not have an accessible name
- `first-contentful-paint` (performance, score 0.57, weight 10) — First Contentful Paint — 2.8 s
- `network-dependency-tree-insight` (performance, score 0.00, weight 0) — Network dependency tree
- `meta-description` (seo, score 0.00, weight 1) — Document does not have a meta description
- `interactive` (performance, score 0.73, weight 0) — Time to Interactive — 5.3 s

### Manual checks
- Real-device behavior on slow 3G / low-tier mobile hardware (Lighthouse is throttled simulation).
- Sustained INP under typical user interaction, not just initial load.
- CrUX data interpretation if site is low-traffic and field data falls back to origin or is missing.

## Security Headers & HTTP
_Captured in 234 ms._

**Transport:**
- Final URL: https://kodud.embach.ee/koik-arendused/
- Status: 200
- Redirected: false
- HTTPS redirect: HTTP → HTTPS ✓

**Caching:**
- cache-control: `max-age=0`
- etag: n/a
- last-modified: Mon, 20 Jul 2026 07:35:03 GMT
- expires: Mon, 20 Jul 2026 09:52:02 GMT
- pragma: n/a
- vary: Accept-Encoding

**Compression:**
- content-encoding: gzip
- content-length: 15173
- Decoded body: 73.5 KB
- Compression ratio: 0.202

### Priority fixes
1. **strict-transport-security missing** (high) — Add HSTS with max-age >= 1 year, includeSubDomains, and preload
2. **content-security-policy missing** (high) — Add a CSP with default-src and script-src restrictions
3. **x-frame-options missing** (medium) — Prefer CSP frame-ancestors; X-Frame-Options as fallback
4. **x-content-type-options missing** (medium) — Send X-Content-Type-Options: nosniff
5. **referrer-policy missing** (low) — Set a Referrer-Policy such as strict-origin-when-cross-origin
6. **permissions-policy missing** (low) — Declare Permissions-Policy to disable unused features
7. **cross-origin-opener-policy missing** (low) — Set COOP to same-origin to isolate browsing context
8. **cross-origin-resource-policy missing** (low) — Set CORP to same-origin or same-site to prevent cross-origin reads
9. **x-permitted-cross-domain-policies missing** (low) — Set to none to prevent Flash/PDF cross-domain requests
10. **server header discloses technology** (low) — Server: Apache / ZoneOS

### Findings

#### Tracked headers
- **strict-transport-security** (missing, high)
- **content-security-policy** (missing, high)
- **x-frame-options** (missing, medium)
- **x-content-type-options** (missing, medium)
- **referrer-policy** (missing, low)
- **permissions-policy** (missing, low)
- **cross-origin-opener-policy** (missing, low)
- **cross-origin-resource-policy** (missing, low)
- **x-permitted-cross-domain-policies** (missing, low)

#### Info disclosure
- Server: `Apache / ZoneOS`


#### All response headers
```
cache-control: max-age=0
connection: Upgrade, Keep-Alive
content-encoding: gzip
content-length: 15173
content-type: text/html; charset=UTF-8
date: Mon, 20 Jul 2026 09:52:02 GMT
expires: Mon, 20 Jul 2026 09:52:02 GMT
keep-alive: timeout=5, max=100
last-modified: Mon, 20 Jul 2026 07:35:03 GMT
server: Apache / ZoneOS
vary: Accept-Encoding
```

### Manual checks
- Cookie attributes set via JavaScript (not visible in HTTP response).
- CORS preflight behavior under non-GET methods (only GET response headers checked).
- HSTS preload list inclusion (check hstspreload.org).
- WAF / DDoS posture beyond what static headers reveal.

## W3C HTML Validator
_Captured in 1084 ms._

**Scoring:** 0 errors · 1 warnings · 15 cosmetic (suppressed)

### Issue groups
- (×1) [warning] This document has heading elements but none of them has a computed heading level of 1. — first at line 411 `<h2 class="h1 hero-development__title">Pärnas`

### Manual checks
- Whether each `<section>` / `<article>` wraps semantically meaningful content.
- Language tag accuracy for multi-language pages or quoted content.
- Whether structural choices align with the document outline algorithm in screen readers.

## axe-core (Accessibility)
_Captured in 1715 ms._

**Scoring:** 1 violations · 32 passes · critical 0 · serious 0 · moderate 1 · minor 0

### Priority fixes
1. **page-has-heading-one** (medium) — Page should contain a level-one heading

### Findings

#### `page-has-heading-one` (moderate)
[Page should contain a level-one heading](https://dequeuniversity.com/rules/axe/4.11/page-has-heading-one?application=playwright)
- `html`

### Incomplete (axe could not determine)
- [Elements must meet minimum color contrast ratio thresholds](https://dequeuniversity.com/rules/axe/4.11/color-contrast?application=playwright) — 3 nodes

### Manual checks
- Keyboard-only navigation flow + visible focus indicators on every interactive element.
- Screen reader output (NVDA, VoiceOver) for actual auditory experience.
- Modal focus trapping and restoration on close.
- Touch target sizes (44×44 px minimum per WCAG 2.5.8).
- Color contrast for elements with alpha-transparency or gradients (axe skips these).

## Browser Runtime
_Captured in 1721 ms._

**Capture summary:** 0 console events · 0 mixed-content requests · 25 network requests · 672.1 KB total

**Network bytes by resource type:**
| Type | Count | Bytes |
| --- | --- | --- |
| image | 5 | 525.1 KB |
| script | 7 | 53.6 KB |
| stylesheet | 5 | 36.9 KB |
| font | 2 | 27.6 KB |
| document | 2 | 14.8 KB |
| xhr | 3 | 7.7 KB |
| other | 1 | 6.4 KB |

**Third-party origins (by bytes):**
- https://cdn.jsdelivr.net — 6 requests, 28.6 KB
- https://fonts.googleapis.com — 2 requests, 0 B

**Slowest requests (top 5):**
- https://fonts.googleapis.com/css?family=Open%20Sans%3A400%2C400i%2C600%2C700%2C700i&subset=cyrillic&display=swap (stylesheet) — 337 ms, 0 B
- https://kodud.embach.ee/koik-arendused (document) — 202 ms, 0 B
- https://fonts.googleapis.com/css?family=Open%20Sans%3A400%2C400i%2C600%2C700%2C700i&subset=cyrillic&display=swap (xhr) — 139 ms, 0 B
- https://kodud.embach.ee/wp-content/plugins/sitepress-multilingual-cms/res/js/cookies/language-cookie.js (script) — 54 ms, 187 B
- https://kodud.embach.ee/wp-content/uploads/sites/3/2026/07/siili_4_ttun1468-1-465x310.jpg (image) — 34 ms, 27.6 KB

### Manual checks
- Console output during user interaction (load-only capture).
- Behavior on slow networks and constrained devices.
- WebGL / canvas FPS profiling via DevTools Layers panel.
- Service worker / cache behavior on repeat visits.

## HTML Inventory
_Captured in 1721 ms._

**Document:**
- Lang: et
- Title: Kõik arendused – Kodud
- Canonical: https://kodud.embach.ee/koik-arendused/
- Viewport: width=device-width, initial-scale=1
- Charset: UTF-8
- HTML bytes: 74463

**Meta tags:**
- Description: not set
- Robots: max-image-preview:large
- Theme color: #ffffff
- Open Graph tags: 0 (none)
- Twitter tags: 0
- hreflang:
  - et → https://kodud.embach.ee/koik-arendused/
  - x-default → https://kodud.embach.ee/koik-arendused/
- JSON-LD: none

**Heading outline:**
- Counts: h1 ×0, h2 ×2, h3 ×0, h4 ×0, h5 ×0, h6 ×0
- Sequence (first 20):
  - h2: Pärnasalu kodud
  - h2: Omaniku leidnud kodud

**Landmarks:**
- nav: present
- main: present
- header: present
- footer: present
- Skip-to-content link: present

**Scripts:** 16 total — 1 defer, 0 async, 6 render-blocking. Speculation rules: yes.

External scripts (first 15):
- https://cdn.jsdelivr.net/gh/orestbida/iframemanager@1.3.0/dist/iframemanager.js
- https://cdn.jsdelivr.net/gh/orestbida/cookieconsent@3.0.1/dist/cookieconsent.umd.js
- https://kodud.embach.ee/wp-content/plugins/sitepress-multilingual-cms/res/js/cookies/language-cookie.js (defer)
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/jquery.d34d86e241c9422e.js
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/core.f01dd0977277031a.js
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/global.04cbabbf7670bc75.js
- https://kodud.embach.ee/wp-includes/js/jquery/jquery-migrate.min.js

**Stylesheets:** 5 external, 3 inline (9.4 KB)

**Images:** 5 total — **0 without alt**, **0 without width/height**, 0 without loading="lazy"

Image inventory (first 15):
| src | alt | w×h | loading | srcset |
| --- | --- | --- | --- | --- |
| t/uploads/sites/3/2026/05/parna_kesk_rgb_0020001-320x180.jpg | _(empty)_ | 320×180 | lazy | ✓ |
| -content/uploads/sites/3/2026/05/tammeparja_3d_4-300x200.jpg | _(empty)_ | 300×200 | lazy | ✓ |
| ntent/uploads/sites/3/2026/07/siili_4_ttun1468-1-300x200.jpg | _(empty)_ | 300×200 | lazy | ✓ |
| h2023_moisavahe-kortermajad_foto-timo-arbeiter-4-300x200.jpg | _(empty)_ | 300×200 | lazy | ✓ |
| oads/sites/3/2026/07/portree_0048-e1783936753672-100x100.jpg | _(empty)_ | 100×100 | lazy | ✓ |

**Links:** 28 anchors — 10 external, 1 preconnect, 2 preload.

Vague repeated link text:
- "kõik arendused" ×2
- "kontakt" ×2

### Priority fixes
1. **Document has 0 <h1> elements** (high) — A page should have exactly one h1; multiple h1s break document outline
2. **6 render-blocking external scripts** (medium) — Only 1 defer, 0 async; add defer/async to non-critical scripts

### Manual checks
- Visual rendering of detected mojibake (browser may auto-correct for display).
- Whether decorative images correctly use empty `alt=""` (vs. content images missing it).
- Whether headings reflect actual document hierarchy semantically.
- Whether vague link text is disambiguated by `aria-label` or surrounding context.

## Optimized-Web Checklist
_Captured in 0 ms._

**Summary:** 4 pass · 1 warn · 1 fail · 1 n/a

**Checklist:**
| Item | Status | Detail |
| --- | --- | --- |
| Page caching plugin / CDN active | ✓ pass | Caching plugin detected (WP Rocket) |
| Images lazy-loaded | ✓ pass | All non-hero raster images use loading="lazy". |
| 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 <img> (not a CSS background-image) | – n/a | No CSS background-images detected on raster-image-eligible elements. |
| Responsive images (srcset / <picture>) | ✓ pass | 5/5 raster images use srcset or <picture> (100%). |
| Reasonable number of image sizes | ✓ pass | 22 distinct srcset widths. |
| JS scripts not blocking in <head> | ! warn | 2 render-blocking scripts in <head>. Move to footer or add defer/async. |

**Evidence:**
- Page caching plugin / CDN active:
  - `HTML markers: WP Rocket`
  - `generator: WP Rocket 3.23`
- Hero image eagerly loaded:
  - `hero: …bach.ee/wp-content/uploads/sites/3/2026/05/parna_kesk_rgb_0020001-320x180.jpg`
  - `loading: lazy`
  - `fetchpriority: (not set)`
- Reasonable number of image sizes:
  - `widths: 100, 150, 155, 200, 232, 300, 310, 320, 400, 465, 600, 640, 768, 800, 1024, 1200, 1252, 1536, 1600, 2048, 2560, 3200`
- JS scripts not blocking in <head>:
  - `https://cdn.jsdelivr.net/gh/orestbida/iframemanager@1.3.0/dist/iframemanager.js`
  - `…//cdn.jsdelivr.net/gh/orestbida/cookieconsent@3.0.1/dist/cookieconsent.umd.js`

### Priority fixes
1. **Hero image eagerly loaded** (high) — 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".
2. **JS scripts not blocking in <head>** (medium) — 2 render-blocking scripts in <head>. Move to footer or add defer/async.

### Manual checks
- Cart / checkout / logged-in pages must bypass the page cache or load dynamic regions via AJAX.
- Verify the cache is warmed for the canonical URL on initial deploy (first visitor should not pay the cold-start cost).
- Inspect "hero" image visually — heuristic above picks the first/largest <img>, which may not match the actual LCP element on JS-heavy pages.
- Confirm scripts marked as defer/async actually tolerate deferred execution (some legacy snippets break when reordered).

---

# Page 5 of 5 — https://kodud.embach.ee/kontakt

Run: 2026-07-20T09:52:21.188Z

## Audit Coverage
**100%** of audit sources returned data.

_All sources OK._

## Methodology

Each tool below contributes data to a single overall 0–100 site quality score. Performance dominates the weighting (~40%), followed by accessibility (~30%), image assets (~15%), and SEO/security (~15%). These weights are informative — the score is judged holistically, not from a fixed formula.

Severity scale in `priorities[]`:
- **high** — blocking issue / vulnerability / fail.
- **medium** — significant degradation.
- **low** — minor improvement.

Each tool section below lists: scores → priority fixes → findings → manual checks the tool cannot verify.

## Site Signals (inferred)

Heuristic site-shape signals derived from the audit data. Use these to calibrate the priority of security-header recommendations (see system rubric). Override when the evidence is clearly wrong.

- Auth surface: no
- Payments: no
- User-generated content: **yes** — anchor href contains "post"
- E-commerce: no

## PageSpeed Insights
_Captured in 14467 ms (mobile + desktop in parallel)._

**Lighthouse scores (mobile vs desktop; worse value bolded):**
| Category | Mobile | Desktop |
| --- | --- | --- |
| Performance | **82** | 99 |
| Accessibility | **91** | 96 |
| Best Practices | 100 | 100 |
| SEO | 92 | 92 |

**Core Web Vitals — lab (Lighthouse) / field (CrUX p75); worse lab value bolded:**
| Metric | Mobile | Desktop |
| --- | --- | --- |
| LCP | **4.5 s** | 0.9 s |
| CLS | 0.000 | **0.000** |
| TBT | **20 ms** | 0 ms |
| FCP | **2.13 s** | 610 ms |
| Speed Index | **2.33 s** | 726 ms |
| TTFB | 2 ms | 2 ms |

### Priority fixes
1. **largest-contentful-paint** (high) — 4.5 s
2. **first-contentful-paint** (low) — 2.1 s
3. **document-latency-insight** (high) — Est savings of 320 ms
4. **font-display-insight** (high) — Est savings of 80 ms
5. **image-delivery-insight** (high) — Est savings of 24 KiB

### Findings (mobile)

#### Unused JavaScript
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/global.04cbabbf7670bc75.js — 117 KB wasted

#### Long tasks
- Unattributable — 117 ms
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/core.f01dd0977277031a.js — 74 ms
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/jquery.d34d86e241c9422e.js — 58 ms

#### DOM size
- Total nodes: 0

#### Failing modeled audits
- SEO: `metaDescription`
- SEO: `tapTargets`
- SEO: `structuredData`

#### All failing PSI audits (sorted by weight × failure margin)
- `largest-contentful-paint` (performance, score 0.37, weight 25) — Largest Contentful Paint — 4.5 s
- `button-name` (accessibility, score 0.00, weight 10) — Buttons do not have an accessible name
- `target-size` (accessibility, score 0.00, weight 7) — Touch targets do not have sufficient size or spacing.
- `first-contentful-paint` (performance, score 0.80, weight 10) — First Contentful Paint — 2.1 s
- `network-dependency-tree-insight` (performance, score 0.00, weight 0) — Network dependency tree
- `meta-description` (seo, score 0.00, weight 1) — Document does not have a meta description
- `interactive` (performance, score 0.82, weight 0) — Time to Interactive — 4.5 s

### Manual checks
- Real-device behavior on slow 3G / low-tier mobile hardware (Lighthouse is throttled simulation).
- Sustained INP under typical user interaction, not just initial load.
- CrUX data interpretation if site is low-traffic and field data falls back to origin or is missing.

## Security Headers & HTTP
_Captured in 233 ms._

**Transport:**
- Final URL: https://kodud.embach.ee/kontakt/
- Status: 200
- Redirected: false
- HTTPS redirect: HTTP → HTTPS ✓

**Caching:**
- cache-control: `max-age=0`
- etag: n/a
- last-modified: Mon, 20 Jul 2026 07:35:08 GMT
- expires: Mon, 20 Jul 2026 09:52:21 GMT
- pragma: n/a
- vary: Accept-Encoding

**Compression:**
- content-encoding: gzip
- content-length: 15197
- Decoded body: 70.8 KB
- Compression ratio: 0.209

### Priority fixes
1. **strict-transport-security missing** (high) — Add HSTS with max-age >= 1 year, includeSubDomains, and preload
2. **content-security-policy missing** (high) — Add a CSP with default-src and script-src restrictions
3. **x-frame-options missing** (medium) — Prefer CSP frame-ancestors; X-Frame-Options as fallback
4. **x-content-type-options missing** (medium) — Send X-Content-Type-Options: nosniff
5. **referrer-policy missing** (low) — Set a Referrer-Policy such as strict-origin-when-cross-origin
6. **permissions-policy missing** (low) — Declare Permissions-Policy to disable unused features
7. **cross-origin-opener-policy missing** (low) — Set COOP to same-origin to isolate browsing context
8. **cross-origin-resource-policy missing** (low) — Set CORP to same-origin or same-site to prevent cross-origin reads
9. **x-permitted-cross-domain-policies missing** (low) — Set to none to prevent Flash/PDF cross-domain requests
10. **server header discloses technology** (low) — Server: Apache / ZoneOS

### Findings

#### Tracked headers
- **strict-transport-security** (missing, high)
- **content-security-policy** (missing, high)
- **x-frame-options** (missing, medium)
- **x-content-type-options** (missing, medium)
- **referrer-policy** (missing, low)
- **permissions-policy** (missing, low)
- **cross-origin-opener-policy** (missing, low)
- **cross-origin-resource-policy** (missing, low)
- **x-permitted-cross-domain-policies** (missing, low)

#### Info disclosure
- Server: `Apache / ZoneOS`


#### All response headers
```
cache-control: max-age=0
connection: Upgrade, Keep-Alive
content-encoding: gzip
content-length: 15197
content-type: text/html; charset=UTF-8
date: Mon, 20 Jul 2026 09:52:21 GMT
expires: Mon, 20 Jul 2026 09:52:21 GMT
keep-alive: timeout=5, max=100
last-modified: Mon, 20 Jul 2026 07:35:08 GMT
server: Apache / ZoneOS
vary: Accept-Encoding
```

### Manual checks
- Cookie attributes set via JavaScript (not visible in HTTP response).
- CORS preflight behavior under non-GET methods (only GET response headers checked).
- HSTS preload list inclusion (check hstspreload.org).
- WAF / DDoS posture beyond what static headers reveal.

## W3C HTML Validator
_Captured in 988 ms._

**Scoring:** 2 errors · 1 warnings · 16 cosmetic (suppressed)

### Priority fixes
1. **Bad value “https://kodud.embach.ee/wp-content/uploads/sites/3/2026/07/tartu.svg” for attribute “srcset” on element “img”: No width specified for image “https://kodud.embach.ee/w…sites/3/2026/07/tartu.svg”. (When the “sizes” attribute is present, all image candidate strings must specify a width.)** (medium) — x1, first at line 526
2. **No “p” element in scope but a “p” end tag seen.** (medium) — x1, first at line 538

### Issue groups
- (×1) [warning] The “type” attribute is unnecessary for JavaScript resources. — first at line 463 `/noscript><script nowprocket type="text/javascript">var el`
- (×1) [error] Bad value “https://kodud.embach.ee/wp-content/uploads/sites/3/2026/07/tartu.svg” for attribute “srcset” on element “img”: No width specified for image “https://kodud.embach.ee/w…sites/3/2026/07/tartu.svg”. (When the “sizes” attribute is present, all image candidate strings must specify a width.) — first at line 526 `<img
        alt=""
        class="image__img"
        loading="lazy"
        wi`
- (×1) [error] No “p” element in scope but a “p” end tag seen. — first at line 538 `duse.</p>
</p>`

### Manual checks
- Whether each `<section>` / `<article>` wraps semantically meaningful content.
- Language tag accuracy for multi-language pages or quoted content.
- Whether structural choices align with the document outline algorithm in screen readers.

## axe-core (Accessibility)
_Captured in 1662 ms._

**Scoring:** 0 violations · 33 passes · critical 0 · serious 0 · moderate 0 · minor 0

### Incomplete (axe could not determine)
- [Elements must meet minimum color contrast ratio thresholds](https://dequeuniversity.com/rules/axe/4.11/color-contrast?application=playwright) — 1 node

### Manual checks
- Keyboard-only navigation flow + visible focus indicators on every interactive element.
- Screen reader output (NVDA, VoiceOver) for actual auditory experience.
- Modal focus trapping and restoration on close.
- Touch target sizes (44×44 px minimum per WCAG 2.5.8).
- Color contrast for elements with alpha-transparency or gradients (axe skips these).

## Browser Runtime
_Captured in 1669 ms._

**Capture summary:** 0 console events · 0 mixed-content requests · 22 network requests · 168.8 KB total

**Network bytes by resource type:**
| Type | Count | Bytes |
| --- | --- | --- |
| script | 7 | 53.6 KB |
| stylesheet | 5 | 36.9 KB |
| font | 2 | 27.6 KB |
| image | 2 | 21.7 KB |
| document | 2 | 14.8 KB |
| xhr | 3 | 7.7 KB |
| other | 1 | 6.4 KB |

**Third-party origins (by bytes):**
- https://cdn.jsdelivr.net — 6 requests, 28.6 KB
- https://fonts.googleapis.com — 2 requests, 0 B

**Slowest requests (top 5):**
- https://kodud.embach.ee/kontakt (document) — 188 ms, 0 B
- https://fonts.googleapis.com/css?family=Open%20Sans%3A400%2C400i%2C600%2C700%2C700i&subset=cyrillic&display=swap (stylesheet) — 150 ms, 0 B
- https://fonts.googleapis.com/css?family=Open%20Sans%3A400%2C400i%2C600%2C700%2C700i&subset=cyrillic&display=swap (xhr) — 141 ms, 0 B
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/global.04cbabbf7670bc75.js (script) — 47 ms, 0 B
- https://kodud.embach.ee/wp-content/plugins/sitepress-multilingual-cms/res/js/cookies/language-cookie.js (script) — 47 ms, 187 B

### Manual checks
- Console output during user interaction (load-only capture).
- Behavior on slow networks and constrained devices.
- WebGL / canvas FPS profiling via DevTools Layers panel.
- Service worker / cache behavior on repeat visits.

## HTML Inventory
_Captured in 1669 ms._

**Document:**
- Lang: et
- Title: Kontakt – Kodud
- Canonical: https://kodud.embach.ee/kontakt/
- Viewport: width=device-width, initial-scale=1
- Charset: UTF-8
- HTML bytes: 71849

**Meta tags:**
- Description: not set
- Robots: max-image-preview:large
- Theme color: #ffffff
- Open Graph tags: 0 (none)
- Twitter tags: 0
- hreflang:
  - et → https://kodud.embach.ee/kontakt/
  - x-default → https://kodud.embach.ee/kontakt/
- JSON-LD: none

**Heading outline:**
- Counts: h1 ×1, h2 ×0, h3 ×0, h4 ×0, h5 ×0, h6 ×0
- Sequence (first 20):
  - h1: Kontakt

**Landmarks:**
- nav: present
- main: present
- header: present
- footer: present
- Skip-to-content link: present

**Scripts:** 16 total — 1 defer, 0 async, 6 render-blocking. Speculation rules: yes.

External scripts (first 15):
- https://cdn.jsdelivr.net/gh/orestbida/iframemanager@1.3.0/dist/iframemanager.js
- https://cdn.jsdelivr.net/gh/orestbida/cookieconsent@3.0.1/dist/cookieconsent.umd.js
- https://kodud.embach.ee/wp-content/plugins/sitepress-multilingual-cms/res/js/cookies/language-cookie.js (defer)
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/jquery.d34d86e241c9422e.js
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/core.f01dd0977277031a.js
- https://kodud.embach.ee/wp-content/themes/embach/inc/theme/js/global.04cbabbf7670bc75.js
- https://kodud.embach.ee/wp-includes/js/jquery/jquery-migrate.min.js

**Stylesheets:** 5 external, 3 inline (9.4 KB)

**Images:** 2 total — **0 without alt**, **0 without width/height**, 0 without loading="lazy"

Image inventory (first 15):
| src | alt | w×h | loading | srcset |
| --- | --- | --- | --- | --- |
| oads/sites/3/2026/07/portree_0048-e1783936753672-100x100.jpg | _(empty)_ | 100×100 | lazy | ✓ |
| kodud.embach.ee/wp-content/uploads/sites/3/2026/07/tartu.svg | _(empty)_ | 400×440 | lazy | ✓ |

**Links:** 27 anchors — 13 external, 1 preconnect, 2 preload.

Vague repeated link text:
- "kõik arendused" ×2
- "kontakt" ×2
- "järelteenindus" ×2

### Priority fixes
1. **6 render-blocking external scripts** (medium) — Only 1 defer, 0 async; add defer/async to non-critical scripts

### Manual checks
- Visual rendering of detected mojibake (browser may auto-correct for display).
- Whether decorative images correctly use empty `alt=""` (vs. content images missing it).
- Whether headings reflect actual document hierarchy semantically.
- Whether vague link text is disambiguated by `aria-label` or surrounding context.

## Optimized-Web Checklist
_Captured in 0 ms._

**Summary:** 2 pass · 1 warn · 1 fail · 3 n/a

**Checklist:**
| Item | Status | Detail |
| --- | --- | --- |
| Page caching plugin / CDN active | ✓ pass | Caching plugin detected (WP Rocket) |
| Images lazy-loaded | ✓ pass | All raster images use loading="lazy" (1 SVG excluded). |
| 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 <img> (not a CSS background-image) | – n/a | No CSS background-images detected on raster-image-eligible elements. |
| Responsive images (srcset / <picture>) | – n/a | Only 1 raster image on the page (1 SVG excluded) — responsive-image rule does not apply. |
| Reasonable number of image sizes | – n/a | Too few raster images to evaluate srcset width variety. |
| JS scripts not blocking in <head> | ! warn | 2 render-blocking scripts in <head>. Move to footer or add defer/async. |

**Evidence:**
- Page caching plugin / CDN active:
  - `HTML markers: WP Rocket`
  - `generator: WP Rocket 3.23`
- Hero image eagerly loaded:
  - `hero: …ee/wp-content/uploads/sites/3/2026/07/portree_0048-e1783936753672-100x100.jpg`
  - `loading: lazy`
  - `fetchpriority: (not set)`
- JS scripts not blocking in <head>:
  - `https://cdn.jsdelivr.net/gh/orestbida/iframemanager@1.3.0/dist/iframemanager.js`
  - `…//cdn.jsdelivr.net/gh/orestbida/cookieconsent@3.0.1/dist/cookieconsent.umd.js`

### Priority fixes
1. **Hero image eagerly loaded** (high) — 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".
2. **JS scripts not blocking in <head>** (medium) — 2 render-blocking scripts in <head>. Move to footer or add defer/async.

### Manual checks
- Cart / checkout / logged-in pages must bypass the page cache or load dynamic regions via AJAX.
- Verify the cache is warmed for the canonical URL on initial deploy (first visitor should not pay the cold-start cost).
- Inspect "hero" image visually — heuristic above picks the first/largest <img>, which may not match the actual LCP element on JS-heavy pages.
- Confirm scripts marked as defer/async actually tolerate deferred execution (some legacy snippets break when reordered).