Qwik SEO
How Qwik's resumability puts content in the HTML by default and drives near-zero INP and TBT — plus the QwikCity patterns for meta tags, canonical URLs, JSON-LD, sitemaps, and i18n that make a Qwik site rank.
1 evidence signal on this page
- Related live toolPage Speed Test & Core Web Vitals Checker
Qwik is a JavaScript framework whose core trick is resumability: the server serializes app state, listeners, and the component tree into the HTML, so the browser resumes without hydrating (a ~1 KB Qwikloader script still runs — it's not literally zero JS). For SEO that's a double win on routes that are actually server-rendered — content is in the HTML by default (crawlers see it immediately, no render-wave delay) and INP/TBT trend toward zero because no hydration blocks the main thread on load; confirm both with field data rather than assuming them. QwikCity, the meta-framework, lets you mix SSR and SSG per route, plus routeLoader$() for server-side data and a head export for title/meta/OG/canonical/JSON-LD — all server-rendered. Basic SEO works out of the box; the main discipline is using routeLoader$() for dynamic metadata, not client-side effects. The catch is a smaller ecosystem than React/Vue, and — as of this writing — Qwik is on its v2 line, currently in beta.
TL;DR — Qwik is a JavaScript framework that does something unusual: it sends finished HTML and then runs almost no JavaScript when the page loads. Most frameworks have to “hydrate” — re-run their code in your browser to wake the page up — and Qwik skips that entirely by resuming from data baked into the HTML. For SEO that means crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. see your full content right away, and pages score well on the speed metrics Google measures.
What Qwik is
Most popular frameworks (React, Vue, Angular) build a lot of the page in your browser. Even when the server sends finished HTML, the framework usually has to hydrate it — download its code and re-run it in your browser to make buttons and menus work. That hydrationTurning HTML, CSS, and JavaScript into the final visual page and DOM. step is one of the biggest reasons pages feel slow: it ties up the browser right when you’re trying to use the page.
Qwik attacks that problem head-on with an idea called resumability. On the server, Qwik renders the HTML and writes everything the page needs to keep working — its state, which clicks do what, the structure of the page — straight into the HTML. When the page loads in your browser, Qwik doesn’t re-run anything. It resumes from that saved information, so it isn’t re-executing your components — but it isn’t literally zero JavaScript either. A tiny (~1 KB) loader script called the Qwikloader does run on load; it just listens for clicks instead of rebuilding the page. Evidence for this claim Qwik serializes application state into HTML and resumes without eagerly re-executing the application on startup. Scope: Qwik resumability; exact JavaScript transferred depends on the application. Confidence: high · Verified: Qwik: Resumable It only fetches the rest of the code it needs the moment you actually click something.
QwikCity is the full toolkit built on top of Qwik — it’s to Qwik what Next.js is to React. It gives you page routing, server renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM., and a clean place to set your titles and meta tagsMeta tags are HTML elements in a page's head that pass metadata about the page to search engines and browsers. For SEO only a few matter — the title element, the meta description, and the robots meta tag — while meta keywords and most others are ignored.. If you’re doing SEO on a Qwik site, you’re almost certainly using QwikCity.
Why this is good for SEO
Two reasons:
- Your content is in the HTML. Because Qwik renders everything on the server and never needs to render again in the browser, the text and links Google needs are right there in the page source. Google doesn’t have to do anything tricky to see your content — which is the whole game in JavaScript SEOMaking sure search engines can crawl, render, and index content that depends on JavaScript.. That’s true when the route is actually server-rendered (SSR or SSG) — check the raw HTML with view-source on your own deployed pages rather than assuming it from the framework alone.
- Pages are fast and responsive. With very little JavaScript running on load, the page reacts to clicks quickly (good INPInteraction to Next Paint — the input-to-paint latency at the 75th percentile of a page's interactions. ≤200 ms is good.) and the browser isn’t blocked. Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. reward exactly that, so it’s a real — if usually small — advantage. It’s a structural head start, not a guarantee; confirm it with field dataPerformance metrics captured from real users, not lab tests. on your own site rather than assuming the number.
What you still have to do
“Works out of the box” doesn’t mean “do nothing.” The big one: set your titles,
descriptions, and other meta tagsMeta tags are HTML elements in a page's head that pass metadata about the page to search engines and browsers. For SEO only a few matter — the title element, the meta description, and the robots meta tag — while meta keywords and most others are ignored. using QwikCity’s head export on each page,
and for pages with dynamic data (blog posts, product pages) pull that data
server-side with routeLoader$() so the meta tags end up in the HTML — not
added later by JavaScript. Evidence for this claim Qwik City routes can provide page metadata through a head export, and routeLoader$ loads route data on the server. Scope: Qwik City metadata and loaders. Confidence: high · Verified: Qwik City: Head Qwik City: Route loaders Get that right and most of Qwik SEOQwik SEO is the practice of optimizing sites built with Qwik, a JavaScript framework whose 'resumability' model serializes app state into HTML so the browser never has to hydrate. Content is in the HTML by default, so crawling, indexing, and Core Web Vitals are all structurally strong. takes care of
itself.
Want the real mechanics — how resumability works, the exact QwikCity patterns for meta tags, canonical URLsHow search engines pick one canonical URL among duplicates and consolidate signals onto it., structured dataStructured data is a standardized way of labeling page content (using the schema.org vocabulary in JSON-LD, Microdata, or RDFa) so search engines can understand its meaning. It's not a direct ranking factor — its value is rich results and entity understanding., and sitemapsA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing., plus the pitfalls? Switch to the Advanced tab.
TL;DR — Qwik’s core innovation is resumability: at SSR time it serializes event listeners (as HTML attributes), the component tree (in HTML comments), and app state (in a
qwik/jsonscript) into the HTML, so the browser resumes instead of hydrating — a ~1 KB Qwikloader script still runs, so it’s not literally zero JS. That’s categorically different from React/Vue/Angular/SolidJS, which all hydrate. On routes that are actually server-rendered, the SEO payoff is twofold: content is in the HTML by default (no render-wave delay for crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index.) and INPInteraction to Next Paint — the input-to-paint latency at the 75th percentile of a page's interactions. ≤200 ms is good./TBTTotal Blocking Time — the sum of the blocking portion (time above 50 ms) of every long task between First Contentful Paint and Time to Interactive. It's a lab-recommended metric and the lab proxy for INP, not a Core Web Vital. trend toward zero because no hydrationTurning HTML, CSS, and JavaScript into the final visual page and DOM. blocks the main thread on load — verify both with field data rather than assuming them. QwikCity is the meta-framework — SSR and SSG can be mixed per route, not chosen once for the whole project. Metadata lives in theheadexport (title, meta, OG, canonical, JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal.), fed byrouteLoader$()for server-side data. SitemapsA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. are automatic in SSG (for routes actually built) and a dynamic route in SSR. Qwik is currently on its v2 line (beta) as of this writing. The honest caveat: the ecosystem is newer and smaller than React’s.
Resumability: the core idea (and why SEO cares)
Qwik was built by Miško Hevery — the creator of Angular — at builder.io, and its whole reason to exist is to kill hydrationActivating server-rendered HTML in the browser by attaching JavaScript handlers.. (As of this writing, Qwik is on its v2 line, currently in beta — check the API surface against your installed version before copying code from any source, including this one.) Hydration is what every mainstream framework does after SSR: it downloads the component code and re-executes it in the browser to attach event handlers and rebuild internal state. As Hevery puts it, “Hydration is when an application is downloaded and executed twice, once as HTML and again as JavaScript.” That second execution is pure overhead — the page looks ready but isn’t interactive, and the main thread is blocked.
Qwik instead serializes three things into the HTML at SSR time:
- Event listeners — encoded as HTML attributes (e.g.
on:click="./chunk.js#symbol"). A tiny inline script (the Qwikloader, ~1 KB) attaches one global listener, reads the encoded chunk/symbol on an event, and downloads only that handler code on demand. - Component tree structure — encoded in HTML comments, so Qwik can rebuild the hierarchy without executing component code.
- Application state — serialized into a
<script type="qwik/json">block, so any component can resume without its parent being present.
When the page loads, Qwik doesn’t re-run your components. Evidence for this claim Qwik resumability restores listeners and application state without rerunning component initialization on page startup. Scope: Qwik resumability model. Confidence: high · Verified: Qwik: Resumable As the docs put it, “Resumability is a way for a framework to recover its state without re-executing the application components on the client.” The result, in the docs’ words: “Qwik apps work instantly without any delay because they don’t need hydration, regardless of their size or complexity.”
This is not Islands Architecture (Astro). Islands still hydrate each island individually. Qwik hydrates nothing — there’s no per-island hydration cost because there’s no hydration at all.
What crawlers actually receive
Because Qwik pre-renders everything server-side and never re-renders on the
client, the HTML GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. fetches already contains your complete content —
text, links, headings, the lot — for a route that’s actually rendered on the
server. RenderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. is a per-route decision in QwikCity (SSR, SSG, or a mix); a
route left in client-only mode, or content fetched from a client-side effect
instead of routeLoader$(), doesn’t get this benefit just because the project
uses Qwik. Google processes JavaScript in two waves (HTML first, then a deferred
render pass that can lag hours to days). A heavily client-rendered app risks
content only showing up in that second wave. A properly server-rendered Qwik
route sidesteps that risk: there’s no render-queue delay because the content was
never waiting on client JS in the first place. Treat “Qwik pages behave like
static HTML for crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index.” as the architecture’s intent, then confirm it on your
deployed URLs with view-source — the safest posture for
JavaScript SEOMaking sure search engines can crawl, render, and index content that depends on JavaScript. is verifying the response, not
trusting the framework label.
Bing works the same way — a two-wave model that prefers server-rendered HTML for efficiency. Qwik’s HTML-first output benefits both engines for the same reason.
Core Web Vitals: a structural advantage
Google uses field dataPerformance metrics captured from real users, not lab tests. (CrUXChrome User Experience Report — Google's public dataset of real-world (field) performance data from eligible Chrome users. It's the official field-data source behind the Core Web Vitals program.) for the Page Experience signal, and INPInteraction to Next Paint — the input-to-paint latency at the 75th percentile of a page's interactions. ≤200 ms is good. replaced FID as a Core Web Vital in March 2024. Here’s where Qwik’s architecture pays off directly: with the Qwikloader as the only script running on load — the docs note sites “can boot with about 1kb of JS (regardless of application complexity)” — there’s almost nothing to block the main thread. Total Blocking Time trends toward zero and INP stays low because there’s no hydration pass competing with the user’s first interactions. A bigger Qwik app doesn’t mean a bigger startup bill; the JavaScript is fetched lazily, per interaction, not as one boot bundle.
That’s the difference from the established frameworks. Next.js, Nuxt, and Angular SSR all put content in the HTML too — they’re not bad for SEO — but they carry a hydration cost that scales with the app. Qwik removes that cost by design.
That’s the architectural expectation, not a measured result. It doesn’t guarantee a specific INP, TBTTotal Blocking Time — the sum of the blocking portion (time above 50 ms) of every long task between First Contentful Paint and Time to Interactive. It's a lab-recommended metric and the lab proxy for INP, not a Core Web Vital., or CrUXChrome User Experience Report — Google's public dataset of real-world (field) performance data from eligible Chrome users. It's the official field-data source behind the Core Web Vitals program. score for your site — third-party scripts, analytics tags, and per-route data-fetching cost can all eat into the advantage. Confirm it with field data (CrUX, Search ConsoleGoogle's free tool for monitoring crawling, indexing, and search performance.’s Core Web Vitals reportThe Google Search Console report (under Experience) that shows how your indexed URLs perform on the Core Web Vitals — LCP, INP, and CLS — using real-user field data from CrUX, grouped by device, status, and clusters of similar-performing URLs.) on your own deployed URLs before making a performance claim to a client or stakeholder; see the How to Measure tab for the specific KPIs and cadence.
Meta tags and the document head
In QwikCity, page metadata lives in a head export from each route file. For
static metadata it’s a constant: Evidence for this claim Qwik City route modules can export a DocumentHead value or function for route metadata. Scope: Qwik City route metadata. Confidence: high · Verified: Qwik City: Head
export const head: DocumentHead = {
title: 'Qwik SEO Guide',
meta: [
{ name: 'description', content: 'How Qwik resumability helps SEO.' },
{ property: 'og:title', content: 'Qwik SEO Guide' },
{ property: 'og:description', content: 'Resumability, meta tags, sitemaps.' },
],
links: [
{ rel: 'canonical', href: 'https://example.com/qwik-seo/' },
],
};All of this is rendered server-side into <head>, so it’s in the HTML the
crawler sees. The canonical pattern — links: [{ rel: 'canonical', href: '...' }]
— is easy to miss but is the right place for it.
For dynamic metadata (blog posts, products), the SEO-critical pattern is
routeLoader$(). It runs server-side before the HTML response, and the head
export can be a function that receives the resolved loader value:
export const usePost = routeLoader$(async ({ params }) => {
return await getPost(params.slug); // runs on the server
});
export const head: DocumentHead = ({ resolveValue }) => {
const post = resolveValue(usePost);
return {
title: post.title,
meta: [{ name: 'description', content: post.excerpt }],
links: [{ rel: 'canonical', href: `https://example.com/blog/${post.slug}/` }],
};
};This is QwikCity’s equivalent of getServerSideProps. The discipline that matters
for SEO: fetch metadata data with routeLoader$(), not in a client-side
effect (useSignal()/useResource$() that run in the browser). If you set the
title from a client effect, it won’t be in the first-wave HTML.
Structured data (JSON-LD)
JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal. goes in the head export’s scripts array, rendered inline in
<head> server-side and fully crawlable:
export const head: DocumentHead = ({ resolveValue }) => {
const post = resolveValue(usePost);
return {
title: post.title,
scripts: [
{
props: { type: 'application/ld+json' },
script: JSON.stringify({
'@context': 'https://schema.org',
'@type': 'Article',
headline: post.title,
datePublished: post.date,
}),
},
],
};
};Because it’s serialized into the HTML response, there’s no rendering delay before
the markup is available to crawlers. One setup detail that’s easy to miss: the
scripts field only produces output if your project’s router-head component
actually renders head.scripts (typically via dangerouslySetInnerHTML) — it’s
not automatic just because you populated the array. If a starter template’s
router-head.tsx doesn’t already loop over head.scripts, add that before
trusting the JSON-LD shows up in the response.
Sitemaps and robots.txt
- SSG builds: the
sitemapOutFileconfig option auto-generatessitemap.xmlduring the static build — but it only includes routes that were actually built. A route excluded from the static build (dynamic params you didn’t pre-render, a page gated behind a condition) won’t be in the sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. even though it exists. - SSR sites: there’s no automatic sitemap — add a route at
src/routes/sitemap.xml/index.tswith aRequestHandlerthat builds and returns the XML dynamically. robots.txt: drop it in/public/so it’s served at the root.- Canonical and sitemap URLs both depend on
origin. QwikCity builds absolute URLs from the configuredorigin/base(or a forwarded-header origin in SSR middleware). A wrong or leaked preview/staging origin in that configuration produces wrong canonicals and sitemap entries in production — check the actual output, not just the config file, after any adapter or deployment change.
International SEO
Two mechanisms, used together:
rewriteRoutesin QwikCity config maps localized URL paths to your routes without duplicating components (e.g./it/documentazione/→/docs/). This gives you clean, localized URLs — the foundation for an international URL structureURL structure is how the parts of a web address — scheme, domain, path, query string, and fragment — are organized and formatted. It mostly affects crawling, usability, and how engines understand a page, not rankings directly..- Qwik Speak (a separate library) handles content translation.
- hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others. tags go in the
headexport’slinksarray, pointing each locale at its alternates. See international SEOInternational SEO is the practice of optimizing a site so search engines understand which countries and/or languages it targets, and serve the right version to each user. It spans URL structure, hreflang, and on-page localization. and hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others. for the cross-engine rules.
SSR vs. SSG for SEO
Both put content in the HTML, so both are crawler-safe — and QwikCity lets you mix modes per route, not just once for the whole project. Choose per route by content shape:
- SSG (static adapter) produces pure HTML files, no server needed — ideal for content that doesn’t change per request. Automatic sitemap (for routes that were actually built), cheapest hosting, fastest TTFBTime to First Byte — the time from the start of a request to when the first byte of the response arrives. It's a diagnostic metric (not a Core Web Vital) and a major input to FCP and LCP; ≤0.8 s is good. from a CDN. The tradeoff is freshness: content only updates on the next build, and a route that fails to build simply isn’t there.
- SSR renders per request — needed for personalized or frequently changing
data. Run it at the edge (Cloudflare, Vercel, Netlify) for low TTFB, and set
Cache-Controlheaders on SSR responses so the CDN can serve repeats without re-rendering. The tradeoff is that a failure at request time (a slow or erroredrouteLoader$()) affects the live response, so add error handling for the data fetch rather than letting it surface as a broken page.
Neither mode is “more SEO-safe” than the other by default — pick per route based on how often the content changes and what happens if the data source is briefly unavailable, then verify the deployed response either way.
What to watch out for
- Not everything serializes. Class instances, promises, and streams can’t be
put into the HTML state. Code that touches them has to run client-only — keep it
out of anything that needs to be in the server HTML (especially metadata). If you
deliberately exclude a value with
noSerialize(), remember it comes back asundefinedafter the app resumes on the client — don’t reach for it on anything the page still needs to read post-resume, including metadata paths. useVisibleTask$()is a real escape hatch, use it sparingly. It runs eagerly on the client after initial render — the one hook that deliberately works against resumability. It doesn’t block rendering or hurt the initial HTML, but it does mean client JS is running that Qwik would otherwise have deferred. Fine for genuinely client-only work (a chart library, a map); wrong choice for anything that should be feeding server-rendered metadata.- Verify meta tagsMeta tags are HTML elements in a page's head that pass metadata about the page to search engines and browsers. For SEO only a few matter — the title element, the meta description, and the robots meta tag — while meta keywords and most others are ignored. are in the source, not injected by JS. View-source (not just
DevTools’ rendered DOM) should show your title, canonical, and JSON-LD. If they
only appear in the rendered DOM, you set them from a client effect instead of the
headexport /routeLoader$(). routeLoader$()vs.useResource$()/useSignal(). Loaders run on the server and feed thehead; the others can run in the browser. For anything that must be in metadata or first-wave HTML, use the loader.- Smaller ecosystem. Qwik has far fewer CMSA content management system (CMS) is software that lets users create, manage, and publish digital content — like blog posts and pages — without writing raw code. WordPress, Drupal, and Joomla are the most common open-source CMS platforms. connectors and SEO plugins than Next.js, and a smaller community to draw on. The framework is capable; you’ll just write more glue yourself. builder.io’s own site runs on Qwik, so it’s used in production — but go in eyes-open about the maturity gap.
Where this sits
Qwik is one of two frameworks in the JavaScript frameworksJavaScript frameworks — React, Vue, Angular, Next.js, Nuxt, Svelte, Astro — are libraries or meta-frameworks for building web UIs. Their SEO impact depends on rendering mode: SSR and SSG deliver pre-rendered HTML; CSR-only apps require Googlebot to execute JavaScript before it can index content. story — the other being SolidJS. The key distinction to keep straight: Qwik resumes; SolidJS (and React, Vue, Angular) hydrate. Both still output content-rich HTML via their meta-frameworks, so crawlingCrawling is how search engines use automated bots (like Googlebot and Bingbot) to discover URLs and download pages. A page has to be crawlable to be indexed, but crawling on its own isn't a ranking factor. is fine either way; the resumability angle is what makes Qwik’s INP/TBT profile structurally the best of the group. For the metric side, see Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data.; for the foundations, the JavaScript SEOMaking sure search engines can crawl, render, and index content that depends on JavaScript. hub.
AI summary
A condensed take on the Advanced version:
- Qwik = resumability. At SSR it serializes event listeners (HTML attributes),
the component tree (HTML comments), and state (a
qwik/jsonscript) into the HTML, so the browser resumes instead of hydrating. This is categorically different from React/Vue/Angular/SolidJS, which all hydrate. It’s on its v2 line (currently beta) as of this writing — check the API against your installed version. - Content is in the HTML by default — for routes that are actually server- rendered. SSR/SSG is a per-route decision in QwikCity, not a project-wide guarantee. No client re-render step on those routes → crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. get complete content with no render-wave delay. Confirm on your own deployed URLs with view-source rather than assuming it from the framework alone.
- CWVGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. is a structural head start, not a guarantee. Sites boot with ~1 KB of JS (the Qwikloader — real JS that does run, not zero) regardless of complexity, so TBTTotal Blocking Time — the sum of the blocking portion (time above 50 ms) of every long task between First Contentful Paint and Time to Interactive. It's a lab-recommended metric and the lab proxy for INP, not a Core Web Vital. trends toward ~0 and INPInteraction to Next Paint — the input-to-paint latency at the 75th percentile of a page's interactions. ≤200 ms is good. stays low when nothing else on the page is blocking the thread. Confirm with field dataPerformance metrics captured from real users, not lab tests. (CrUXChrome User Experience Report — Google's public dataset of real-world (field) performance data from eligible Chrome users. It's the official field-data source behind the Core Web Vitals program. / Search Console) — third-party scripts and route-level data-fetching cost can offset the advantage.
- QwikCity is the meta-framework (Next.js for Qwik): SSR/SSG mixed per route,
file-system routing,
routeLoader$()for server-side data. - Metadata lives in the
headexport — title, meta, OG,canonical(inlinks), and JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal. (inscripts) — all server-rendered. For dynamic pages, makeheada function fed byrouteLoader$(); don’t set metadata from client-side effects. Thescriptsfield only outputs if yourrouter-headcomponent actually rendershead.scripts— check that it does before trusting the JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal. shows up. - SitemapsA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing.: automatic in SSG (
sitemapOutFile, limited to routes actually built); a dynamicsrc/routes/sitemap.xml/index.tsroute in SSR.robots.txtgoes in/public/. Canonical and sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. URLs both depend on the configuredorigin— a leaked preview/staging origin breaks both in production. - i18n:
rewriteRoutesfor localized URLs + Qwik Speak for content; hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others. viahead.links. - Watch out: non-serializable data (class instances, promises, streams) is
client-only, and a
noSerialize()-wrapped value comes backundefinedafter resume;useVisibleTask$()runs eagerly on the client and should be used sparingly; verify meta tagsMeta tags are HTML elements in a page's head that pass metadata about the page to search engines and browsers. For SEO only a few matter — the title element, the meta description, and the robots meta tag — while meta keywords and most others are ignored. are in view-source, not JS-injected; the ecosystem is smaller than React/Next.js.
Official documentation
Primary-source documentation from Qwik and the search engines.
Qwik / QwikCity
- Qwik documentation — Overview — the docs home; the ~1 KB JS and instant-loading claims.
- Resumability — the canonical explanation of the serialization mechanism and why it isn’t hydrationTurning HTML, CSS, and JavaScript into the final visual page and DOM..
- QwikCity overview — the meta-framework: routing, SSR/SSG, the “Next.js for Qwik” framing.
- Routing — file-system routing, the
Linkcomponent’s prefetch, and route rewrites. - Pages / DocumentHead — the
headexport,routeLoader$(), dynamic head, and structured dataStructured data is a standardized way of labeling page content (using the schema.org vocabulary in JSON-LD, Microdata, or RDFa) so search engines can understand its meaning. It's not a direct ranking factor — its value is rich results and entity understanding.. - Sitemaps —
sitemap.xmlgeneration androbots.txt. - Deployments — adapters, SSR/SSG platforms, and cache headers.
- JavaScript SEO basics — two-wave renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. and lazy-loaded content in the DOM.
- Core Web Vitals — CWVGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. as a ranking signal (INPInteraction to Next Paint — the input-to-paint latency at the 75th percentile of a page's interactions. ≤200 ms is good., LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good., CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good.).
Quotes from the source
On-the-record framing from Qwik’s creator and the official docs. Confirm wording against the live pages before treating any quote as final.
Miško Hevery — creator of Qwik, builder.io
- “HydrationTurning HTML, CSS, and JavaScript into the final visual page and DOM. is when an application is downloaded and executed twice, once as HTML and again as JavaScript.” — “Resumability vs HydrationActivating server-rendered HTML in the browser by attaching JavaScript handlers.,” builder.io. Read the post
- “Resumability is a way for a framework to recover its state without re-executing the application components on the client.” — “Resumability vs Hydration,” builder.io. Read the post
- “Hydration must execute before the app becomes interactive. Yes, the execution may be lazy, but the button will not process events until Hydration executes.” — “Resumability vs Hydration,” builder.io. Read the post
Qwik official docs (qwik.dev)
- “Your sites and apps can boot with about 1kb of JS (regardless of application complexity).” — Qwik Docs, Overview. Source
- “Qwik apps work instantly without any delay because they don’t need hydration, regardless of their size or complexity.” — Qwik Docs, Resumability. Source
- “QwikCity is to Qwik, as Next.js is to React, Nuxt is to Vue, SvelteKit to Svelte, and Analog is to Angular.” — QwikCity Docs, Overview. Source
- “Thanks to Qwik’s resumability and JavaScript streaming, there is no additional cost to the end user from Qwik City. (zero JavaScript).” — QwikCity Docs, Overview. Source
Qwik SEO checklist
A pass to confirm a QwikCity site is set up to rank:
- You’re using QwikCity (the meta-framework) with SSR or SSG — not the bare library in client-only mode.
- View-source shows your real content and
<a href>links in the raw HTML (not an empty shell). - Dynamic page data is fetched with
routeLoader$()(server-side), not a client-side effect. - Title, description, and OG tagsOpen Graph (OG) tags are `<meta>` elements in a page's head, defined by the Open Graph protocol (ogp.me, created by Facebook), that describe a page as a shareable object — its title, description, image, URL, and type. They control how a link preview card looks when the page is shared on Facebook, LinkedIn, Slack, Discord, WhatsApp, and iMessage. They are not a direct Google ranking factor, though Google reads og:title, og:image, and og:site_name as inputs to how a result appears. are set via the
headexport — and as a function fed byresolveValue()for dynamic pages. - Canonical URLs are in
head.linksas{ rel: 'canonical', href: '...' }. - JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal. is in
head.scriptswithtype: 'application/ld+json'. -
sitemap.xmlis configured —sitemapOutFilefor SSG, or asrc/routes/sitemap.xml/index.tsroute for SSR. -
robots.txtis in/public/. - Cache-ControlCaching stores a copy of a page or resource — in a browser, a CDN edge node, or a search crawler's own cache — so it can be served again without regenerating or re-downloading it. It isn't a direct ranking factor, but it feeds page speed and crawl efficiency. headers are set on SSR responses (edge SSR for low TTFBTime to First Byte — the time from the start of a request to when the first byte of the response arrives. It's a diagnostic metric (not a Core Web Vital) and a major input to FCP and LCP; ≤0.8 s is good.).
- hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others. tags are in
head.linksif the site is multilingual; localized URLs viarewriteRoutes. - INPInteraction to Next Paint — the input-to-paint latency at the 75th percentile of a page's interactions. ≤200 ms is good. / LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. / CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good. verified in the field (CrUXChrome User Experience Report — Google's public dataset of real-world (field) performance data from eligible Chrome users. It's the official field-data source behind the Core Web Vitals program. / Search ConsoleGoogle's free tool for monitoring crawling, indexing, and search performance.), not just lab.
- No critical content depends on non-serializable (class instances, promises, streams) client-only code.
The mental models
1. Resume, don’t replay. The single idea behind Qwik. Every other mainstream framework replays the app in the browser (hydrationTurning HTML, CSS, and JavaScript into the final visual page and DOM.) to make SSR HTML interactive. Qwik resumes from state serialized into the HTML, executing ~zero JS on load. If you internalize one thing, make it this.
2. The HTML is the content. Because there’s no client render step, what the crawlerA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. fetches is the finished page. There’s no second wave to wait on, no “did it render?” risk. Treat a Qwik page like static HTML for crawl/indexStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. purposes.
3. Server-side data → metadata.
The chain that decides whether your meta tagsMeta tags are HTML elements in a page's head that pass metadata about the page to search engines and browsers. For SEO only a few matter — the title element, the meta description, and the robots meta tag — while meta keywords and most others are ignored. are crawlable:
routeLoader$() (server) → head export function → HTML <head>. Break the
chain by fetching in a client effect and your title/OG/canonical fall out of the
first-wave HTML.
4. SSG vs. SSR is a hosting/freshness call, not an SEO call. Both put content in the HTML. Pick SSG for static content (free hosting, auto sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing.) and SSR for per-request data (run it at the edge, cache the responses). CrawlabilityCrawlability is how well search engine crawlers can discover, access, and fetch a site's pages. A crawlability issue is any technical condition — blocked access, broken links, server failures, or bloated URL inventory — that stops pages from reaching the index. is fine either way.
5. The performance win is INPInteraction to Next Paint — the input-to-paint latency at the 75th percentile of a page's interactions. ≤200 ms is good./TBTTotal Blocking Time — the sum of the blocking portion (time above 50 ms) of every long task between First Contentful Paint and Time to Interactive. It's a lab-recommended metric and the lab proxy for INP, not a Core Web Vital., not crawlabilityCrawlability is how well search engine crawlers can discover, access, and fetch a site's pages. A crawlability issue is any technical condition — blocked access, broken links, server failures, or bloated URL inventory — that stops pages from reaching the index.. React/Next.js already SSR content for crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index.. What Qwik adds is the absence of the hydrationActivating server-rendered HTML in the browser by attaching JavaScript handlers. tax — that’s where its CWV advantage lives. Don’t reach for Qwik to “fix crawlingCrawling is how search engines use automated bots (like Googlebot and Bingbot) to discover URLs and download pages. A page has to be crawlable to be indexed, but crawling on its own isn't a ranking factor. React can’t”; reach for it when responsiveness is the lever.
Qwik SEO — cheat sheet
Where each SEO element goes (all in the head export)
| Element | Where | Pattern |
|---|---|---|
| Title | head.title | string (or function for dynamic) |
| Meta descriptionThe meta description is an HTML head tag — `<meta name=\"description\" content=\"…\">` — that suggests a short summary of the page for the search snippet. It's not a Google ranking factor, and Google rewrites it the majority of the time, but a good one can still lift click-through. / OG | head.meta | [{ name/property, content }] |
| Canonical | head.links | { rel: 'canonical', href: '...' } |
| hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others. | head.links | { rel: 'alternate', hreflang, href } |
| JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal. | head.scripts | { props: { type: 'application/ld+json' }, script } |
| Dynamic data | routeLoader$() | server-side; read via resolveValue() |
SSG vs. SSR for SEO
| SSG (static adapter) | SSR | |
|---|---|---|
| Content in HTML | ✅ | ✅ |
| SitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. | Auto (sitemapOutFile) | Add a /sitemap.xml route |
| Hosting | Static files / CDN | Server / edge runtime |
| Best for | Stable content | Per-request / personalized |
| CachingCaching stores a copy of a page or resource — in a browser, a CDN edge node, or a search crawler's own cache — so it can be served again without regenerating or re-downloading it. It isn't a direct ranking factor, but it feeds page speed and crawl efficiency. | Inherent | Set Cache-Control yourself |
Resumability vs. hydrationTurning HTML, CSS, and JavaScript into the final visual page and DOM. (the one distinction that matters)
| HydrationActivating server-rendered HTML in the browser by attaching JavaScript handlers. (React/Vue/Angular/SolidJS) | Resumability (Qwik) | |
|---|---|---|
| Browser work on load | Re-execute components | Resume from serialized state |
| JS on load | Scales with app | ~1 KB (Qwikloader) |
| TBTTotal Blocking Time — the sum of the blocking portion (time above 50 ms) of every long task between First Contentful Paint and Time to Interactive. It's a lab-recommended metric and the lab proxy for INP, not a Core Web Vital. / INPInteraction to Next Paint — the input-to-paint latency at the 75th percentile of a page's interactions. ≤200 ms is good. | Higher | Near-zero |
| Content in HTML | Yes (with meta-framework) | Yes (always) |
Common mistakes
- ❌ Setting meta tagsMeta tags are HTML elements in a page's head that pass metadata about the page to search engines and browsers. For SEO only a few matter — the title element, the meta description, and the robots meta tag — while meta keywords and most others are ignored. from a client effect → not in first-wave HTML. Use
head+routeLoader$(). - ❌ Calling Qwik “lazy hydration” → it doesn’t hydrate at all; it resumes.
- ❌ Forgetting an SSR sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. → SSR has no auto sitemap; add the route.
Check Qwik’s generated HTML
Point BUILD_DIR at the HTML output from the production build:
BUILD_DIR=dist
find "$BUILD_DIR" -name '*.html' -type f | while IFS= read -r file; do
titles=$(grep -Eio '<title>[^<]*</title>' "$file" | wc -l | tr -d ' ')
canonicals=$(grep -Eio '<link[^>]+rel=["'"']canonical["'"'][^>]*>' "$file" | wc -l | tr -d ' ')
descriptions=$(grep -Eio '<meta[^>]+name=["'"']description["'"'][^>]*>' "$file" | wc -l | tr -d ' ')
if [ "$titles" -ne 1 ] || [ "$canonicals" -ne 1 ] || [ "$descriptions" -ne 1 ]; then
printf '%s\ttitle=%s\tcanonical=%s\tdescription=%s\n' "$file" "$titles" "$canonicals" "$descriptions"
fi
doneThis catches routes whose Qwik City head function is missing or duplicated. It does not replace checking field performance and rendered content on deployed URLs.
Patrick's relevant free tools
- SEO Incident Simulator — Practice thirty deterministic technical SEO incident investigations — indexability, crawl controls, redirects, sitemaps, markup, caching, DNS, bot verification, rendering, hreflang, and faceted navigation — with clearly labeled fixture evidence and Find → Fix → Verify handoffs.
- Raw vs. Rendered HTML Checker — See what's in your page's initial HTML versus after JavaScript runs — headless-Chrome rendering only when the page actually needs it, a rendering-strategy verdict (SSR / prerendered / CSR / hybrid), ~15 calibrated JavaScript-SEO checks (noindex, canonicals, robots.txt blocking, links, soft 404s), a side-by-side raw-vs-rendered diff, and shareable reports.
- Page Speed Test & Core Web Vitals Checker — One sentence tells you whether a page passes Core Web Vitals and what to fix first — real Chrome user data (CrUX) with a Lighthouse lab fallback, mobile and desktop side by side, loudly-labeled data sources, and prioritized diagnostic fixes. Plus a bulk origin scorecard with CSV export.
Tools for auditing a Qwik site
- View-source (
view-source:in the browser) — the fastest check: is your content, title, canonical, and JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal. actually in the raw HTML, or only in the rendered DOM? - Google Search ConsoleA free Google service that reports how a site performs in Google Search and surfaces problems with how Google crawls, indexes, and serves it. It's first-party data straight from Google — but you don't need it to appear in results. — URL InspectionA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version. — confirm the rendered HTML matches
the source: content present, no JS-injected
noindex, canonical resolved. - PageSpeed InsightsPageSpeed Insights (PSI) is a free Google tool at pagespeed.web.dev that reports two kinds of data for a URL: real-user field data from the Chrome UX Report and a single Lighthouse lab run with the 0–100 Performance score. Only the field Core Web Vitals are what Google uses for ranking. / CrUXChrome User Experience Report — Google's public dataset of real-world (field) performance data from eligible Chrome users. It's the official field-data source behind the Core Web Vitals program. — field Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. (INPInteraction to Next Paint — the input-to-paint latency at the 75th percentile of a page's interactions. ≤200 ms is good., LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good., CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good.). This is where Qwik’s resumability advantage should actually show up.
- Chrome DevTools (Performance / LighthouseLighthouse is Google's free, open-source tool that audits a page under simulated lab conditions and scores it 0–100 across Performance, Accessibility, Best Practices, and SEO. It's lab data — useful for debugging, not a ranking signal.) — lab TBTTotal Blocking Time — the sum of the blocking portion (time above 50 ms) of every long task between First Contentful Paint and Time to Interactive. It's a lab-recommended metric and the lab proxy for INP, not a Core Web Vital. and main-thread work; confirm the near-zero startup JS in practice.
- Rich ResultsRich results (formerly 'rich snippets') are enhanced search listings — stars, images, prices, breadcrumbs, video thumbnails, and more — that Google and Bing build from structured data. They're a display feature, not a ranking factor, and eligibility never guarantees they'll show. Test — validate the JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal. you added via
head.scripts. - Site crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. (Ahrefs Site Audit, Screaming Frog) — crawl the rendered site to check titles, canonicals, hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others., and internal linksAn internal link is a hyperlink from one page on a website to another page on the same website. Internal links help search engines discover your pages and pass ranking signals (PageRank and anchor-text context) between them. at scale.
Mistakes people actually make on Qwik
Resumability removes most of the JS-SEO risk that trips up other frameworks, but these are the real ways teams still shoot themselves in the foot on Qwik.
Setting metadata from a client-side effect
The mistake: pulling a post’s title or description into a useSignal() or
useResource$() that runs in the browser, then trying to set the page titleThe title tag is the HTML title element in a page's head that specifies the document's title. It's the primary source for the SERP title link and a confirmed light ranking factor — but since August 2021 Google doesn't always show it verbatim. from
that value.
Why it’s wrong: anything computed client-side runs after the server sends its response. It never makes it into the HTML GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. fetches on the first pass — it only shows up in the rendered DOM, which is exactly the render-wave delay resumability was supposed to avoid you.
What to do instead: fetch the data with routeLoader$() (server-side) and
make the route’s head export a function fed by resolveValue(), as shown in
the Advanced tab. That’s the only path that lands metadata in the first-wave
HTML.
Running Qwik without QwikCity
The mistake: using the bare Qwik library in client-only mode — no meta- framework, no server renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. — because “resumability doesn’t need hydrationActivating server-rendered HTML in the browser by attaching JavaScript handlers. so it doesn’t need SSR either.”
Why it’s wrong: resumability describes what happens after the HTML exists. If nothing renders the HTML on the server in the first place, there’s nothing to resume — you’re back to an empty shell for crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index., no different from any other client-only SPA.
What to do instead: use QwikCity (or another server-renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. adapter) for anything public-facing. It’s what actually produces the server-rendered HTML that gives Qwik its SEO advantage.
Assuming SSR gets an automatic sitemap
The mistake: shipping an SSR Qwik site and expecting sitemap.xml to
exist because it “just works” in the SSG build.
Why it’s wrong: the automatic sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. is a build-time feature of the
static adapter (sitemapOutFile). SSR sites render per request — there’s no
build step to generate a static XML file from, so nothing produces one unless
you add it.
What to do instead: add a route at src/routes/sitemap.xml/index.ts with
a RequestHandler that builds and returns the XML dynamically, as covered in
the Advanced tab.
Putting non-serializable data in anything the server needs to resume
The mistake: storing a class instance, an open promise, or a stream
reference in state that the head export or a server-rendered component
depends on.
Why it’s wrong: Qwik’s serialization only handles plain, serializable values — anything else can’t be written into the HTML at SSR time, which breaks the exact mechanism (Resumability) that makes Qwik’s SEO story work.
What to do instead: keep non-serializable objects client-only and out of
anything that feeds metadata or server-rendered markup. Convert to plain data
(a resolved value, not the promise or class instance) before it touches
routeLoader$() or head.
Calling Qwik “lazy hydration” in a client pitch or audit note
The mistake: describing Qwik’s behavior as a faster or lazier version of hydration when documenting an audit or briefing a dev team.
Why it’s wrong: it sets the wrong expectation — “lazy hydration” implies the browser eventually re-executes every component, just later. Qwik never re-executes components on load at all; that’s the whole point of resumability, and the distinction changes what you’d even look for when something’s slow.
What to do instead: use “resumes” and “resumability,” matching the docs’ own terminology, and check the Qwikloader’s ~1 KB boot script in DevTools if you need to prove the “no hydration” claim to a skeptical stakeholder.
Standing KPIs for a Qwik site
These are the numbers to track on an ongoing basis, not a one-time launch check — Qwik’s whole value proposition is a performance and crawlabilityCrawlability is how well search engine crawlers can discover, access, and fetch a site's pages. A crawlability issue is any technical condition — blocked access, broken links, server failures, or bloated URL inventory — that stops pages from reaching the index. story, so both sides need a metric.
INP (field)
What it tells you: whether real visitors are actually experiencing the low-hydrationTurning HTML, CSS, and JavaScript into the final visual page and DOM.-cost responsiveness Qwik is supposed to deliver. This is the metric Qwik’s architecture is most directly built to win.
How to pull it: Google Search ConsoleA free Google service that reports how a site performs in Google Search and surfaces problems with how Google crawls, indexes, and serves it. It's first-party data straight from Google — but you don't need it to appear in results.’s Core Web Vitals reportThe Google Search Console report (under Experience) that shows how your indexed URLs perform on the Core Web Vitals — LCP, INP, and CLS — using real-user field data from CrUX, grouped by device, status, and clusters of similar-performing URLs., CrUXChrome User Experience Report — Google's public dataset of real-world (field) performance data from eligible Chrome users. It's the official field-data source behind the Core Web Vitals program., or Patrick’s CWV Checker / Core Web Vitals History & Competitor Comparison for a per-URL or per-origin field read.
Benchmark / realistic range: Google’s published threshold is “good” at or under 200ms, “needs improvement” 200–500ms, “poor” above 500ms — the same threshold for every site, not Qwik-specific. A resumable site with a clean Qwikloader boot should sit comfortably in “good,” but a bloated per-interaction chunk or heavy third-party script can still push it up.
Cadence: monthly, or after any release that changes interaction handlers; CrUXChrome User Experience Report — Google's public dataset of real-world (field) performance data from eligible Chrome users. It's the official field-data source behind the Core Web Vitals program. data itself is a rolling 28-day window.
TBT (lab)
What it tells you: how much main-thread work is happening on load in a controlled test — this is where you’d catch a regression before it shows up in field INPInteraction to Next Paint — the input-to-paint latency at the 75th percentile of a page's interactions. ≤200 ms is good..
How to pull it: LighthouseLighthouse is Google's free, open-source tool that audits a page under simulated lab conditions and scores it 0–100 across Performance, Accessibility, Best Practices, and SEO. It's lab data — useful for debugging, not a ranking signal. or Chrome DevTools’ Performance panelThe Performance panel is Chrome DevTools' built-in, local profiler for recording and analyzing how a page loads and runs — CPU, main-thread work, rendering, network, and live Core Web Vitals. The recorded trace is local, lab data from your own browser — not what Googlebot sees — though the panel can optionally show real-user CrUX field data alongside it., run against the live URL (not localhost, where results skew low).
Benchmark / realistic range: there’s no universal “good Qwik” number —
it depends on what’s on the page (third-party scripts, image decode work,
route-level routeLoader$() cost). What you’re checking for is that TBTTotal Blocking Time — the sum of the blocking portion (time above 50 ms) of every long task between First Contentful Paint and Time to Interactive. It's a lab-recommended metric and the lab proxy for INP, not a Core Web Vital.
stays near-zero relative to a hydrating equivalent of the same page, not
against a fixed target.
Cadence: before/after any deploy that adds a third-party script, analytics tag, or new interactive component.
Indexed page coverage
What it tells you: whether Google is actually crawlingCrawling is how search engines use automated bots (like Googlebot and Bingbot) to discover URLs and download pages. A page has to be crawlable to be indexed, but crawling on its own isn't a ranking factor. and indexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. the pages you expect — the practical proof that “content is in the HTML by default” is translating into indexing, not just a theoretical advantage.
How to pull it: Search ConsoleGoogle's free tool for monitoring crawling, indexing, and search performance.’s Page Indexing reportThe Google Search Console report (formerly Index Coverage) showing how many of your URLs are indexed vs. not indexed, and grouping the not-indexed ones by reason., filtered to the Qwik site’s URL prefix; cross-check against your sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing.’s submitted-URL count.
Benchmark / realistic range: depends entirely on site size and how much of it you intend to have indexed — there’s no fixed target. Track the trend (indexed count moving toward submitted count) rather than chasing a specific number.
Cadence: weekly during and after a migration to Qwik; monthly once stable.
JS transferred on load
What it tells you: whether the “boots with ~1 KB” claim is holding up in practice, or whether third-party scripts and oversized initial chunks have eaten into Qwik’s structural advantage.
How to pull it: the Network panel in Chrome DevTools, filtered to JS, on a cold load with cache disabled.
Benchmark / realistic range: the Qwikloader itself is roughly 1 KB; anything meaningfully larger on initial load is coming from something else on the page (analytics, ads, a polyfill) — investigate rather than compare against a fixed number, since page-to-page variance is expected.
Cadence: after any change to third-party tags, analytics, or shared layout components.
Test yourself: Qwik SEO
Five quick questions on resumability and getting a QwikCity site to rank. Pick an answer for each, then check.
Resources worth your time
My related writing
- JavaScript SEO: A Definitive Guide — renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM., DOM parityWhether the rendered DOM matches what you expect the raw HTML to become., and getting JS-built content indexedStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed.; the foundation a Qwik audit builds on.
- Core Web Vitals: A Complete Guide — what INPInteraction to Next Paint — the input-to-paint latency at the 75th percentile of a page's interactions. ≤200 ms is good., LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good., and CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good. measure and how they factor into SEO — the metrics Qwik’s architecture optimizes.
- The Beginner’s Guide to Technical SEO — where framework choice and renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. fit in the bigger picture.
My speaking
- How Search Works (SlideShare) — my walkthrough of crawlingCrawling is how search engines use automated bots (like Googlebot and Bingbot) to discover URLs and download pages. A page has to be crawlable to be indexed, but crawling on its own isn't a ranking factor., rendering, indexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed., and ranking — the pipeline a Qwik site has to clear. (My standing disclaimer applies: “This is my understanding of systems… not going to be 100% complete or accurate.”)
From around the industry
- Qwik — Resumability — the clearest primary-source explanation of how serialization replaces hydrationActivating server-rendered HTML in the browser by attaching JavaScript handlers..
- QwikCity overview — the meta-framework: routing, SSR/SSG, loaders.
- Qwik — Pages / DocumentHead — the
headexport,routeLoader$(), dynamic head, and structured dataStructured data is a standardized way of labeling page content (using the schema.org vocabulary in JSON-LD, Microdata, or RDFa) so search engines can understand its meaning. It's not a direct ranking factor — its value is rich results and entity understanding.. - Qwik — Sitemaps — sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing..xml generation and robots.txtA plain-text file at the root of a host that tells crawlers which URLs they may and may not request. It controls crawling, not indexing — a blocked URL can still be indexed if it's linked from elsewhere..
- Builder.io — Resumability vs Hydration — Miško Hevery on why hydration is “executed twice” and how resumability avoids it.
- Google — JavaScript SEO basics — two-wave rendering and what crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. do with JS.
- r/TechSEO — the community for debugging framework rendering and indexing questions.
Qwik SEO
Qwik SEO is the practice of optimizing sites built with Qwik, a JavaScript framework whose 'resumability' model serializes app state into HTML so the browser never has to hydrate. Content is in the HTML by default, so crawling, indexing, and Core Web Vitals are all structurally strong.
Related: JavaScript SEO, Core Web Vitals
Qwik SEO
Qwik is a JavaScript framework — built by Miško Hevery (creator of Angular) at builder.io — whose headline innovation is resumability. Instead of hydrating (downloading and re-executing the app in the browser to make server-rendered HTML interactive, the way React, Vue, Angular, and SolidJS all do), Qwik serializes the app’s event listeners, component tree, and state directly into the HTML on the server. The browser then resumes from where the server left off without re-executing components — though a ~1 KB “Qwikloader” script still runs on load to listen for events, so it isn’t literally zero JavaScript.
For SEO this matters in two ways, on routes that are actually server-rendered (SSR or SSG — a per-route choice in QwikCity, not a project-wide guarantee). First, the content is in the HTML by default — there’s no client render step, so crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. see complete content in the first wave with no renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM.-queue delay. Second, because there’s no hydrationActivating server-rendered HTML in the browser by attaching JavaScript handlers. blocking the main thread on load, INPInteraction to Next Paint — the input-to-paint latency at the 75th percentile of a page's interactions. ≤200 ms is good. and TBTTotal Blocking Time — the sum of the blocking portion (time above 50 ms) of every long task between First Contentful Paint and Time to Interactive. It's a lab-recommended metric and the lab proxy for INP, not a Core Web Vital. trend toward near-zero, which is exactly what Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. reward — worth confirming with field dataPerformance metrics captured from real users, not lab tests. rather than assuming it.
QwikCity is Qwik’s meta-framework (what Next.js is to React): file-system routing, SSR and SSG mixable per route, routeLoader$() for server-side data fetching, and a head export for managing title, meta, Open GraphOpen Graph (OG) tags are `<meta>` elements in a page's head, defined by the Open Graph protocol (ogp.me, created by Facebook), that describe a page as a shareable object — its title, description, image, URL, and type. They control how a link preview card looks when the page is shared on Facebook, LinkedIn, Slack, Discord, WhatsApp, and iMessage. They are not a direct Google ranking factor, though Google reads og:title, og:image, and og:site_name as inputs to how a result appears., canonical, and JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal. — all server-rendered. Basic SEO works out of the box; the main discipline is using routeLoader$() for dynamic metadata instead of client-side effects. The trade-off is a newer, smaller ecosystem than React or Vue. As of this writing, Qwik is on its v2 line, currently in beta.
Related: JavaScript SEO, Core Web Vitals
Build-time retrieval analysis plus live signals for this exact article. The automatic chunk report includes a deterministic readiness score and is ready without a model download.
Search Console
sampleGA4 traffic (28d)
sampleCloudflare traffic (7d)
sampledCrUX field data (28d, phone)
sampleGoogle NLP entities
localChangelog
Updated Jul 18, 2026.
Editorial summary and recorded change details.Summary
Corrected an unqualified 'zero JavaScript on load' claim (the ~1 KB Qwikloader is real JS that runs), reframed SSR/SSG and 'content is in the HTML' claims as per-route rather than project-wide, added a router-head.tsx rendering caveat to the JSON-LD example (verified live against current qwik.dev docs), noted Qwik's current v2-beta status, and added noSerialize()/useVisibleTask$() failure-mode notes.
Change details
-
Fixed beginner-lens claim of 'roughly zero JavaScript on load' — Qwik still runs a ~1 KB Qwikloader script; content now matches the Advanced lens's accurate description.
-
Reframed 'content is in the HTML by default' and CWV claims across Beginner/Advanced/AI Summary as conditional on a route actually being server-rendered (SSR/SSG is a per-route QwikCity decision), with a pointer to confirm via view-source and field data.
-
Added a caveat to the JSON-LD section: the head export's scripts field only renders if the project's router-head component actually outputs head.scripts (e.g. via dangerouslySetInnerHTML) — verified live against current qwik.dev Pages docs.
-
Added an origin/base caveat to the sitemap section (canonical and sitemap URLs depend on configured origin) and noted SSG sitemaps only include routes actually built.
-
Noted Qwik is currently on its v2 line (beta) as of this writing, and added noSerialize()-returns-undefined and useVisibleTask$()-as-eager-escape-hatch notes to the pitfalls list. The v2-beta status and useVisibleTask$() behaviour were verified live against qwik.dev; the noSerialize() behaviour could not be re-fetched during this pass (the serialization docs URL 404'd) and rests on corroboration from Qwik's serialization guide as cited in next-gen-frameworks.
Full comparison unavailable — no prior snapshot was archived for this revision.