Audit

20260901T120947Z-ea1d

← Back to playee
Audited URL
https://play.ee/
Timestamp
2026-09-01T12:15:53.895Z
Kind
site
Pages
5
Audit summary
https://play.ee/
5 of 5 pages audited
Pagespeed scores
Other checks
LLM Report

Weighted audit summary

76
Overall site quality
Needs Improvementhigh confidence

Site overall 76 is the mean of 5 pages. Scores range 73 (https://play.ee/software-development-work-index/) → 79 (https://play.ee/web-development-case-studies/). Weakest page: Mobile PSI 96 indicates strong performance (LCP 2.3 s, CLS 0.04), but security configuration is critically weak (Grade 20/100, HTTP not redirecting to HTTPS). W3C validation shows 8 errors with parser recovery failure at line 106, indicating broken DOM structure. Accessibility has a serious color-contrast violation and missing main landmark. Image assets lack explicit dimensions on all 53 instances, risking CLS. Overall score reflects high performance weighed down by security and structural quality issues.

Per-page scores
75
Home
high
79
…evelopment-case-studies
high
73
…-development-work-index
high
76
…rdpress-support-service
high
78
…-development-in-estonia
high

Audit Report: Perfectly formed web development team - gotoAndPlay

Website: https://play.ee/
Date: 01.09.2026
Audit Coverage: 100% — all sources returned data
Confidence: high

Pages Audited (5 of 5):

Summary of results

Overall Score: 76 / 100
Status: 🟡 Needs Improvement

Site overall 76 is the mean of 5 pages. Scores range 73 (https://play.ee/software-development-work-index/) → 79 (https://play.ee/web-development-case-studies/). Weakest page: Mobile PSI 96 indicates strong performance (LCP 2.3 s, CLS 0.04), but security configuration is critically weak (Grade 20/100, HTTP not redirecting to HTTPS). W3C validation shows 8 errors with parser recovery failure at line 106, indicating broken DOM structure. Accessibility has a serious color-contrast violation and missing main landmark. Image assets lack explicit dimensions on all 53 instances, risking CLS. Overall score reflects high performance weighed down by security and structural quality issues.

Per-page scores

🟡 Needs Improvement · https://play.ee/

Score Performance Accessibility Best Practices SEO Security
75 94 100 100 92 20

🟡 Needs Improvement · https://play.ee/web-development-case-studies/

Score Performance Accessibility Best Practices SEO Security
79 97 90 96 100 20

🟡 Needs Improvement · https://play.ee/software-development-work-index/

Score Performance Accessibility Best Practices SEO Security
73 96 90 96 100 20

🟡 Needs Improvement · https://play.ee/wordpress-support-service/

Score Performance Accessibility Best Practices SEO Security
76 94 91 100 100 20

🟡 Needs Improvement · https://play.ee/web-development-in-estonia/

Score Performance Accessibility Best Practices SEO Security
78 96 94 100 100 20

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://play.ee/ 94 / 100 2.51 s / 662 ms 0.000 / 0.007
https://play.ee/web-development-case-studies/ 97 / 93 2.13 s / 544 ms 0.005 / 0.005
https://play.ee/software-development-work-index/ 96 / 100 2.33 s / 582 ms 0.041 / 0.004
https://play.ee/wordpress-support-service/ 94 / 100 2.57 s / 546 ms 0.000 / 0.002
https://play.ee/web-development-in-estonia/ 96 / 100 2.40 s / 623 ms 0.002 / 0.006

Optimization Checklist

2 of 2 passing — 2 pass · 0 warn · 0 fail · 5 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 (37 SVGs, 13 placeholders excluded).
Hero image eagerly loaded N/A No raster <img> elements found (37 SVGs, 13 placeholders excluded).
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 (37 SVGs, 13 placeholders 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> Pass No render-blocking scripts in <head>.

Fixes

Priority 1: Critical

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

1A. Force HTTPS redirect Security

  • Impact: Transport security, MITM protection
  • Problem: http://play.ee/ does not redirect to HTTPS, leaving the site vulnerable to downgrade attacks despite HTTPS support.
  • Solution: Configure the web server (Apache/Nginx) to return a 301 redirect for all HTTP traffic to HTTPS:
    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
    

1B. Enforce HTTPS redirect Security

  • Impact: Transport security, downgrade attack prevention
  • Problem: Security audit reports 'http://play.ee/web-development-case-studies/ does not redirect to HTTPS', leaving users vulnerable to downgrade attacks.
  • Solution: Configure the web server (Apache/Nginx) to return a 301 redirect for all HTTP requests to HTTPS:
    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
    

1C. Fix color contrast violations Accessibility

  • Impact: WCAG 1.4.3 compliance, readability
  • Problem: axe-core reports 1 serious violation: 'color-contrast' on multiple nodes including h1 and card titles.
  • Solution: Increase contrast ratio to ≥4.5:1 for normal text. Adjust CSS colors for .heading__main and .card__title:
    .heading__main { color: #333333; } /* Example adjustment */
    

1D. Enforce HTTPS redirect and add baseline security headers Security

  • Impact: Transport security, clickjacking protection, MIME sniffing
  • Problem: HTTP does not redirect to HTTPS (Grade 20/100); HSTS, X-Content-Type-Options, and X-Frame-Options are missing.
  • Solution: Configure server to redirect all HTTP traffic to HTTPS. Add these headers:
    Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains"
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "SAMEORIGIN"
    

1E. Fix HTML validation errors and parser recovery failure Best Practices

  • Impact: DOM integrity, SEO rendering, cross-browser compatibility
  • Problem: W3C reports 8 errors including parser recovery failure at line 106; stray tags and invalid attributes detected.
  • Solution: Review lines 52–106 in source. Fix empty href on <link>, remove <iframe> from <head> (move to <body>), and correct <meta> attributes. Ensure <noscript> is closed properly.

1F. Force HTTPS redirect and add HSTS Security

  • Impact: Transport security, trust
  • Problem: HTTP does not redirect to HTTPS and HSTS is missing; Security Headers grade is 20/100.
  • Solution: Configure server to redirect all HTTP traffic to HTTPS and send HSTS header:
    Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
    

1G. Fix HTML validation errors and parser recovery Best Practices

  • Impact: DOM integrity, SEO, rendering
  • Problem: W3C validator reports 7 errors including parser recovery failure at line 107 (iframe in noscript in head).
  • Solution: Move <noscript><iframe> tags out of <head> and ensure <meta> tags are valid. Fix stray end tags to allow full DOM parsing.

1H. Enforce HTTPS redirect and add HSTS Security

  • Impact: Transport security, user trust
  • Problem: HTTP does not redirect to HTTPS and HSTS is missing (Security Headers grade 20/100).
  • Solution: Configure server to redirect all HTTP traffic to HTTPS and send HSTS header:
    Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
    

Priority 2: Important

Essential for compliance, user reach, and search visibility.

2A. Add HSTS and X-Content-Type-Options Security

  • Impact: Protocol downgrade, MIME sniffing
  • Problem: Security Headers grade is 20/100; HSTS and X-Content-Type-Options are missing regardless of site signals.
  • Solution: Add these headers to the server configuration:
    Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
    Header always set X-Content-Type-Options "nosniff"
    

2B. Add main landmark and skip-to-content link Accessibility

  • Impact: Screen reader navigation, WCAG 2.4.1
  • Problem: axe-core reports missing main landmark and no skip-to-content link; 50 images lack dimensions.
  • Solution: Wrap primary content in <main> and add a skip link at the top:
    <a href="#main-content" class="skip-link">Skip to content</a>
    ...
    <main id="main-content">
    

2C. Fix W3C HTML validation errors SEO

  • Impact: Rendering consistency, SEO crawling
  • Problem: 8 W3C errors including empty href attributes, stray end tags, and parser recovery failure at line 107.
  • Solution: Review the HTML source around line 54 and 104. Remove empty href="" on links, fix <noscript> nesting inside <head>, and ensure <meta> tags are in valid locations.

2D. Add main landmark and skip link Accessibility

  • Impact: Screen reader navigation, WCAG 2.4.1
  • Problem: HTML Inventory confirms 'main: missing' and 'Skip-to-content link: missing'; axe reports 'landmark-one-main' failure.
  • Solution: Wrap primary content in <main> and add a skip link at the top:
    <a href="#main-content" class="skip-link">Skip to content</a>
    ...
    <main id="main-content">
      <!-- Page content -->
    </main>
    

2E. Fix contrast violations and add main landmark Accessibility

  • Impact: WCAG 1.4.3 contrast, 1.3.1 info relationships
  • Problem: axe-core reports 1 serious color-contrast violation (h1, p span); PSI landmark-one-main failed; no skip-to-content link.
  • Solution:
    • Increase contrast ratio on .heading__main and p > span to ≥4.5:1.
    • Add <main id="main-content"> wrapper around primary content.
    • Add <a href="#main-content" class="skip-link">Skip to content</a> before header.

2F. Add explicit width and height to all images Performance

  • Impact: CLS (Cumulative Layout Shift)
  • Problem: 53 images lack width/height attributes, risking layout shifts despite low lab CLS score.
  • Solution: Add width and height attributes to every <img> tag matching intrinsic dimensions. For responsive images, use width/height on the <img> and sizes on <source>.

2G. Fix color contrast and link names Accessibility

  • Impact: WCAG 1.4.3, 2.4.4 compliance
  • Problem: axe-core reports 2 serious violations: color-contrast on multiple nodes and link-name on logo grid links.
  • Solution: Increase contrast ratio to ≥4.5:1 for .button--tertiary and .heading__small. Add aria-label to logo links with empty href.

2H. Eliminate render-blocking resources Performance

  • Impact: LCP, FCP, Speed Index
  • Problem: PSI findings indicate potential savings of 1,270 ms from render-blocking insight; LCP is 2.6 s.
  • Solution: Defer non-critical scripts and inline critical CSS. Ensure jquery.bfe1bb19d13b3c17b682.min.js is deferred if not needed for initial paint.

2I. Fix W3C validation errors and heading structure SEO

  • Impact: Document outline, parser reliability
  • Problem: W3C reports 7 errors including parser recovery failure at line 100 and 2 <h1> elements.
  • Solution: Ensure exactly one <h1> per page. Fix malformed <noscript>/<iframe> nesting in <head> and remove invalid name attributes on <meta> tags.

Priority 3: Best Practice

Recommended for long-term maintainability.

3A. Disambiguate vague link text SEO

  • Impact: Link context, SEO anchor text
  • Problem: 9 instances of 'read more' and repeated generic text ('visit our facebook page') reduce link descriptiveness.
  • Solution: Update link text to describe the destination, e.g., 'Read more about our case studies' or use aria-label if visual text must remain generic.

3B. Add explicit width/height to images Performance

  • Impact: CLS prevention, layout stability
  • Problem: HTML Inventory shows 56 images without width/height attributes, risking layout shifts despite current CLS score.
  • Solution: Add width and height attributes to all <img> tags or use CSS aspect-ratio:
    <img src="..." width="300" height="200" alt="...">
    

3C. Remove unused CSS and JavaScript Performance

  • Impact: FCP, TBT, Total Page Weight
  • Problem: 32 KiB unused CSS and 23 KiB unused JS detected; FCP is 1.96 s (warning zone).
  • Solution:
    • Purge unused CSS rules (WP Rocket may handle this).
    • Defer non-critical JS or remove jquery.bfe1bb19d13b3c17b682.min.js if not needed.
    • Enable tree-shaking in build process.

3D. Add image dimensions and lazy loading Performance

  • Impact: CLS, bandwidth
  • Problem: 31 images lack explicit width/height attributes and loading="lazy" despite low total weight.
  • Solution: Add width and height attributes to all <img> tags to reserve space. Add loading="lazy" to images below the fold.

3E. Implement Content-Security-Policy (CSP) Security

  • Impact: XSS defense-in-depth
  • Problem: CSP is missing. Site signals show no auth/payments/UGC, so risk is lower but defense-in-depth is recommended.
  • Solution: Deploy a strict CSP with nonces for scripts:
    Header always set Content-Security-Policy "default-src 'self'; script-src 'nonce-{random}' 'strict-dynamic'; object-src 'none'; base-uri 'none';"
    
▸Raw Markdown sent to the LLM
# Site Audit — https://play.ee/
Run: 2026-09-01T12:09:47.482Z

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

Pages audited:
- https://play.ee/
- https://play.ee/web-development-case-studies/
- https://play.ee/software-development-work-index/
- https://play.ee/wordpress-support-service/
- https://play.ee/web-development-in-estonia/

---

# Page 1 of 5 — https://play.ee/

Run: 2026-09-01T12:09:47.633Z

## 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: no
- E-commerce: no

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

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

**Core Web Vitals — lab (Lighthouse) / field (CrUX p75); worse lab value bolded:**
| Metric | Mobile | Desktop |
| --- | --- | --- |
| LCP | **2.5 s** | 0.7 s |
| CLS | 0.000 | **0.007** |
| TBT | 0 ms | **16 ms** |
| FCP | **1.99 s** | 514 ms |
| Speed Index | **4.09 s** | 542 ms |
| TTFB | **36 ms** | 9 ms |

### Priority fixes
1. **largest-contentful-paint** (low) — 2.5 s
2. **speed-index** (low) — 4.1 s
3. **first-contentful-paint** (low) — 2.0 s
4. **network-dependency-tree-insight** (high)
5. **render-blocking-insight** (high) — Est savings of 1,050 ms

### Findings (mobile)

#### Unused JavaScript
- https://play.ee/wp-content/themes/gotoandplay/inc/theme/js/jquery.bfe1bb19d13b3c17b682.min.js — 23 KB wasted

#### DOM size
- Total nodes: 0

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

#### All failing PSI audits (sorted by weight × failure margin)
- `largest-contentful-paint` (performance, score 0.89, weight 25) — Largest Contentful Paint — 2.5 s
- `speed-index` (performance, score 0.79, weight 10) — Speed Index — 4.1 s
- `first-contentful-paint` (performance, score 0.84, weight 10) — First Contentful Paint — 2.0 s
- `network-dependency-tree-insight` (performance, score 0.00, weight 0) — Network dependency tree
- `link-text` (seo, score 0.00, weight 1) — Links do not have descriptive text — 9 links found

### 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 59 ms._

**Transport:**
- Final URL: https://play.ee/
- Status: 200
- Redirected: false
- HTTPS redirect: ✗ http://play.ee/ does not redirect to HTTPS (target: none)

**Caching:**
- cache-control: `max-age=0`
- etag: n/a
- last-modified: Tue, 01 Sep 2026 08:39:15 GMT
- expires: Tue, 01 Sep 2026 12:09:47 GMT
- pragma: n/a
- vary: Accept-Encoding

**Compression:**
- content-encoding: gzip
- content-length: 35476
- Decoded body: 217.0 KB
- Compression ratio: 0.16

### Priority fixes
1. **HTTP does not redirect to HTTPS** (high) — http://play.ee/ does not redirect to HTTPS
2. **strict-transport-security missing** (high) — Add HSTS with max-age >= 1 year, includeSubDomains, and preload
3. **content-security-policy weak** (high) — missing default-src; missing object-src 'none'; only frame-ancestors set — no script/resource restrictions
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

### Findings

#### Tracked headers
- **strict-transport-security** (missing, high)
- **content-security-policy** (weak, high) `frame-ancestors 'self';` — missing default-src; missing object-src 'none'; only frame-ancestors set — no script/resource restrictions
- **x-frame-options** (present, medium) `SAMEORIGIN`
- **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`
- X-Powered-By: `PHP/8.3.33`

#### All response headers
```
cache-control: max-age=0
connection: Upgrade, Keep-Alive
content-encoding: gzip
content-length: 35476
content-security-policy: frame-ancestors 'self';
content-type: text/html; charset=UTF-8
date: Tue, 01 Sep 2026 12:09:47 GMT
expires: Tue, 01 Sep 2026 12:09:47 GMT
keep-alive: timeout=5, max=100
last-modified: Tue, 01 Sep 2026 08:39:15 GMT
server: Apache
upgrade: h2,h2c
vary: Accept-Encoding
x-frame-options: SAMEORIGIN
x-powered-by: PHP/8.3.33
```

### 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 738 ms._

**Scoring:** 8 errors · 0 warnings · 23 cosmetic (suppressed)

> **Validator truncated at line 107** — the Nu validator stopped after hitting its internal error budget; score against the errors above, NOT as a fatal parse failure: Cannot recover after last error. Any further errors will be ignored.

### Priority fixes
1. **Parser recovery at line 107** (high) — Cannot recover after last error. Any further errors will be ignored.
2. **Bad value “” for attribute “href” on element “link”: Must be non-empty.** (medium) — x1, first at line 54
3. **Bad start tag in “iframe” in “noscript” in “head”.** (medium) — x1, first at line 104
4. **Stray end tag “noscript”.** (medium) — x1, first at line 104
5. **Attribute “name” not allowed on element “meta” at this point.** (medium) — x1, first at line 106

### Issue groups
- (×1) [error] Bad value “” for attribute “href” on element “link”: Must be non-empty. — first at line 54 `refetch">
<link data-rocket-prefetch href="" rel="dns-prefetch">
<link`
- (×1) [error] Bad start tag in “iframe” in “noscript” in “head”. — first at line 104 `<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-K3P64XMJ"`
- (×1) [error] Stray end tag “noscript”. — first at line 104 `></iframe></noscript><!-- E`
- (×1) [error] Attribute “name” not allowed on element “meta” at this point. — first at line 106 `<meta name="generator" content="WP Rocket 3.23.3.3" data-wpr-features="wpr_delay`
- (×1) [error] Element “meta” is missing one or more of the following attributes: “itemprop”, “property”. — first at line 106 `<meta name="generator" content="WP Rocket 3.23.3.3" data-wpr-features="wpr_delay`
- (×1) [error] Stray end tag “head”. — first at line 106 `esktop" /></head>
<body`
- (×1) [error] Start tag “body” seen but an element of the same type was already open. — first at line 107 `/></head>
<body class="home wp-singular page-template page-template-template-dyn`
- (×1) [error] Cannot recover after last error. Any further errors will be ignored. — first at line 107 `/></head>
<body class="home wp-singular page-template page-template-template-dyn`

### 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 1663 ms._

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

### Priority fixes
1. **landmark-unique** (medium) — Landmarks should have a unique role or role/label/title (i.e. accessible name) combination
2. **region** (medium) — All page content should be contained by landmarks

### Findings

#### `landmark-unique` (moderate)
[Landmarks should have a unique role or role/label/title (i.e. accessible name) combination](https://dequeuniversity.com/rules/axe/4.11/landmark-unique?application=playwright)
- `.header__nav`

#### `region` (moderate)
[All page content should be contained by landmarks](https://dequeuniversity.com/rules/axe/4.11/region?application=playwright)
- `.home-hero__main`
- `.home-hero__bottom`
- `canvas`
- `.keywords__mouse`
- `.keywords__intro`
- … and 31 more nodes

### Incomplete (axe could not determine)
- [Elements must meet minimum color contrast ratio thresholds](https://dequeuniversity.com/rules/axe/4.11/color-contrast?application=playwright) — 38 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 1676 ms._

**Capture summary:** 1 console events · 0 mixed-content requests · 13 network requests · 178.1 KB total

**Network bytes by resource type:**
| Type | Count | Bytes |
| --- | --- | --- |
| font | 3 | 57.6 KB |
| script | 4 | 45.6 KB |
| document | 1 | 34.6 KB |
| stylesheet | 2 | 34.2 KB |
| other | 1 | 5.5 KB |
| image | 1 | 576 B |
| xhr | 1 | 0 B |

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

**Slowest requests (top 5):**
- https://fast.fonts.net/t/1.css?apiType=css&projectid=d924b670-8ecc-46fd-9fff-80fd9989d037 (stylesheet) — 67 ms, 0 B
- https://play.ee/ (document) — 33 ms, 34.6 KB
- https://cdn.jsdelivr.net/gh/orestbida/iframemanager@1.3.0/dist/iframemanager.js (script) — 33 ms, 3.0 KB
- https://cdn.jsdelivr.net/gh/orestbida/cookieconsent@3.0.1/dist/cookieconsent.umd.js (script) — 32 ms, 10.1 KB
- https://play.ee/wp-content/themes/gotoandplay/inc/theme/js/jquery.bfe1bb19d13b3c17b682.min.js (script) — 31 ms, 31.5 KB

### Findings

#### Console events
- [warning] Couldn't load preload assets:  

### 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 1676 ms._

**Document:**
- Lang: en
- Title: Perfectly formed web development team - gotoAndPlay
- Canonical: https://play.ee/
- Viewport: width=device-width, initial-scale=1
- Charset: UTF-8
- HTML bytes: 218194

**Meta tags:**
- Description: Small, agile web development team working on big ideas in close collaboration with our clients. Result driven from day one!
- Robots: follow, index, max-snippet:-1, max-video-preview:-1, max-image-preview:large
- Theme color: #ffffff
- Open Graph tags: 7 (og:locale, og:type, og:title, og:description, og:url, og:site_name, og:updated_time)
- Twitter tags: 3
- hreflang:
  - en → http://play.ee/
  - et → http://play.ee/et/
  - x-default → http://play.ee/
- JSON-LD: 1 blocks (1 valid) — types: Unknown

**Heading outline:**
- Counts: h1 ×1, h2 ×6, h3 ×5, h4 ×0, h5 ×0, h6 ×0
- Sequence (first 20):
  - h1: we create memorable experiences with
        
                    web technologi
  - h2: Your result
  - h2: we offer
        
                    more than expected
  - h2: Üks
  - h2: meet the team of
        
                    uncommon talent
  - h2: proof to our approach are
        
                    happy clients
  - h3: Deliverables with high quality standards
  - h3: Working with gotoAndPlay is a great experience
  - h3: Speed, attitude, skills!
  - h3: Hardworking, fun & ready to adopt new technologies
  - h3: The sky is the limit
  - h2: take a look at our
        
                    
    case studies

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

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

External scripts (first 15):
- https://cdn.jsdelivr.net/gh/orestbida/iframemanager@1.3.0/dist/iframemanager.js (defer)
- https://cdn.jsdelivr.net/gh/orestbida/cookieconsent@3.0.1/dist/cookieconsent.umd.js (defer)
- https://play.ee/wp-content/themes/gotoandplay/inc/theme/js/runtime.30d3b226dcf211e512b1.min.js
- https://play.ee/wp-content/themes/gotoandplay/inc/theme/js/jquery.bfe1bb19d13b3c17b682.min.js (defer)

**Stylesheets:** 1 external, 3 inline (9.6 KB)

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

Image inventory (first 15):
| src | alt | w×h | loading | srcset |
| --- | --- | --- | --- | --- |
| ee/wp-content/themes/gotoandplay/inc/theme/img/landscape.svg | Please turn your device sideways | _n/a_ | _n/a_ | ✗ |
| %2Fsvg%22%20viewBox%3D%220%200%20360%20420%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| %2Fsvg%22%20viewBox%3D%220%200%20360%20420%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| %2Fsvg%22%20viewBox%3D%220%200%20360%20420%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| %2Fsvg%22%20viewBox%3D%220%200%20360%20420%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| %2Fsvg%22%20viewBox%3D%220%200%20360%20420%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| %2Fsvg%22%20viewBox%3D%220%200%20360%20420%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| %2Fsvg%22%20viewBox%3D%220%200%20360%20420%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| %2Fsvg%22%20viewBox%3D%220%200%20360%20420%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| %2Fsvg%22%20viewBox%3D%220%200%20360%20420%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| %2Fsvg%22%20viewBox%3D%220%200%20360%20420%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| %2Fsvg%22%20viewBox%3D%220%200%20360%20420%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| %2Fsvg%22%20viewBox%3D%220%200%20360%20420%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| %2Fsvg%22%20viewBox%3D%220%200%20360%20420%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| ;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== | _(empty)_ | _n/a_ | _n/a_ | ✗ |

**Links:** 46 anchors — 34 external, 1 preconnect, 0 preload.

Vague repeated link text:
- "read more" ×9
- "view our instagram feed" ×3
- "visit our facebook page" ×3
- "visit our linkedin page" ×3
- "eng" ×3
- "est" ×3
- "case studies" ×2
- "styleguide" ×2
- "privacy policy" ×2

**Forms:**
Form 1:
- text — labeled

### Priority fixes
1. **Missing skip-to-content link** (medium) — No anchor link with "skip" / "otse sisu" text found
2. **50 images without explicit width/height** (medium) — Missing dimensions can cause layout shifts (CLS)
3. **Vague link text repeated** (medium) — "read more" ×9

### 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 · 0 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 (37 SVGs, 13 placeholders excluded). |
| Hero image eagerly loaded | – n/a | No raster <img> elements found (37 SVGs, 13 placeholders excluded). |
| 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 (37 SVGs, 13 placeholders 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> | ✓ pass | No render-blocking scripts in <head>. |

**Evidence:**
- Page caching plugin / CDN active:
  - `HTML markers: WP Rocket`
  - `generator: WP Rocket 3.23.3.3`

### 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://play.ee/web-development-case-studies/

Run: 2026-09-01T12:09:47.644Z

## 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: no
- E-commerce: no

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

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

**Core Web Vitals — lab (Lighthouse) / field (CrUX p75); worse lab value bolded:**
| Metric | Mobile | Desktop |
| --- | --- | --- |
| LCP | **2.1 s** | 0.5 s |
| CLS | 0.005 | **0.005** |
| TBT | 0 ms | 0 ms |
| FCP | **1.98 s** | 527 ms |
| Speed Index | 1.98 s | **2.87 s** |
| TTFB | 3 ms | **4 ms** |

### Priority fixes
1. **first-contentful-paint** (low) — 2.0 s
2. **network-dependency-tree-insight** (high)
3. **render-blocking-insight** (high) — Est savings of 1,210 ms
4. **unused-css-rules** (high) — Est savings of 32 KiB
5. **unused-javascript** (medium) — Est savings of 23 KiB

### Findings (mobile)

#### Unused JavaScript
- https://play.ee/wp-content/themes/gotoandplay/inc/theme/js/jquery.bfe1bb19d13b3c17b682.min.js — 23 KB wasted

#### Layout-shift sources
- footer.footer > h2.heading > span.heading__main > a.link — shift 0.005

#### DOM size
- Total nodes: 0

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

#### All failing PSI audits (sorted by weight × failure margin)
- `color-contrast` (accessibility, score 0.00, weight 7) — Background and foreground colors do not have a sufficient contrast ratio.
- `landmark-one-main` (accessibility, score 0.00, weight 3) — Document does not have a main landmark.
- `first-contentful-paint` (performance, score 0.85, weight 10) — First Contentful Paint — 2.0 s
- `network-dependency-tree-insight` (performance, score 0.00, weight 0) — Network dependency tree
- `image-size-responsive` (best-practices, score 0.00, weight 1) — Serves images with low resolution

### 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 4257 ms._

**Transport:**
- Final URL: https://play.ee/web-development-case-studies/
- Status: 200
- Redirected: false
- HTTPS redirect: ✗ http://play.ee/web-development-case-studies/ does not redirect to HTTPS (target: none)

**Caching:**
- cache-control: `max-age=0`
- etag: n/a
- last-modified: Tue, 01 Sep 2026 12:09:51 GMT
- expires: Tue, 01 Sep 2026 12:09:47 GMT
- pragma: n/a
- vary: Accept-Encoding

**Compression:**
- content-encoding: gzip
- content-length: 27764
- Decoded body: 191.9 KB
- Compression ratio: 0.141

### Priority fixes
1. **HTTP does not redirect to HTTPS** (high) — http://play.ee/web-development-case-studies/ does not redirect to HTTPS
2. **strict-transport-security missing** (high) — Add HSTS with max-age >= 1 year, includeSubDomains, and preload
3. **content-security-policy weak** (high) — missing default-src; missing object-src 'none'; only frame-ancestors set — no script/resource restrictions
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

### Findings

#### Tracked headers
- **strict-transport-security** (missing, high)
- **content-security-policy** (weak, high) `frame-ancestors 'self';` — missing default-src; missing object-src 'none'; only frame-ancestors set — no script/resource restrictions
- **x-frame-options** (present, medium) `SAMEORIGIN`
- **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`
- X-Powered-By: `PHP/8.3.33`

#### All response headers
```
cache-control: max-age=0
connection: Upgrade, Keep-Alive
content-encoding: gzip
content-length: 27764
content-security-policy: frame-ancestors 'self';
content-type: text/html; charset=UTF-8
date: Tue, 01 Sep 2026 12:09:47 GMT
expires: Tue, 01 Sep 2026 12:09:47 GMT
keep-alive: timeout=5, max=100
last-modified: Tue, 01 Sep 2026 12:09:51 GMT
link: <https://play.ee/wp-json/>; rel="https://api.w.org/", <https://play.ee/wp-json/wp/v2/pages/2433>; rel="alternate"; title="JSON"; type="application/json", <https://play.ee/?p=2433>; rel=shortlink
server: Apache
upgrade: h2,h2c
vary: Accept-Encoding
x-content-security-policy: frame-ancestors 'self';block-all-mixed-content;default-src 'self';script-src 'self' 'report-sample' 'unsafe-inline' https:\/\/*.sentry.io https:\/\/browser.sentry-cdn.com https:\/\/googletagmanager.com https:\/\/js.sentry-cdn.com https:\/\/tagmanager.google.com https:\/\/www.googletagmanager.com;style-src 'self' 'report-sample' 'unsafe-inline' fast.fonts.net tagmanager.google.com www.googletagmanager.com;object-src 'none';frame-src 'self' www.googletagmanager.com;child-src 'self' www.googletagmanager.com;img-src 'self' data: www.googletagmanager.com;font-src 'self' data:;connect-src 'self' *.sentry.io www.googletagmanager.com;manifest-src 'self';base-uri 'self';form-action 'self';media-src 'self';prefetch-src 'self';worker-src 'self';
x-frame-options: SAMEORIGIN
x-powered-by: PHP/8.3.33
```

### 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 4991 ms._

**Scoring:** 7 errors · 0 warnings · 23 cosmetic (suppressed)

> **Validator truncated at line 105** — the Nu validator stopped after hitting its internal error budget; score against the errors above, NOT as a fatal parse failure: Cannot recover after last error. Any further errors will be ignored.

### Priority fixes
1. **Parser recovery at line 105** (high) — Cannot recover after last error. Any further errors will be ignored.
2. **Bad start tag in “iframe” in “noscript” in “head”.** (medium) — x1, first at line 102
3. **Stray end tag “noscript”.** (medium) — x1, first at line 102
4. **Attribute “name” not allowed on element “meta” at this point.** (medium) — x1, first at line 104
5. **Element “meta” is missing one or more of the following attributes: “itemprop”, “property”.** (medium) — x1, first at line 104

### Issue groups
- (×1) [error] Bad start tag in “iframe” in “noscript” in “head”. — first at line 102 `<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-K3P64XMJ"`
- (×1) [error] Stray end tag “noscript”. — first at line 102 `></iframe></noscript><!-- E`
- (×1) [error] Attribute “name” not allowed on element “meta” at this point. — first at line 104 `<meta name="generator" content="WP Rocket 3.23.3.3" data-wpr-features="wpr_delay`
- (×1) [error] Element “meta” is missing one or more of the following attributes: “itemprop”, “property”. — first at line 104 `<meta name="generator" content="WP Rocket 3.23.3.3" data-wpr-features="wpr_delay`
- (×1) [error] Stray end tag “head”. — first at line 104 `esktop" /></head>
<body`
- (×1) [error] Start tag “body” seen but an element of the same type was already open. — first at line 105 `/></head>
<body class="wp-singular page-template page-template-template-dynamic `
- (×1) [error] Cannot recover after last error. Any further errors will be ignored. — first at line 105 `/></head>
<body class="wp-singular page-template page-template-template-dynamic `

### 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 5738 ms._

**Scoring:** 3 violations · 28 passes · critical 0 · serious 1 · moderate 2 · minor 0

### Priority fixes
1. **color-contrast** (high) — Elements must meet minimum color contrast ratio thresholds
2. **landmark-unique** (medium) — Landmarks should have a unique role or role/label/title (i.e. accessible name) combination
3. **region** (medium) — All page content should be contained by landmarks

### Findings

#### `color-contrast` (serious) — WCAG: wcag2aa, wcag143
[Elements must meet minimum color contrast ratio thresholds](https://dequeuniversity.com/rules/axe/4.11/color-contrast?application=playwright)
- `h1 > .heading__main`
- `#case_study-20063 > .card__inner > .card__content > .card__meta`
- `#case_study-3610 > .card__inner > .card__content > .card__title.h4`
- `#case_study-3610 > .card__inner > .card__content > .card__meta`
- `#case_study-3420 > .card__inner > .card__content > .card__title.h4`
- … and 18 more nodes

#### `landmark-unique` (moderate)
[Landmarks should have a unique role or role/label/title (i.e. accessible name) combination](https://dequeuniversity.com/rules/axe/4.11/landmark-unique?application=playwright)
- `.header__nav`

#### `region` (moderate)
[All page content should be contained by landmarks](https://dequeuniversity.com/rules/axe/4.11/region?application=playwright)
- `h1`
- `.sidebar__title`
- `.sidebar__list`
- `.button__text`
- `#case_study-20063 > .card__inner > .card__content`
- … and 22 more nodes

### Incomplete (axe could not determine)
- [Elements must meet minimum color contrast ratio thresholds](https://dequeuniversity.com/rules/axe/4.11/color-contrast?application=playwright) — 9 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 5751 ms._

**Capture summary:** 1 console events · 0 mixed-content requests · 12 network requests · 170.0 KB total

**Network bytes by resource type:**
| Type | Count | Bytes |
| --- | --- | --- |
| font | 3 | 57.6 KB |
| script | 4 | 45.6 KB |
| stylesheet | 2 | 34.2 KB |
| document | 1 | 27.1 KB |
| other | 1 | 5.5 KB |
| xhr | 1 | 0 B |

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

**Slowest requests (top 5):**
- https://play.ee/web-development-case-studies/ (document) — 4.14 s, 27.1 KB
- https://cdn.jsdelivr.net/gh/orestbida/iframemanager@1.3.0/dist/iframemanager.js (script) — 28 ms, 3.0 KB
- https://cdn.jsdelivr.net/gh/orestbida/cookieconsent@3.0.1/dist/cookieconsent.umd.js (script) — 28 ms, 10.1 KB
- https://fast.fonts.net/t/1.css?apiType=css&projectid=d924b670-8ecc-46fd-9fff-80fd9989d037 (stylesheet) — 23 ms, 0 B
- https://play.ee/wp-content/themes/gotoandplay/inc/theme/js/runtime.30d3b226dcf211e512b1.min.js (script) — 20 ms, 1.0 KB

### Findings

#### Console events
- [warning] Couldn't load preload assets:  

### 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 5751 ms._

**Document:**
- Lang: en
- Title: Case studies of the web development company gotoAndPlay
- Canonical: https://play.ee/web-development-case-studies/
- Viewport: width=device-width, initial-scale=1
- Charset: UTF-8
- HTML bytes: 193345

**Meta tags:**
- Description: Read about the different web development projects of gotoAndPlay. Find out more about the process, challenges and results of our work.
- Robots: follow, index, max-snippet:-1, max-video-preview:-1, max-image-preview:large
- Theme color: #ffffff
- Open Graph tags: 7 (og:locale, og:type, og:title, og:description, og:url, og:site_name, og:updated_time)
- Twitter tags: 3
- hreflang:
  - en → https://play.ee/web-development-case-studies/
  - et → https://play.ee/et/tehtud-tood/
  - x-default → https://play.ee/web-development-case-studies/
- JSON-LD: 1 blocks (1 valid) — types: Unknown

**Heading outline:**
- Counts: h1 ×1, h2 ×22, h3 ×0, h4 ×0, h5 ×0, h6 ×0
- Sequence (first 20):
  - h1: take a look at our
        
                    featured projects
  - h2: by client
  - h2: unlocking the future of trailer sharing
  - h2: a digital glow-up for one of Estonia’s top furniture retailers
  - h2: coding a healthier future
  - h2: building cyber bridges
  - h2: navigating digital waters
  - h2: egg-citing digital transformation
  - h2: heating up the web with a new site
  - h2: bringing a breath of fresh air to office environments
  - h2: Swooshing through the ERP world using Katana
  - h2: three interwoven websites for a single pizza franchise
  - h2: A web ecosystem for the most unique cinema in town
  - h2: website for a top tier law firm
  - h2: A handcrafted sofa for your living room
  - h2: a total makeover for a business that will never cease to exist
  - h2: a modular webpage for a company that has their sight set on the future
  - h2: a high security web application for keeping an eye on your finances
  - h2: Award winning website for 21st century home
  - h2: Stress-free tutoring with tutor.id web application

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

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

External scripts (first 15):
- https://cdn.jsdelivr.net/gh/orestbida/iframemanager@1.3.0/dist/iframemanager.js (defer)
- https://cdn.jsdelivr.net/gh/orestbida/cookieconsent@3.0.1/dist/cookieconsent.umd.js (defer)
- https://play.ee/wp-content/themes/gotoandplay/inc/theme/js/runtime.30d3b226dcf211e512b1.min.js
- https://play.ee/wp-content/themes/gotoandplay/inc/theme/js/jquery.bfe1bb19d13b3c17b682.min.js (defer)

**Stylesheets:** 1 external, 3 inline (9.6 KB)

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

Image inventory (first 15):
| src | alt | w×h | loading | srcset |
| --- | --- | --- | --- | --- |
| %2Fsvg%22%20viewBox%3D%220%200%20300%20240%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| ;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| ;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| %2Fsvg%22%20viewBox%3D%220%200%20300%20240%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| ;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| ;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| %2Fsvg%22%20viewBox%3D%220%200%20300%20240%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| ;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| ;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| %2Fsvg%22%20viewBox%3D%220%200%20300%20240%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| ;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| ;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| %2Fsvg%22%20viewBox%3D%220%200%20300%20240%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| ;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| %2Fsvg%22%20viewBox%3D%220%200%20300%20240%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |

**Links:** 69 anchors — 14 external, 1 preconnect, 0 preload.

Vague repeated link text:
- "view our instagram feed" ×3
- "visit our facebook page" ×3
- "visit our linkedin page" ×3
- "eng" ×3
- "est" ×3
- "styleguide" ×2
- "privacy policy" ×2

### Priority fixes
1. **Missing skip-to-content link** (medium) — No anchor link with "skip" / "otse sisu" text found
2. **56 images without explicit width/height** (medium) — Missing dimensions can cause layout shifts (CLS)

### 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 · 0 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 (20 SVGs, 36 placeholders excluded). |
| Hero image eagerly loaded | – n/a | No raster <img> elements found (20 SVGs, 36 placeholders excluded). |
| 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 (20 SVGs, 36 placeholders 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> | ✓ pass | No render-blocking scripts in <head>. |

**Evidence:**
- Page caching plugin / CDN active:
  - `HTML markers: WP Rocket`
  - `generator: WP Rocket 3.23.3.3`

### 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://play.ee/software-development-work-index/

Run: 2026-09-01T12:10:23.596Z

## 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: no
- E-commerce: no

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

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

**Core Web Vitals — lab (Lighthouse) / field (CrUX p75); worse lab value bolded:**
| Metric | Mobile | Desktop |
| --- | --- | --- |
| LCP | **2.3 s** | 0.6 s |
| CLS | **0.041** | 0.004 |
| TBT | 0 ms | 0 ms |
| FCP | **1.96 s** | 582 ms |
| Speed Index | **1.96 s** | 600 ms |
| TTFB | 8 ms | **41 ms** |

### Priority fixes
1. **first-contentful-paint** (low) — 2.0 s
2. **network-dependency-tree-insight** (high)
3. **render-blocking-insight** (high) — Est savings of 1,060 ms
4. **unused-css-rules** (high) — Est savings of 32 KiB
5. **unused-javascript** (medium) — Est savings of 23 KiB

### Findings (mobile)

#### Unused JavaScript
- https://play.ee/wp-content/themes/gotoandplay/inc/theme/js/jquery.bfe1bb19d13b3c17b682.min.js — 23 KB wasted

#### Layout-shift sources
- div.section__inner > div.section__content > div.h-container > div.grid — shift 0.041

#### DOM size
- Total nodes: 0

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

#### All failing PSI audits (sorted by weight × failure margin)
- `color-contrast` (accessibility, score 0.00, weight 7) — Background and foreground colors do not have a sufficient contrast ratio.
- `landmark-one-main` (accessibility, score 0.00, weight 3) — Document does not have a main landmark.
- `first-contentful-paint` (performance, score 0.85, weight 10) — First Contentful Paint — 2.0 s
- `network-dependency-tree-insight` (performance, score 0.00, weight 0) — Network dependency tree
- `image-size-responsive` (best-practices, score 0.00, weight 1) — Serves images with low resolution

### 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 40 ms._

**Transport:**
- Final URL: https://play.ee/software-development-work-index/
- Status: 200
- Redirected: false
- HTTPS redirect: ✗ http://play.ee/software-development-work-index/ does not redirect to HTTPS (target: none)

**Caching:**
- cache-control: `max-age=0`
- etag: n/a
- last-modified: Tue, 01 Sep 2026 08:40:05 GMT
- expires: Tue, 01 Sep 2026 12:10:23 GMT
- pragma: n/a
- vary: Accept-Encoding

**Compression:**
- content-encoding: gzip
- content-length: 32134
- Decoded body: 271.3 KB
- Compression ratio: 0.116

### Priority fixes
1. **HTTP does not redirect to HTTPS** (high) — http://play.ee/software-development-work-index/ does not redirect to HTTPS
2. **strict-transport-security missing** (high) — Add HSTS with max-age >= 1 year, includeSubDomains, and preload
3. **content-security-policy weak** (high) — missing default-src; missing object-src 'none'; only frame-ancestors set — no script/resource restrictions
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

### Findings

#### Tracked headers
- **strict-transport-security** (missing, high)
- **content-security-policy** (weak, high) `frame-ancestors 'self';` — missing default-src; missing object-src 'none'; only frame-ancestors set — no script/resource restrictions
- **x-frame-options** (present, medium) `SAMEORIGIN`
- **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`
- X-Powered-By: `PHP/8.3.33`

#### All response headers
```
cache-control: max-age=0
connection: Upgrade, Keep-Alive
content-encoding: gzip
content-length: 32134
content-security-policy: frame-ancestors 'self';
content-type: text/html; charset=UTF-8
date: Tue, 01 Sep 2026 12:10:23 GMT
expires: Tue, 01 Sep 2026 12:10:23 GMT
keep-alive: timeout=5, max=100
last-modified: Tue, 01 Sep 2026 08:40:05 GMT
server: Apache
upgrade: h2,h2c
vary: Accept-Encoding
x-frame-options: SAMEORIGIN
x-powered-by: PHP/8.3.33
```

### 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 957 ms._

**Scoring:** 8 errors · 0 warnings · 23 cosmetic (suppressed)

> **Validator truncated at line 106** — the Nu validator stopped after hitting its internal error budget; score against the errors above, NOT as a fatal parse failure: Cannot recover after last error. Any further errors will be ignored.

### Priority fixes
1. **Parser recovery at line 106** (high) — Cannot recover after last error. Any further errors will be ignored.
2. **Bad value “” for attribute “href” on element “link”: Must be non-empty.** (medium) — x1, first at line 52
3. **Bad start tag in “iframe” in “noscript” in “head”.** (medium) — x1, first at line 103
4. **Stray end tag “noscript”.** (medium) — x1, first at line 103
5. **Attribute “name” not allowed on element “meta” at this point.** (medium) — x1, first at line 105

### Issue groups
- (×1) [error] Bad value “” for attribute “href” on element “link”: Must be non-empty. — first at line 52 `refetch">
<link data-rocket-prefetch href="" rel="dns-prefetch">
<link`
- (×1) [error] Bad start tag in “iframe” in “noscript” in “head”. — first at line 103 `<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-K3P64XMJ"`
- (×1) [error] Stray end tag “noscript”. — first at line 103 `></iframe></noscript><!-- E`
- (×1) [error] Attribute “name” not allowed on element “meta” at this point. — first at line 105 `<meta name="generator" content="WP Rocket 3.23.3.3" data-wpr-features="wpr_delay`
- (×1) [error] Element “meta” is missing one or more of the following attributes: “itemprop”, “property”. — first at line 105 `<meta name="generator" content="WP Rocket 3.23.3.3" data-wpr-features="wpr_delay`
- (×1) [error] Stray end tag “head”. — first at line 105 `esktop" /></head>
<body`
- (×1) [error] Start tag “body” seen but an element of the same type was already open. — first at line 106 `/></head>
<body class="wp-singular page-template page-template-template-dynamic `
- (×1) [error] Cannot recover after last error. Any further errors will be ignored. — first at line 106 `/></head>
<body class="wp-singular page-template page-template-template-dynamic `

### 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 2002 ms._

**Scoring:** 3 violations · 26 passes · critical 0 · serious 1 · moderate 2 · minor 0

### Priority fixes
1. **color-contrast** (high) — Elements must meet minimum color contrast ratio thresholds
2. **landmark-unique** (medium) — Landmarks should have a unique role or role/label/title (i.e. accessible name) combination
3. **region** (medium) — All page content should be contained by landmarks

### Findings

#### `color-contrast` (serious) — WCAG: wcag2aa, wcag143
[Elements must meet minimum color contrast ratio thresholds](https://dequeuniversity.com/rules/axe/4.11/color-contrast?application=playwright)
- `h1 > .heading__main`
- `p:nth-child(1) > span`

#### `landmark-unique` (moderate)
[Landmarks should have a unique role or role/label/title (i.e. accessible name) combination](https://dequeuniversity.com/rules/axe/4.11/landmark-unique?application=playwright)
- `.header__nav`

#### `region` (moderate)
[All page content should be contained by landmarks](https://dequeuniversity.com/rules/axe/4.11/region?application=playwright)
- `h1`
- `.project-index__row.grid__col:nth-child(1) > .grid--middle.grid > .grid__col--last-xs.grid__col--original-sm.grid__col--sm-6`
- `.project-index__row.grid__col:nth-child(1) > .grid--middle.grid > .grid__col--sm-6.grid__col:nth-child(2) > .grid--no-wrap.grid--middle.grid > .grid__col--min.grid__col`
- `.project-index__link[href$="ehl.ee/"][target="_blank"]`
- `.has-link.project-index__row.grid__col:nth-child(2) > .grid--middle.grid > .grid__col--last-xs.grid__col--original-sm.grid__col--sm-6 > .project-index__heading`
- … and 147 more nodes

### Incomplete (axe could not determine)
- [Elements must meet minimum color contrast ratio thresholds](https://dequeuniversity.com/rules/axe/4.11/color-contrast?application=playwright) — 10 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 2020 ms._

**Capture summary:** 1 console events · 0 mixed-content requests · 12 network requests · 174.3 KB total

**Network bytes by resource type:**
| Type | Count | Bytes |
| --- | --- | --- |
| font | 3 | 57.6 KB |
| script | 4 | 45.6 KB |
| stylesheet | 2 | 34.2 KB |
| document | 1 | 31.4 KB |
| other | 1 | 5.5 KB |
| xhr | 1 | 0 B |

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

**Slowest requests (top 5):**
- https://fast.fonts.net/t/1.css?apiType=css&projectid=d924b670-8ecc-46fd-9fff-80fd9989d037 (stylesheet) — 30 ms, 0 B
- https://cdn.jsdelivr.net/gh/orestbida/iframemanager@1.3.0/dist/iframemanager.js (script) — 28 ms, 3.0 KB
- https://play.ee/wp-content/themes/gotoandplay/inc/theme/fonts/1c0243aa-c535-4d42-ac53-d6f0f74a1412.bd94708352cbb3b4863c.woff2 (font) — 28 ms, 19.3 KB
- https://play.ee/wp-content/themes/gotoandplay/inc/theme/fonts/fc2fa85e-cd2d-4004-930a-8adad6c60317.3bd2a5f3705d9fb438c5.woff2 (font) — 28 ms, 19.3 KB
- https://play.ee/wp-content/themes/gotoandplay/inc/theme/fonts/f389f79b-6013-4448-aa6a-b6fd235eab80.b91a05bafb09e626383a.woff2 (font) — 28 ms, 19.0 KB

### Findings

#### Console events
- [warning] Couldn't load preload assets:  

### 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 2020 ms._

**Document:**
- Lang: en
- Title: High-quality software development – from idea to launch
- Canonical: https://play.ee/software-development-work-index/
- Viewport: width=device-width, initial-scale=1
- Charset: UTF-8
- HTML bytes: 274492

**Meta tags:**
- Description: Our focus is on web application, website and software development, utilizing top-tier technologies such as Laravel, React, and Node.js.
- Robots: follow, index, max-snippet:-1, max-video-preview:-1, max-image-preview:large
- Theme color: #ffffff
- Open Graph tags: 7 (og:locale, og:type, og:title, og:description, og:url, og:site_name, og:updated_time)
- Twitter tags: 3
- hreflang:
  - en → https://play.ee/software-development-work-index/
  - et → https://play.ee/et/tarkvaraarendus-saavutuste-indeks/
  - x-default → https://play.ee/software-development-work-index/
- JSON-LD: 1 blocks (1 valid) — types: Unknown

**Heading outline:**
- Counts: h1 ×1, h2 ×30, h3 ×0, h4 ×0, h5 ×0, h6 ×0
- Sequence (first 20):
  - h1: highlights from the
        
                    last couple of years
  - h2: Future-proof software development for Tallink
  - h2: Built on years of trust – the EHL web transformation
  - h2: Web experience capturing the spirit and energy of Tallinn City Theatre
  - h2: Building the future of Estonian engineering with a next-gen web experience
  - h2: New website for a new perspective
  - h2: Risk management portal for IUTE
  - h2: Unlocking the future of trailer sharing
  - h2: Smart web for smart lockers
  - h2: WordPress website for Forus
  - h2: A new website for Coop Pank that offers the best experience for their customers
  - h2: Bringing together cybersecurity experts and stakeholders
  - h2: Auctions platform MVP for Foxway
  - h2: Going beyond the benchmark with Katana website
  - h2: Web application for a green energy marketplace
  - h2: Custom tailored PIM for Telia Eesti
  - h2: Back-office system for arthouse cinema
  - h2: Updating a webpage for most stylish quarter in Tallinn
  - h2: Amplifying the future with Low Noise Factory
  - h2: Just like Airbnb, but for trailers

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

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

External scripts (first 15):
- https://cdn.jsdelivr.net/gh/orestbida/iframemanager@1.3.0/dist/iframemanager.js (defer)
- https://cdn.jsdelivr.net/gh/orestbida/cookieconsent@3.0.1/dist/cookieconsent.umd.js (defer)
- https://play.ee/wp-content/themes/gotoandplay/inc/theme/js/runtime.30d3b226dcf211e512b1.min.js
- https://play.ee/wp-content/themes/gotoandplay/inc/theme/js/jquery.bfe1bb19d13b3c17b682.min.js (defer)

**Stylesheets:** 1 external, 3 inline (9.6 KB)

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

Image inventory (first 15):
| src | alt | w×h | loading | srcset |
| --- | --- | --- | --- | --- |
| ;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| %2Fsvg%22%20viewBox%3D%220%200%20352%20264%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| ;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| %2Fsvg%22%20viewBox%3D%220%200%20352%20264%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| ;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| %2Fsvg%22%20viewBox%3D%220%200%20352%20264%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| ;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| %2Fsvg%22%20viewBox%3D%220%200%20352%20264%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| ;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| ;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| %2Fsvg%22%20viewBox%3D%220%200%20352%20264%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| ;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| %2Fsvg%22%20viewBox%3D%220%200%20352%20264%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| ;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| %2Fsvg%22%20viewBox%3D%220%200%20352%20264%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |

**Links:** 94 anchors — 76 external, 1 preconnect, 0 preload.

Vague repeated link text:
- "visit the website" ×21
- "visit website" ×21
- "read more about the project" ×15
- "view our instagram feed" ×3
- "visit our facebook page" ×3
- "visit our linkedin page" ×3
- "eng" ×3
- "est" ×3
- "read the case study" ×3
- "read case study" ×3

### Priority fixes
1. **Missing skip-to-content link** (medium) — No anchor link with "skip" / "otse sisu" text found
2. **53 images without explicit width/height** (medium) — Missing dimensions can cause layout shifts (CLS)
3. **Vague link text repeated** (medium) — "read more about the project" ×15, "read more about futuclass" ×3

### 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 · 0 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 (24 SVGs, 29 placeholders excluded). |
| Hero image eagerly loaded | – n/a | No raster <img> elements found (24 SVGs, 29 placeholders excluded). |
| 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 (24 SVGs, 29 placeholders 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> | ✓ pass | No render-blocking scripts in <head>. |

**Evidence:**
- Page caching plugin / CDN active:
  - `HTML markers: WP Rocket`
  - `generator: WP Rocket 3.23.3.3`

### 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://play.ee/wordpress-support-service/

Run: 2026-09-01T12:10:27.891Z

## 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: no
- E-commerce: no

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

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

**Core Web Vitals — lab (Lighthouse) / field (CrUX p75); worse lab value bolded:**
| Metric | Mobile | Desktop |
| --- | --- | --- |
| LCP | **2.6 s** | 0.5 s |
| CLS | 0.000 | **0.002** |
| TBT | 0 ms | 0 ms |
| FCP | **1.96 s** | 526 ms |
| Speed Index | **4.07 s** | 526 ms |
| TTFB | **35 ms** | 4 ms |

### Priority fixes
1. **largest-contentful-paint** (low) — 2.6 s
2. **speed-index** (low) — 4.1 s
3. **first-contentful-paint** (low) — 2.0 s
4. **network-dependency-tree-insight** (high)
5. **render-blocking-insight** (high) — Est savings of 1,270 ms

### Findings (mobile)

#### Unused JavaScript
- https://play.ee/wp-content/themes/gotoandplay/inc/theme/js/jquery.bfe1bb19d13b3c17b682.min.js — 23 KB wasted

#### DOM size
- Total nodes: 0

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

#### All failing PSI audits (sorted by weight × failure margin)
- `color-contrast` (accessibility, score 0.00, weight 7) — Background and foreground colors do not have a sufficient contrast ratio.
- `link-name` (accessibility, score 0.00, weight 7) — Links do not have a discernible name
- `largest-contentful-paint` (performance, score 0.88, weight 25) — Largest Contentful Paint — 2.6 s
- `speed-index` (performance, score 0.80, weight 10) — Speed Index — 4.1 s
- `first-contentful-paint` (performance, score 0.85, weight 10) — First Contentful Paint — 2.0 s
- `network-dependency-tree-insight` (performance, score 0.00, weight 0) — Network dependency tree

### 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 42 ms._

**Transport:**
- Final URL: https://play.ee/wordpress-support-service/
- Status: 200
- Redirected: false
- HTTPS redirect: ✗ http://play.ee/wordpress-support-service/ does not redirect to HTTPS (target: none)

**Caching:**
- cache-control: `max-age=0`
- etag: n/a
- last-modified: Tue, 01 Sep 2026 09:46:03 GMT
- expires: Tue, 01 Sep 2026 12:10:27 GMT
- pragma: n/a
- vary: Accept-Encoding

**Compression:**
- content-encoding: gzip
- content-length: 31014
- Decoded body: 184.1 KB
- Compression ratio: 0.165

### Priority fixes
1. **HTTP does not redirect to HTTPS** (high) — http://play.ee/wordpress-support-service/ does not redirect to HTTPS
2. **strict-transport-security missing** (high) — Add HSTS with max-age >= 1 year, includeSubDomains, and preload
3. **content-security-policy weak** (high) — missing default-src; missing object-src 'none'; only frame-ancestors set — no script/resource restrictions
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

### Findings

#### Tracked headers
- **strict-transport-security** (missing, high)
- **content-security-policy** (weak, high) `frame-ancestors 'self';` — missing default-src; missing object-src 'none'; only frame-ancestors set — no script/resource restrictions
- **x-frame-options** (present, medium) `SAMEORIGIN`
- **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`
- X-Powered-By: `PHP/8.3.33`

#### All response headers
```
cache-control: max-age=0
connection: Upgrade, Keep-Alive
content-encoding: gzip
content-length: 31014
content-security-policy: frame-ancestors 'self';
content-type: text/html; charset=UTF-8
date: Tue, 01 Sep 2026 12:10:27 GMT
expires: Tue, 01 Sep 2026 12:10:27 GMT
keep-alive: timeout=5, max=100
last-modified: Tue, 01 Sep 2026 09:46:03 GMT
server: Apache
upgrade: h2,h2c
vary: Accept-Encoding
x-frame-options: SAMEORIGIN
x-powered-by: PHP/8.3.33
```

### 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 728 ms._

**Scoring:** 7 errors · 0 warnings · 30 cosmetic (suppressed)

> **Validator truncated at line 107** — the Nu validator stopped after hitting its internal error budget; score against the errors above, NOT as a fatal parse failure: Cannot recover after last error. Any further errors will be ignored.

### Priority fixes
1. **Parser recovery at line 107** (high) — Cannot recover after last error. Any further errors will be ignored.
2. **Bad start tag in “iframe” in “noscript” in “head”.** (medium) — x1, first at line 104
3. **Stray end tag “noscript”.** (medium) — x1, first at line 104
4. **Attribute “name” not allowed on element “meta” at this point.** (medium) — x1, first at line 106
5. **Element “meta” is missing one or more of the following attributes: “itemprop”, “property”.** (medium) — x1, first at line 106

### Issue groups
- (×1) [error] Bad start tag in “iframe” in “noscript” in “head”. — first at line 104 `<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-K3P64XMJ"`
- (×1) [error] Stray end tag “noscript”. — first at line 104 `></iframe></noscript><!-- E`
- (×1) [error] Attribute “name” not allowed on element “meta” at this point. — first at line 106 `<meta name="generator" content="WP Rocket 3.23.3.3" data-wpr-features="wpr_delay`
- (×1) [error] Element “meta” is missing one or more of the following attributes: “itemprop”, “property”. — first at line 106 `<meta name="generator" content="WP Rocket 3.23.3.3" data-wpr-features="wpr_delay`
- (×1) [error] Stray end tag “head”. — first at line 106 `mobile" /></head>
<body`
- (×1) [error] Start tag “body” seen but an element of the same type was already open. — first at line 107 `/></head>
<body class="wp-singular page-template page-template-template-dynamic `
- (×1) [error] Cannot recover after last error. Any further errors will be ignored. — first at line 107 `/></head>
<body class="wp-singular page-template page-template-template-dynamic `

### 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 2077 ms._

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

### Priority fixes
1. **color-contrast** (high) — Elements must meet minimum color contrast ratio thresholds
2. **link-name** (high) — Links must have discernible text
3. **landmark-unique** (medium) — Landmarks should have a unique role or role/label/title (i.e. accessible name) combination
4. **region** (medium) — All page content should be contained by landmarks

### Findings

#### `color-contrast` (serious) — WCAG: wcag2aa, wcag143
[Elements must meet minimum color contrast ratio thresholds](https://dequeuniversity.com/rules/axe/4.11/color-contrast?application=playwright)
- `.button--tertiary > .button__inner > .button__text`
- `.grid__col--md-4.capabilities__grid-col.grid__col--sm-6:nth-child(1) > .heading--h5.capabilities__heading.h5 > .heading__small`
- `.grid__col--md-4.capabilities__grid-col.grid__col--sm-6:nth-child(2) > .heading--h5.capabilities__heading.h5 > .heading__small`
- `.grid__col--md-4.capabilities__grid-col.grid__col--sm-6:nth-child(3) > .heading--h5.capabilities__heading.h5 > .heading__small`
- `.grid__col--md-4.capabilities__grid-col.grid__col--sm-6:nth-child(4) > .heading--h5.capabilities__heading.h5 > .heading__small`
- … and 10 more nodes

#### `landmark-unique` (moderate)
[Landmarks should have a unique role or role/label/title (i.e. accessible name) combination](https://dequeuniversity.com/rules/axe/4.11/landmark-unique?application=playwright)
- `.header__nav`

#### `link-name` (serious) — WCAG: wcag2a, wcag244, wcag412
[Links must have discernible text](https://dequeuniversity.com/rules/axe/4.11/link-name?application=playwright)
- `.logo-grid__row.js-in-viewport:nth-child(1) > .logo-grid__item:nth-child(1) > .logo-grid__link[href=""][rel="noopener"]`
- `.logo-grid__row.js-in-viewport:nth-child(1) > .logo-grid__item:nth-child(2) > .logo-grid__link[href=""][rel="noopener"]`
- `.logo-grid__row.js-in-viewport:nth-child(1) > .logo-grid__item:nth-child(3) > .logo-grid__link[href=""][rel="noopener"]`
- `.logo-grid__row.js-in-viewport:nth-child(2) > .logo-grid__item:nth-child(1) > .logo-grid__link[href=""][rel="noopener"]`
- `.logo-grid__row.js-in-viewport:nth-child(2) > .logo-grid__item:nth-child(2) > .logo-grid__link[href=""][rel="noopener"]`
- … and 4 more nodes

#### `region` (moderate)
[All page content should be contained by landmarks](https://dequeuniversity.com/rules/axe/4.11/region?application=playwright)
- `.contact-hero__intro > h1`
- `.intro__content > p:nth-child(2)`
- `p:nth-child(3)`
- `.button--tertiary`
- `canvas`
- … and 95 more nodes

### Incomplete (axe could not determine)
- [Elements must meet minimum color contrast ratio thresholds](https://dequeuniversity.com/rules/axe/4.11/color-contrast?application=playwright) — 15 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 2087 ms._

**Capture summary:** 1 console events · 0 mixed-content requests · 24 network requests · 201.9 KB total

**Network bytes by resource type:**
| Type | Count | Bytes |
| --- | --- | --- |
| font | 3 | 57.6 KB |
| script | 5 | 53.5 KB |
| stylesheet | 2 | 34.2 KB |
| document | 1 | 30.3 KB |
| image | 11 | 20.8 KB |
| other | 1 | 5.5 KB |
| xhr | 1 | 0 B |

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

**Slowest requests (top 5):**
- https://play.ee/wp-content/themes/gotoandplay/inc/theme/fonts/f389f79b-6013-4448-aa6a-b6fd235eab80.b91a05bafb09e626383a.woff2 (font) — 220 ms, 19.0 KB
- https://play.ee/wp-content/themes/gotoandplay/inc/theme/fonts/fc2fa85e-cd2d-4004-930a-8adad6c60317.3bd2a5f3705d9fb438c5.woff2 (font) — 219 ms, 19.3 KB
- https://cdn.jsdelivr.net/gh/orestbida/iframemanager@1.3.0/dist/iframemanager.js (script) — 27 ms, 3.0 KB
- https://cdn.jsdelivr.net/gh/orestbida/cookieconsent@3.0.1/dist/cookieconsent.umd.js (script) — 25 ms, 10.1 KB
- https://play.ee/wordpress-support-service/ (document) — 24 ms, 30.3 KB

### Findings

#### Console events
- [warning] Couldn't load preload assets:  

### 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 2087 ms._

**Document:**
- Lang: en
- Title: WordPress support service
- Canonical: https://play.ee/wordpress-support-service/
- Viewport: width=device-width, initial-scale=1
- Charset: UTF-8
- HTML bytes: 187226

**Meta tags:**
- Description: From ongoing WordPress support to health monitoring and expert fixes, we take care of your website so you can spend more time building your business.
- Robots: follow, index, max-snippet:-1, max-video-preview:-1, max-image-preview:large
- Theme color: #ffffff
- Open Graph tags: 13 (og:locale, og:type, og:title, og:description, og:url, og:site_name, og:updated_time, og:image, og:image:secure_url, og:image:width, og:image:height, og:image:alt, og:image:type)
- Twitter tags: 4
- hreflang:
  - en → https://play.ee/wordpress-support-service/
  - et → https://play.ee/et/tugiteenus/
  - x-default → https://play.ee/wordpress-support-service/
- JSON-LD: 1 blocks (1 valid) — types: Unknown

**Heading outline:**
- Counts: h1 ×2, h2 ×16, h3 ×14, h4 ×0, h5 ×0, h6 ×0
- Sequence (first 20):
  - h1: Your worry-free
        
                    WordPress website
  - h2: Why choose our
        
                    WordPress support service
  - h3: #1
        
                    peace of mind
  - h3: #2
        
                    security first
  - h3: #3
        
                    expert team on-call
  - h3: #4
        
                    performance wins
  - h3: #5
        
                    save money
  - h3: #6
        
                    monthly health reports
  - h3: #7
        
                    collaboration
  - h3: #8
        
                    extensive network
  - h3: #9
        
                    top notch tools
  - h2: service by professionals who
        
                    build websites for a l
  - h2: customizable & transparent
        
                    Pricing
  - h2: <Basic/>
  - h2: <Advanced/>
  - h2: <Pro/>
  - h2: five-step
        
                    onboarding process
  - h1: additional services
        
                    to upgrade your online presence
  - h2: UX/UI audit
  - h2: WCAG audit

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

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

External scripts (first 15):
- https://cdn.jsdelivr.net/gh/orestbida/iframemanager@1.3.0/dist/iframemanager.js (defer)
- https://cdn.jsdelivr.net/gh/orestbida/cookieconsent@3.0.1/dist/cookieconsent.umd.js (defer)
- https://play.ee/wp-content/themes/gotoandplay/inc/theme/js/runtime.30d3b226dcf211e512b1.min.js
- https://play.ee/wp-content/themes/gotoandplay/inc/theme/js/jquery.bfe1bb19d13b3c17b682.min.js (defer)
- https://play.ee/wp-content/plugins/wp-rocket/assets/js/wpr-beacon.min.js (async)

**Stylesheets:** 1 external, 3 inline (9.6 KB)

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

Image inventory (first 15):
| src | alt | w×h | loading | srcset |
| --- | --- | --- | --- | --- |
| ;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== | Expert WordPress support service | _n/a_ | _n/a_ | ✗ |
| p-content/themes/gotoandplay/inc/theme/img/line-1-mobile.svg | line-1 | _n/a_ | _n/a_ | ✗ |
| ay.ee/wp-content/themes/gotoandplay/inc/theme/img/line-1.svg | line-1 | _n/a_ | _n/a_ | ✗ |
| p-content/themes/gotoandplay/inc/theme/img/line-2-mobile.svg | line-2 | _n/a_ | _n/a_ | ✗ |
| ay.ee/wp-content/themes/gotoandplay/inc/theme/img/line-2.svg | line-2 | _n/a_ | _n/a_ | ✗ |
| p-content/themes/gotoandplay/inc/theme/img/line-3-mobile.svg | line-3 | _n/a_ | _n/a_ | ✗ |
| ay.ee/wp-content/themes/gotoandplay/inc/theme/img/line-3.svg | line-3 | _n/a_ | _n/a_ | ✗ |
| p-content/themes/gotoandplay/inc/theme/img/line-4-mobile.svg | line-4 | _n/a_ | _n/a_ | ✗ |
| ay.ee/wp-content/themes/gotoandplay/inc/theme/img/line-4.svg | line-4 | _n/a_ | _n/a_ | ✗ |
| p-content/themes/gotoandplay/inc/theme/img/line-5-mobile.svg | line-5 | _n/a_ | _n/a_ | ✗ |
| ay.ee/wp-content/themes/gotoandplay/inc/theme/img/line-5.svg | line-5 | _n/a_ | _n/a_ | ✗ |
| ;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| ;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| ;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| ;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== | _(empty)_ | _n/a_ | _n/a_ | ✗ |

**Links:** 57 anchors — 17 external, 2 preconnect, 0 preload.

Vague repeated link text:
- "get in touch" ×14
- "view our instagram feed" ×3
- "visit our facebook page" ×3
- "visit our linkedin page" ×3
- "eng" ×3
- "est" ×3
- "styleguide" ×2
- "privacy policy" ×2

### Priority fixes
1. **Document has 2 <h1> elements** (medium) — A page should have exactly one h1; multiple h1s break document outline
2. **Missing skip-to-content link** (medium) — No anchor link with "skip" / "otse sisu" text found
3. **31 images without explicit width/height** (medium) — Missing dimensions can cause layout shifts (CLS)

### 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 · 0 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 (24 SVGs, 7 placeholders excluded). |
| Hero image eagerly loaded | – n/a | No raster <img> elements found (24 SVGs, 7 placeholders excluded). |
| 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 (24 SVGs, 7 placeholders 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> | ✓ pass | No render-blocking scripts in <head>. |

**Evidence:**
- Page caching plugin / CDN active:
  - `HTML markers: WP Rocket`
  - `generator: WP Rocket 3.23.3.3`

### 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://play.ee/web-development-in-estonia/

Run: 2026-09-01T12:11:03.825Z

## 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: no
- E-commerce: no

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

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

**Core Web Vitals — lab (Lighthouse) / field (CrUX p75); worse lab value bolded:**
| Metric | Mobile | Desktop |
| --- | --- | --- |
| LCP | **2.4 s** | 0.6 s |
| CLS | 0.002 | **0.006** |
| TBT | 0 ms | 0 ms |
| FCP | **1.95 s** | 485 ms |
| Speed Index | **1.95 s** | 627 ms |
| TTFB | **9 ms** | 4 ms |

### Priority fixes
1. **first-contentful-paint** (low) — 2.0 s
2. **network-dependency-tree-insight** (high)
3. **render-blocking-insight** (high) — Est savings of 1,050 ms
4. **unused-css-rules** (high) — Est savings of 31 KiB
5. **unused-javascript** (medium) — Est savings of 23 KiB

### Findings (mobile)

#### Unused JavaScript
- https://play.ee/wp-content/themes/gotoandplay/inc/theme/js/jquery.bfe1bb19d13b3c17b682.min.js — 23 KB wasted

#### Layout-shift sources
- div.main > footer.footer > h2.heading > span.heading__main — shift 0.002

#### DOM size
- Total nodes: 0

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

#### All failing PSI audits (sorted by weight × failure margin)
- `color-contrast` (accessibility, score 0.00, weight 7) — Background and foreground colors do not have a sufficient contrast ratio.
- `landmark-one-main` (accessibility, score 0.00, weight 3) — Document does not have a main landmark.
- `first-contentful-paint` (performance, score 0.85, weight 10) — First Contentful Paint — 2.0 s
- `network-dependency-tree-insight` (performance, score 0.00, weight 0) — Network dependency tree

### 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 41 ms._

**Transport:**
- Final URL: https://play.ee/web-development-in-estonia/
- Status: 200
- Redirected: false
- HTTPS redirect: ✗ http://play.ee/web-development-in-estonia/ does not redirect to HTTPS (target: none)

**Caching:**
- cache-control: `max-age=0`
- etag: n/a
- last-modified: Tue, 01 Sep 2026 08:39:18 GMT
- expires: Tue, 01 Sep 2026 12:11:03 GMT
- pragma: n/a
- vary: Accept-Encoding

**Compression:**
- content-encoding: gzip
- content-length: 33598
- Decoded body: 219.6 KB
- Compression ratio: 0.149

### Priority fixes
1. **HTTP does not redirect to HTTPS** (high) — http://play.ee/web-development-in-estonia/ does not redirect to HTTPS
2. **strict-transport-security missing** (high) — Add HSTS with max-age >= 1 year, includeSubDomains, and preload
3. **content-security-policy weak** (high) — missing default-src; missing object-src 'none'; only frame-ancestors set — no script/resource restrictions
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

### Findings

#### Tracked headers
- **strict-transport-security** (missing, high)
- **content-security-policy** (weak, high) `frame-ancestors 'self';` — missing default-src; missing object-src 'none'; only frame-ancestors set — no script/resource restrictions
- **x-frame-options** (present, medium) `SAMEORIGIN`
- **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`
- X-Powered-By: `PHP/8.3.33`

#### All response headers
```
cache-control: max-age=0
connection: Upgrade, Keep-Alive
content-encoding: gzip
content-length: 33598
content-security-policy: frame-ancestors 'self';
content-type: text/html; charset=UTF-8
date: Tue, 01 Sep 2026 12:11:03 GMT
expires: Tue, 01 Sep 2026 12:11:03 GMT
keep-alive: timeout=5, max=100
last-modified: Tue, 01 Sep 2026 08:39:18 GMT
server: Apache
upgrade: h2,h2c
vary: Accept-Encoding
x-frame-options: SAMEORIGIN
x-powered-by: PHP/8.3.33
```

### 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 727 ms._

**Scoring:** 7 errors · 0 warnings · 23 cosmetic (suppressed)

> **Validator truncated at line 100** — the Nu validator stopped after hitting its internal error budget; score against the errors above, NOT as a fatal parse failure: Cannot recover after last error. Any further errors will be ignored.

### Priority fixes
1. **Parser recovery at line 100** (high) — Cannot recover after last error. Any further errors will be ignored.
2. **Bad start tag in “iframe” in “noscript” in “head”.** (medium) — x1, first at line 97
3. **Stray end tag “noscript”.** (medium) — x1, first at line 97
4. **Attribute “name” not allowed on element “meta” at this point.** (medium) — x1, first at line 99
5. **Element “meta” is missing one or more of the following attributes: “itemprop”, “property”.** (medium) — x1, first at line 99

### Issue groups
- (×1) [error] Bad start tag in “iframe” in “noscript” in “head”. — first at line 97 `<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-K3P64XMJ"`
- (×1) [error] Stray end tag “noscript”. — first at line 97 `></iframe></noscript><!-- E`
- (×1) [error] Attribute “name” not allowed on element “meta” at this point. — first at line 99 `<meta name="generator" content="WP Rocket 3.23.3.3" data-wpr-features="wpr_delay`
- (×1) [error] Element “meta” is missing one or more of the following attributes: “itemprop”, “property”. — first at line 99 `<meta name="generator" content="WP Rocket 3.23.3.3" data-wpr-features="wpr_delay`
- (×1) [error] Stray end tag “head”. — first at line 99 `esktop" /></head>
<body`
- (×1) [error] Start tag “body” seen but an element of the same type was already open. — first at line 100 `/></head>
<body class="wp-singular page-template page-template-template-dynamic `
- (×1) [error] Cannot recover after last error. Any further errors will be ignored. — first at line 100 `/></head>
<body class="wp-singular page-template page-template-template-dynamic `

### 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 2007 ms._

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

### Priority fixes
1. **color-contrast** (high) — Elements must meet minimum color contrast ratio thresholds
2. **landmark-unique** (medium) — Landmarks should have a unique role or role/label/title (i.e. accessible name) combination
3. **region** (medium) — All page content should be contained by landmarks

### Findings

#### `color-contrast` (serious) — WCAG: wcag2aa, wcag143
[Elements must meet minimum color contrast ratio thresholds](https://dequeuniversity.com/rules/axe/4.11/color-contrast?application=playwright)
- `.focus__heading > h1 > .heading__main`
- `.capabilities__grid-col.grid__col--sm-6.grid__col--md-4:nth-child(1) > .capabilities__heading.heading--h5.h5 > .heading__small`
- `.capabilities__grid-col.grid__col--sm-6.grid__col--md-4:nth-child(2) > .capabilities__heading.heading--h5.h5 > .heading__small`
- `.capabilities__grid-col.grid__col--sm-6.grid__col--md-4:nth-child(3) > .capabilities__heading.heading--h5.h5 > .heading__small`
- `.capabilities__grid-col.grid__col--sm-6.grid__col--md-4:nth-child(4) > .capabilities__heading.heading--h5.h5 > .heading__small`
- … and 21 more nodes

#### `landmark-unique` (moderate)
[Landmarks should have a unique role or role/label/title (i.e. accessible name) combination](https://dequeuniversity.com/rules/axe/4.11/landmark-unique?application=playwright)
- `.header__nav`

#### `region` (moderate)
[All page content should be contained by landmarks](https://dequeuniversity.com/rules/axe/4.11/region?application=playwright)
- `.section--page-intro`
- `.capabilities`
- `.alliance`
- `.mentoring > .section__inner > .section__content > .h-container > .intro`
- `.partners-logos`
- … and 58 more nodes

### Incomplete (axe could not determine)
- [Elements must meet minimum color contrast ratio thresholds](https://dequeuniversity.com/rules/axe/4.11/color-contrast?application=playwright) — 88 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 2023 ms._

**Capture summary:** 1 console events · 0 mixed-content requests · 14 network requests · 201.7 KB total

**Network bytes by resource type:**
| Type | Count | Bytes |
| --- | --- | --- |
| font | 3 | 57.6 KB |
| script | 5 | 53.5 KB |
| stylesheet | 2 | 34.2 KB |
| document | 1 | 32.8 KB |
| image | 1 | 18.1 KB |
| other | 1 | 5.5 KB |
| xhr | 1 | 0 B |

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

**Slowest requests (top 5):**
- https://cdn.jsdelivr.net/gh/orestbida/cookieconsent@3.0.1/dist/cookieconsent.umd.js (script) — 26 ms, 10.1 KB
- https://cdn.jsdelivr.net/gh/orestbida/iframemanager@1.3.0/dist/iframemanager.js (script) — 26 ms, 3.0 KB
- https://play.ee/web-development-in-estonia/ (document) — 23 ms, 32.8 KB
- https://play.ee/wp-content/themes/gotoandplay/inc/theme/js/jquery.bfe1bb19d13b3c17b682.min.js (script) — 23 ms, 31.5 KB
- https://fast.fonts.net/t/1.css?apiType=css&projectid=d924b670-8ecc-46fd-9fff-80fd9989d037 (stylesheet) — 22 ms, 0 B

### Findings

#### Console events
- [warning] Couldn't load preload assets:  

### 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 2023 ms._

**Document:**
- Lang: en
- Title: Expert web development in Estonia and worldwide
- Canonical: https://play.ee/web-development-in-estonia/
- Viewport: width=device-width, initial-scale=1
- Charset: UTF-8
- HTML bytes: 221970

**Meta tags:**
- Description: Premium web development in Estonia and beyond. We provide a full range of services, from building simple websites to complex web applications.
- Robots: follow, index, max-snippet:-1, max-video-preview:-1, max-image-preview:large
- Theme color: #ffffff
- Open Graph tags: 7 (og:locale, og:type, og:title, og:description, og:url, og:site_name, og:updated_time)
- Twitter tags: 3
- hreflang:
  - en → https://play.ee/web-development-in-estonia/
  - et → https://play.ee/et/veebiarendus-eestis/
  - x-default → https://play.ee/web-development-in-estonia/
- JSON-LD: 1 blocks (1 valid) — types: Unknown

**Heading outline:**
- Counts: h1 ×2, h2 ×27, h3 ×37, h4 ×0, h5 ×0, h6 ×0
- Sequence (first 20):
  - h1: our
        
                    strong suit
  - h2: we love
        
                    web apps
  - h2: we make awesome
        
                    websites
  - h2: we validate ideas by
        
                    prototyping
  - h2: how it's done
        
                    our way
  - h3: 01
        
                    discover
  - h3: 02
        
                    research
  - h3: 03
        
                    plan
  - h3: 04
        
                    create and iterate
  - h3: 05
        
                    launch
  - h3: 06
        
                    support
  - h2: we are part of
        
                    play & nope alliance
  - h2: we believe in learning from
        
                    each other
  - h2: we love our
        
                    partners
  - h2: follow our
        
                    journey
  - h3: GOTOANDPLAY WAS FOUNDED
  - h3: THE TEAM IS GROWING
  - h3: FIRST BIG PROJECT
  - h3: FIRST BIG CLIENT
  - h3: WE SNATCHED PLAY.EE

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

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

External scripts (first 15):
- https://cdn.jsdelivr.net/gh/orestbida/iframemanager@1.3.0/dist/iframemanager.js (defer)
- https://cdn.jsdelivr.net/gh/orestbida/cookieconsent@3.0.1/dist/cookieconsent.umd.js (defer)
- https://play.ee/wp-content/themes/gotoandplay/inc/theme/js/runtime.30d3b226dcf211e512b1.min.js
- https://play.ee/wp-content/themes/gotoandplay/inc/theme/js/jquery.bfe1bb19d13b3c17b682.min.js (defer)
- https://play.ee/wp-content/plugins/wp-rocket/assets/js/wpr-beacon.min.js (async)

**Stylesheets:** 1 external, 3 inline (9.6 KB)

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

Image inventory (first 15):
| src | alt | w×h | loading | srcset |
| --- | --- | --- | --- | --- |
| ;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| ;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| %2Fsvg%22%20viewBox%3D%220%200%20352%20264%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| %2Fsvg%22%20viewBox%3D%220%200%20352%20264%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| 0%2Fsvg%22%20viewBox%3D%220%200%20230%2080%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| 0%2Fsvg%22%20viewBox%3D%220%200%20230%2080%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| 0%2Fsvg%22%20viewBox%3D%220%200%20230%2080%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| 0%2Fsvg%22%20viewBox%3D%220%200%20230%2080%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| 0%2Fsvg%22%20viewBox%3D%220%200%20230%2080%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| 0%2Fsvg%22%20viewBox%3D%220%200%20230%2080%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| 0%2Fsvg%22%20viewBox%3D%220%200%20230%2080%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| ;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| 0%2Fsvg%22%20viewBox%3D%220%200%20230%2080%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| 0%2Fsvg%22%20viewBox%3D%220%200%20230%2080%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |
| 0%2Fsvg%22%20viewBox%3D%220%200%20230%2080%22%3E%3C%2Fsvg%3E | _(empty)_ | _n/a_ | _n/a_ | ✗ |

**Links:** 62 anchors — 46 external, 1 preconnect, 0 preload.

Vague repeated link text:
- "view our instagram feed" ×3
- "visit our facebook page" ×3
- "visit our linkedin page" ×3
- "eng" ×3
- "est" ×3
- "styleguide" ×2
- "privacy policy" ×2

### Priority fixes
1. **Document has 2 <h1> elements** (medium) — A page should have exactly one h1; multiple h1s break document outline
2. **Missing skip-to-content link** (medium) — No anchor link with "skip" / "otse sisu" text found
3. **67 images without explicit width/height** (medium) — Missing dimensions can cause layout shifts (CLS)

### 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 · 0 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 (52 SVGs, 15 placeholders excluded). |
| Hero image eagerly loaded | – n/a | No raster <img> elements found (52 SVGs, 15 placeholders excluded). |
| 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 (52 SVGs, 15 placeholders 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> | ✓ pass | No render-blocking scripts in <head>. |

**Evidence:**
- Page caching plugin / CDN active:
  - `HTML markers: WP Rocket`
  - `generator: WP Rocket 3.23.3.3`

### 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).