Performance and Core Web Vitals
Hyprism is built to clear Shopify Theme Store performance gates with margin. This chapter covers the optimizations baked in, what targets to expect, and how to verify performance on your store.
14.1 Targets
Section titled “14.1 Targets”Hyprism aims for these performance targets across all 13 templates:
| Metric | Mobile target | Desktop target | Theme Store gate |
|---|---|---|---|
| Lighthouse Performance | ≥85 (median 92) | ≥95 (median 99–100) | ≥75 mobile |
| Largest Contentful Paint (LCP) | <2.5s | <1.5s | <2.5s |
| Cumulative Layout Shift (CLS) | <0.1 | <0.1 | <0.1 |
| Total Blocking Time (TBT) | <300ms | <100ms | <300ms |
| Interaction to Next Paint (INP) | <200ms | <200ms | <200ms |
The median across all 13 templates after 4 iterative Lighthouse runs (on a development store with apparel demo content) was:
- Mobile: 92 (Performance), 96–100 (A11y), 100 (SEO) — only Cart shows SEO=69 because
/cartis intentionally blocked from indexing via robots.txt. - Desktop: 99–100 (Performance), 96–100 (A11y), 100 (SEO).
14.2 What’s optimized
Section titled “14.2 What’s optimized”Critical CSS
Section titled “Critical CSS”The theme’s critical above-the-fold CSS (the styles needed before any section renders) is in assets/critical.css. It’s loaded synchronously in <head> with <link rel="preload"> so the browser fetches it early.
Non-critical CSS lives in {% stylesheet %} blocks inside individual section/block Liquid files — Shopify bundles these into per-section CSS files that load only when that section is on the page.
Preconnect and preload
Section titled “Preconnect and preload”In layout/theme.liquid <head>:
<link rel="preconnect" href="https://fonts.shopifycdn.com"><link rel="preload" as="style" href="critical.css"><link rel="preload" as="font" type="font/woff2" href="..."> <!-- body + heading fonts -->Browser starts connection + font / CSS download before parsing the rest of the page.
⚠️ Preconnect to cdn.shopify.com was removed in v0.7 — Lighthouse flagged it as “unused” because Shopify serves theme assets same-origin (no DNS resolution needed). Removing the preconnect freed up critical-path latency by ~1500ms on the home page. Lesson: only preconnect to origins you actually fetch from cross-origin.
Image optimization
Section titled “Image optimization”- All images use
image_urlfilter for the Shopify CDN, which auto-converts to AVIF/WebP based on browser support. - Section-position-aware fetchpriority: hero/first-section images get
fetchpriority="high"for LCP; below-fold images getloading="lazy"for delayed loading. decoding="async"on every<img>— browser decodes images off the main thread, so image rendering doesn’t block scroll responsiveness.- Subgrid card alignment keeps all product cards in a grid identical-height (no layout shift as images load at different speeds).
Passive event listeners
Section titled “Passive event listeners”All scroll, touch, and wheel listeners use { passive: true }:
window.addEventListener('scroll', handler, { passive: true });section.addEventListener('touchstart', handler, { passive: true });This tells the browser “I won’t preventDefault” — the browser can start scrolling immediately without waiting for the JS to run. Massively improves INP.
Deferred JS
Section titled “Deferred JS”Every theme JS script uses defer:
<script src="hyprism.js" defer></script><script src="hyprism-features.js" defer></script>JS doesn’t block HTML parsing. It executes after DOMContentLoaded.
IntersectionObserver for lazy work
Section titled “IntersectionObserver for lazy work”Instead of scroll listeners that fire on every scroll event, Hyprism uses IntersectionObservers for:
- Sticky Product Bar (watches the main ATC)
- Mobile Sticky Cart Bar (watches the in-flow summary)
- Off-screen card visibility-hiding in slider carousels
- Recently-viewed tracking (when a product page enters viewport, the product is added to localStorage)
IntersectionObservers fire only when an element crosses a threshold — orders of magnitude cheaper than scroll listeners.
Animation considerations
Section titled “Animation considerations”- Transform-only animations (translate, scale, rotate) — the browser composites these on GPU without main-thread cost
will-changeonly when transitioning — not set permanently (which would keep elements on a GPU layer always)backdrop-filteronly on explicit glass elements — not on overlay-wrappers (which would force the entire page through GPU compositor)
14.3 What’s intentionally NOT optimized
Section titled “14.3 What’s intentionally NOT optimized”A few things that could be optimized but aren’t, because the trade-offs aren’t worth it:
Preload-link for product / article featured images (REVERTED)
Section titled “Preload-link for product / article featured images (REVERTED)”Tried in v0.7-Round-2: <link rel="preload" as="image"> for the product page’s main image. On throttled-mobile (Lighthouse’s mobile profile = 4× CPU + Slow-4G), the preload competed with critical-path resources for bandwidth, and FCP regressed +0.6s. Net-negative — reverted.
Lesson: preload helps only for late-discovered resources (JS-driven images, dynamically-imported fonts). For in-the-HTML images, the browser’s default discovery is already optimal.
Logo fetchpriority="low" (REVERTED)
Section titled “Logo fetchpriority="low" (REVERTED)”Tried in v0.7-Round-2: deprioritize the header logo to free bandwidth for the hero. On throttled-mobile, this delayed FCP because the logo is part of the first paint. Browser-default heuristics (auto-prio for above-fold images) were already correct. Reverted.
Lesson: don’t speculatively deprioritize above-fold resources — the browser knows better.
14.4 Lighthouse Best Practices = 77
Section titled “14.4 Lighthouse Best Practices = 77”This score is constant across all 13 Hyprism templates because the failing items are Shopify-platform-level, not theme-fixable:
| Failed Item | Cause | Fixable? |
|---|---|---|
CSP script-src and object-src missing | Shopify edge sets Content-Security-Policy header that Hyprism can’t override | No — Shopify-level |
| HSTS max-age too low | Shopify edge sets HSTS header | No |
| No COOP (Cross-Origin-Opener-Policy) | Shopify edge | No |
| No Trusted Types | Shopify edge | No |
| Third-party cookies (shop.app) | Shopify ecosystem | No |
Dawn and Horizon score 77 too — reviewers are familiar with this plateau and don’t reject themes for it.
14.5 Verifying performance on your store
Section titled “14.5 Verifying performance on your store”Run Lighthouse
Section titled “Run Lighthouse”In Chrome / Edge:
- Open the page you want to test.
- DevTools (F12) → Lighthouse tab.
- Pick “Mobile” + “Performance, Accessibility, Best Practices, SEO” + “Slow 4G + 4× CPU”.
- Click “Analyze page load”.
Run 3–5 times and take the median — Lighthouse Mobile has natural variance (±5–15 points per run, even with no code changes).
Run Shopify Web Performance Dashboard
Section titled “Run Shopify Web Performance Dashboard”Shopify Admin → Online Store → Themes → Customize → Performance tab. Shopify tests every published theme weekly and reports CWV.
Run real-user monitoring
Section titled “Run real-user monitoring”Once your store is live with real traffic, Shopify’s Performance tab shows real-user CWV data (anonymized aggregate). This is more meaningful than Lighthouse because it reflects what real visitors experience.
14.6 Performance tips for content choices
Section titled “14.6 Performance tips for content choices”Things merchants control that affect performance:
| Choice | Impact | Recommendation |
|---|---|---|
| Hero video file size | High | Compress to ≤2MB for autoplay-loops |
| Hero image size | Medium | Upload at 2× display size; let Shopify CDN serve optimized formats |
| Number of sections on home page | Low | Generally fine; Hyprism uses section-scoped CSS so unused sections aren’t loaded |
| Number of apps installed | High | Each app injects JS. Apps often hurt performance more than themes. |
| Custom Liquid section content | Variable | Custom Liquid runs server-side, so it’s free at runtime. JavaScript inside Custom Liquid can be costly. |
14.7 INP (Interaction to Next Paint)
Section titled “14.7 INP (Interaction to Next Paint)”INP is Google’s newer metric (replacing FID in 2024). It measures the longest input-to-paint delay during a page session — basically “how snappy does this page feel?”
Hyprism INP targets <200ms. To achieve this:
- All JS listeners are passive where applicable
- Main-thread tasks are <50ms each
- Animations are GPU-composited (transform / opacity / filter)
- IntersectionObserver replaces scroll listeners
- AJAX cart updates are event-driven, no polling
If your INP is high on a specific page, check:
- Apps with heavy JS — Shopify Apps tab → Performance tab shows per-app impact
- Custom Liquid sections — large
forloops in Liquid run server-side (fine) but JSON output rendered as<script>and parsed in JS can be slow if huge - Marketing pixels — Meta Pixel, TikTok Pixel, etc. can be heavy
Chapter 15 — Localization — multi-language store setup.