SEO performance: Core Web Vitals, Schema.org and technical audit
PageSpeed shows 34/100 on mobile. In Search Console — red metrics on all category pages. Competitor with a site 3 years older ranks higher despite weaker content. Technical performance became a direct ranking factor — and the gap between "acceptable" and "fast" costs positions.
Core Web Vitals: what really affects rankings
Google uses three metrics as ranking signals (Page Experience): LCP (Largest Contentful Paint), CLS (Cumulative Layout Shift), INP (Interaction to Next Paint, replaced FID since March 2024).
LCP: why 8 seconds is not an image problem
LCP measures rendering time of the largest visible element on page. Usually — hero image or H1. Thresholds: good < 2.5s, poor > 4s.
Typical diagnosis on real project: clothing e-commerce, LCP 7.8s on mobile. Element — category hero image, 4.2MB JPEG without srcset, loaded via CSS background-image (not <img>). Problem here is double: first, browser can't preload CSS background images via <link rel="preload"> standard way. Second, 4.2MB on mobile connection — physically slow.
Solution step by step:
- Move hero from CSS background to
<img>withfetchpriority="high"andloading="eager" - Convert to WebP, add
srcset:800wfor mobile,1400wfor desktop -
<link rel="preload" as="image" href="hero-800.webp" media="(max-width: 768px)">in<head> - Remove all render-blocking scripts above hero via
defer
Result: LCP 7.8s → 1.9s. Without changing hosting, without CDN.
If LCP is not image but text block: problem may be in TTFB (slow server), render-blocking CSS/JS, or web fonts with font-display: block.
CLS: shifts that annoy user and Google
CLS measures cumulative shift of elements during page load. Thresholds: good < 0.1, poor > 0.25. CLS 0.35 — banner appearing in one second and shifting all content down.
CLS sources:
-
Images without set dimensions.
<img src="photo.jpg">withoutwidthandheight— browser doesn't reserve space, content jumps on load. Fix: explicitwidth/heightoraspect-ratioin CSS. -
Ad blocks and widgets. Google Ads, chat widgets, cookie consent — everything appearing after main content. Solution: reserve space via
min-heightor load before main render. -
Web fonts. FOUT (Flash of Unstyled Text) and FOIT (Flash of Invisible Text) can cause reflows.
font-display: swapwithsize-adjust(CSS property to align fallback font size) minimizes CLS. - Dynamic content. If block appears after load (data fetch, lazy load) — add skeleton placeholder with needed dimensions.
INP: why interface "hangs" for 500ms
INP measures response delay to any user interaction: click, tap, input. Thresholds: good < 200ms, poor > 500ms. INP 680ms — user clicks filter button, nothing happens for half second.
Main cause of high INP — blocked main thread. JavaScript bundle 2.1MB parsed and executed synchronously. While executing, user events not processed.
Diagnosis via Chrome DevTools → Performance → interaction with suspicious delay → find Long Tasks (> 50ms). Typical culprits:
- Processing large list without
requestIdleCallbackorrequestAnimationFrame - Heavy event listeners without
debounce/throttle - Synchronous setState in React triggering full re-render of complex component tree
- Third-party scripts: livechat, analytics, widgets — executed on same main thread
Solutions: code splitting via dynamic import(), moving heavy computations to Web Workers, React.memo + useMemo preventing unnecessary re-renders, scheduler API for task prioritization.
Schema.org: markup that robots read
Structured data via JSON-LD — not direct ranking factor, but gives rich snippets (rating stars, prices, publication date), increasing CTR by 20–30%.
Markup types by scenario:
E-commerce: Product with offers (price, availability, currency), aggregateRating (rating from reviews), brand. BreadcrumbList for navigation. ItemList for category pages.
Articles and blog: Article or BlogPosting with author, datePublished, dateModified, image. Organization and WebSite on homepage — helps Google connect site with brand.
Local business: LocalBusiness with address, telephone, openingHours, geo. Critical for local SEO.
FAQ: FAQPage with mainEntity — questions and answers can appear directly in results as expandable block.
Validation: Google Rich Results Test and Schema Markup Validator. Common mistake — specify price without priceCurrency, or ratingValue without reviewCount. Google ignores incomplete markup.
Technical SEO audit: what we check
Crawlability. robots.txt blocks needed pages (or conversely, doesn't block service pages). Canonical URLs configured wrong — pages duplicated with UTM tags. Sitemap contains pages with noindex. All this Screaming Frog or Sitebulb shows in hour of crawling.
Core Web Vitals at scale. Google Search Console → Core Web Vitals → look not at individual pages, but URL groups (product page template, category template, blog). Problem usually systemic — one error in template ruins hundreds of pages.
JavaScript SEO. Google renders JavaScript, but with delay (sometimes days for full render). For critical content — SSR or SSG mandatory. Check via Search Console → Inspect URL → View Crawled Page: what Googlebot sees.
Internal linking. Orphan pages (no incoming internal links) lose PageRank. Broken links (404) — quality signal.
Toolkit
- Diagnostics: Chrome DevTools Performance, Lighthouse CLI, WebPageTest with tracing
- Monitoring: Sentry Performance, Google Search Console, SpeedCurve for historical trends
- Markup: JSON-LD generation on backend (not via GTM — Google sees server-rendered more reliably)
- Crawling: Screaming Frog SEO Spider, Sitebulb for structure visualization
Process and timelines
Technical audit → problem prioritization by impact → critical render path optimization → CLS and INP work → Schema.org implementation → Core Web Vitals monitoring setup in CI.
| Work type | Timeline |
|---|---|
| Technical SEO audit + roadmap | 1–2 weeks |
| Core Web Vitals optimization (one template) | 2–4 weeks |
| Full technical site optimization | 4–10 weeks |
| Schema.org implementation for e-commerce | 1–3 weeks |
Cost calculated individually after audit.







