The short answer
dardo.studio is an Astro site served by a Cloudflare Worker, with content in a headless CMS and every page in English, Spanish and Portuguese. Over 28 days, from 24 September to 22 October 2026, the 75th percentile of real page views was 1,114 ms for Largest Contentful Paint (LCP), 80 ms for Interaction to Next Paint (INP) and 0.08 for Cumulative Layout Shift (CLS). Google's good thresholds are 2.5 seconds, 200 ms and 0.1, so the site as a whole passes.
The averages hide two problems. On large screens the home page's CLS p75 was 0.239, more than twice the limit, because a hover effect rearranged a grid; we fixed it on 22 October. On phones the home page's INP p75 was exactly 200 ms, good with no margin, and still unexplained. In the lab our pages scored 90 to 99 on mobile, and the weak spot is JavaScript: about two-thirds of it on a content page is analytics.
How the site is built, and why each piece
- Astro 7.3.2 with static output, because a marketing page should be HTML first: Astro strips client-side JavaScript from components unless one is marked as an interactive island. One route, /preview/, renders on request so the CMS can show drafts.
- A Cloudflare Worker, through the @astrojs/cloudflare adapter 14.3.4, so redirects, language routing, the contact form's API and our free tools' server checks live next to the files it serves.
- EmDash, a headless CMS on Cloudflare, so editors publish without a developer and visitors never wait on a CMS query. It holds the pages, 41 service pages, case studies, articles, tools, interface text and settings; a publish triggers a rebuild through Workers Builds that goes live a few minutes later. More in headless CMS development.
- Cloudflare D1, a SQLite database, for inquiries and our own Core Web Vitals readings (kept 35 days), so we own the field data; R2 for media.
- Three languages for the US, Latin America and Brazil, with hreflang alternates: 418 URLs in the sitemap on 22 October 2026, 145 in English. See multilingual websites.
Everything except the draft preview changes when an editor publishes, not when a visitor arrives, so it is built once and served as files. Our Astro vs Next.js comparison covers when that trade goes the other way.
Field data: what real visitors got
These numbers come from our own measurement, not Google's Chrome UX Report. Each page view sends its Core Web Vitals, Time to First Byte (TTFB) and First Contentful Paint (FCP) to a D1 table. We report the 75th percentile, as Google's guidance does, split into phone-sized and large (tablet and desktop) viewports. Collection follows the visitor's analytics choice, so browsers that opt out or send Do Not Track or Global Privacy Control are not in the sample. The samples are small: read rows with a low n as direction, not proof.
| Page type, screen | LCP p75 | INP p75 | CLS p75 | TTFB p75 |
|---|---|---|---|---|
| All pages, all screens | 1,114 ms (n=1,414) | 80 ms (n=883) | 0.08 (n=1,223) | 457 ms (n=1,712) |
| All pages, phones | 1,016 ms (n=291) | 184 ms (n=183) | 0.001 (n=153) | 489 ms (n=389) |
| All pages, large screens | 1,192 ms (n=1,123) | 64 ms (n=700) | 0.089 (n=1,070) | 438.9 ms (n=1,323) |
| Home, phones | 1,018 ms (n=182) | 200 ms (n=148) | 0.0 (n=75) | 476 ms (n=232) |
| Home, large screens | 792 ms (n=607) | 56 ms (n=465) | 0.239 (n=574) | 380.9 ms (n=663) |
| Service pages, phones | 640 ms (n=42) | 48 ms (n=14) | 0.067 (n=32) | 485 ms (n=47) |
| Service pages, large screens | 716 ms (n=96) | 64 ms (n=42) | 0.089 (n=89) | 475.6 ms (n=129) |
| Articles, phones | 1,076 ms (n=13) | 40 ms (n=2) | 0.001 (n=13) | 281.8 ms (n=13) |
| Articles, large screens | 648 ms (n=30) | 40 ms (n=8) | 0.005 (n=32) | 162.3 ms (n=55) |
LCP is the strongest result: 90% of readings were good, and the slowest row, all pages on large screens, is 1,192 ms. TTFB p75 was 457 ms, under the 0.8 seconds web.dev calls good, and FCP p75 was 1,068 ms against a good mark of 1.8 seconds. Of the six page-type and screen rows, five pass all three Core Web Vitals; the home page on large screens fails on CLS. INP splits by device, 64 ms on large screens and 184 ms on phones, and 148 of the 183 phone INP readings came from the home page, the one page with heavy artwork.
What failed, and what we changed on 22 October
Our D1 table stores values without attribution, so on 21 and 22 October we found each cause by reproducing it in a browser with performance traces.
Home page layout shift on large screens
CLS p75 was 0.239 (n=574), with only 65% of readings good; a 21-day slice read 0.306. Hovering a card in the services mosaic expanded it by changing the grid's columns, so every card around it moved, and each hover shifted the layout by 0.13 to 0.26. A hover isn't a discrete input like a click, so the browser doesn't excuse its shifts as it does those within 500 ms of a click. Phones have no hover, which fits their 0.0.
Cards now keep one origin and move with CSS transforms, which don't change layout. A lab sweep that hovers every card went from 0.331 to 0.0008. The trade-off: the mosaic's artwork can sit up to 1 px from its resting place. The field number needs a few weeks of new data to move.
Phone INP on the home page
INP p75 on phones was 200 ms (n=148), 75% good. A 21-day slice read 232 ms (n=126); since 15 October it was 128 ms, on 32 readings. The worst interaction we can produce in the lab takes 64 ms. The one slow interaction we caught landed on a 295 ms startup frame with no long script, which points at the GPU or a shader compile for the WebGL artwork. Making five per-frame attribute writes run only on change cut DOM mutations by 23% but left the lab at 64 ms. It stays open. Adding attribution to our own measurement, as our guide to fixing INP describes, would point at the frame or script behind it.
Service page shifts and a slow work hub
Service pages on large screens had a CLS p75 of 0.089, yet four readings within three minutes on 21 October came in at 0.223. Covers used aspect-ratio: auto, so text jumped about 435 px when the image arrived, and intros sized in ch units grew 24% wider when the brand font loaded. Covers now reserve their ratio, those widths have an em floor and fallback fonts are scaled to the brand fonts. In the lab, service pages went from 0.03 to 0.21 down to 0.04 or less, and tablet layouts from as much as 0.50 to 0.004 or less.
The work hub's desktop LCP p75 was 4,740 ms in a 21-day slice (n=36; 2,868 ms over 28 days, in a page type that also holds case studies). Its largest element, a blurred backdrop, had no fetchpriority while hidden rows' images got the boost. Hero images now load at high priority, the rest at low, and a 4.4 MB film waits for its poster. Lab LCP fell from 1.80 to 1.45 seconds at 1x pixel density and from 2.20 to 1.57 at 2x, on an HTTP/2 server that honors priority.
Lab data and page weight against platform medians
We ran Lighthouse 12.8.2 locally on 22 October 2026 and report the second mobile run, because the first run after a rebuild hits a cold cache. Lighthouse's documentation notes that much run-to-run variation comes from outside the tool.
| Page | Mobile score | Mobile LCP | Mobile CLS | Desktop score | Desktop LCP |
|---|---|---|---|---|---|
| Home | 96 | 1.6 s | 0.000 | 95 | 0.6 s |
| Service: Astro development | 90 | 3.5 s | 0.000 | 99 | 0.7 s |
| Article: Framer to Astro | 96 | 2.8 s | 0.000 | 99 | 0.8 s |
| Tool: redirect map generator | 99 | 1.8 s | 0.000 | 100 | 0.4 s |
The service page's mobile LCP of 3.5 seconds and the article's 2.8 are past the 2.5-second line, while real visits to those page types had p75 LCP between 640 and 1,076 ms. Lighthouse's mobile run simulates a slow phone on a throttled connection, slower than our field data suggests most visitors have, so we treat it as a regression alarm and the field data as the verdict. Lab CLS was 0.000 everywhere, which is why the hover shift went unnoticed: a page-load test doesn't hover.
Page weight against typical sites on each platform
The HTTP Archive measures the home pages of sites it detects on each platform. The platforms' audiences differ, so its medians describe typical sites, not what a careful build achieves. Ours are Lighthouse transfer sizes, one run per page.
| Page or platform | Total | JavaScript | Images | Lighthouse mobile |
|---|---|---|---|---|
| dardo.studio home | 1,168 KB | 709 KB | 218 KB | 96 |
| dardo.studio service page | 820 KB | 433 KB | 207 KB | 90 |
| dardo.studio article | 716 KB | 432 KB | 120 KB | 96 |
| dardo.studio tool page | 663 KB | 440 KB | 43 KB | 99 |
| Astro median, 47,277 origins | 1,326 KB | 399 KB | 346 KB | 70 |
| Framer Sites median, 11,319 origins | 3,011 KB | 797 KB | 934 KB | 67 |
| Webflow median, 59,483 origins | 3,398 KB | 904 KB | 793 KB | 62 |
| WordPress median, 2,658,175 origins | 2,656 KB | 661 KB | 1,017 KB | 43 |
Each of our pages is lighter in total than the median Astro home page and less than half the Framer, Webflow and WordPress medians, and carries fewer image bytes than any of them. JavaScript is the exception: every page ships more than the Astro median's 399 KB.
Pass rates tell a quieter story. In September 2026, 71.1% of Astro origins passed all three Core Web Vitals on mobile, close to Framer at 70.8% and Webflow at 71.3%, and well above WordPress at 48.3%. On desktop the figures were 84.6%, 87.9%, 82.6% and 53.7%. A lighter median page doesn't guarantee a pass; the build decides.
Where the JavaScript goes
Content pages carry about 432 KB of JavaScript. About 287 KB is analytics, loaded from third parties or through our proxy: Google's tag (gtag.js, 160 KB) and PostHog's recorder, surveys, autocapture and web-vitals modules (about 127 KB). Our own scripts are about 145 KB, a 96 KB shared interface bundle plus small page modules. Fonts add 126 KB. The home page carries 709 KB because of its interactive artwork, a WebGL dart flight driven by scrolling.
So two-thirds of the script on an article or service page is measurement, not the page. It costs transfer, plus parsing and running on the phone's main thread, the thread INP depends on. Content pages still answer quickly in our field data, with INP p75 of 40 to 64 ms on small samples. We keep the analytics because they show which pages and tools lead to inquiries; if the numbers slip, the cheaper moves are fewer PostHog modules, loading them later or dropping one tool. A speed optimization project should start the same way: list every script, its size and who needs it.
What it costs to run
The fixed platform cost is USD 5 a month, the Cloudflare account's Workers Paid plan, verified in the account's subscriptions on 22 October 2026. R2 and Stream are on usage-based plans with no base fee, the zone is on Cloudflare's free plan, and the domain and CMS run on the same account.
As of October 2026, Workers Paid includes 10 million requests and 30 million CPU milliseconds a month, then USD 0.30 per additional million requests and USD 0.02 per additional million CPU milliseconds. Requests to static assets are free and unlimited, which matters for a site that is almost all static files. D1 includes 25 billion rows read, 50 million rows written and 5 GB of storage a month, and egress from R2 is free.
The USD 5 excludes usage above those amounts, R2 and Stream usage, the domain registration, services outside Cloudflare such as analytics, and people's time. We don't publish the account's invoices, so read it as the floor, not our monthly bill.
How the site serves AI crawlers and agents
- robots.txt allows search and AI crawlers, with Content-Signal preferences of search=yes and ai-input=yes.
- /llms.txt (42 KB) and /llms-full.txt (about 877 KB), generated from the CMS.
- A Markdown copy of every page: add index.md to the address, or send Accept: text/markdown.
- A public, read-only MCP endpoint at /mcp and an A2A agent card at /.well-known/agent-card.json that answer questions about our published services from the same content as the pages.
What we can't claim: we know of no AI search vendor that documents an effect of llms.txt, Markdown copies or an MCP endpoint on whether a page gets cited. We publish them because they are cheap to generate from structured content and useful to agents that read them. Our llms.txt guide covers what the file is and who reads it, and the AI visibility checker shows how your robots.txt treats each AI crawler. We expect crawlable HTML, specific facts and named sources to matter more.
What this means if you are considering Astro
Astro made it easy to keep content pages light: our own code on an article is about 145 KB of JavaScript, and nothing runs unless we add it. It didn't prevent our two problems. A hover effect broke CLS and WebGL artwork is the suspect for phone INP; both were design decisions that would cause the same trouble on any platform.
Astro fits when the site is mostly content that changes on publish, you want the code, hosting and data in your own accounts, and you have developers to own the templates. It is the wrong move when your marketing team edits layouts visually every week and the current site already passes Core Web Vitals; Framer and Webflow pass rates are close to Astro's. A migration should buy something specific: code you own, a backend the builder can't provide, or control over every script.
Astro on Cloudflare Workers is our default stack for Astro development, and we run migrations from Framer to Astro, Webflow to Astro and WordPress to Astro.
How to measure your own site
- Start with context: our website platform speed report shows the HTTP Archive's latest month for your platform.
- Get field data. Google's Chrome UX Report only covers pages and origins with enough Chrome visitors; if yours falls short, send Core Web Vitals from the browser to your own store, as we do with D1.
- Report p75 with the sample size, by page type and screen size. Our site-wide numbers passed and hid both problems.
- Run Lighthouse twice, keep the second run and use it to catch regressions, not as the verdict.
- Test what a load test skips: hover, menus, scrolling artwork. Our worst layout shift lived there.
- Fix one cause at a time, then wait for new field data before calling it fixed.
Our guide to passing Core Web Vitals covers each metric's usual causes and fixes.
Common questions
Is an Astro site faster than a Framer or Webflow site?
Not automatically. In September 2026 the median Astro home page weighed 1,326 KB on mobile, against 3,011 KB for Framer and 3,398 KB for Webflow, yet the share passing Core Web Vitals on mobile was about the same: 71.1%, 70.8% and 71.3%. Astro ships no JavaScript unless you add it; whether a site passes depends on what you add.
Why does Lighthouse report a slower LCP than real visitors see?
Its mobile run simulates a slow phone on a throttled network, slower than most of our visitors appear to have. Our Astro development page had a 3.5-second LCP in the lab, while real visits to service pages had a p75 LCP of 640 ms on phones and 716 ms on large screens. Use the lab to catch regressions and field data to judge what visitors get.
How much does it cost to host an Astro site on Cloudflare Workers?
Our fixed cost is the Workers Paid plan, USD 5 a month as of October 2026, with 10 million requests and 30 million CPU milliseconds included and static asset requests free. Usage above that, storage, video, the domain and outside tools cost extra, so check Cloudflare's pricing against your own traffic.
Do llms.txt files or an MCP endpoint get a site cited in AI answers?
We know of no AI search vendor that documents such an effect. We publish /llms.txt, Markdown copies and a read-only MCP endpoint because they are cheap to generate from CMS content and useful to agents that read them. Treat them as a convenience, not a lever, and keep crawlable HTML and sourced facts right.
How many readings do you need before field data means something?
There is no single number. Report the sample size next to every p75 and read small slices as direction. Our site-wide LCP rests on 1,414 readings, while articles on phones rest on 13 and their INP on 2, so we draw no conclusion from those rows alone.
Sources & further reading
Sources behind this page, with further detail from the original publishers.
- HTTP Archive: Technology reporthttparchive.org
- web.dev: Web Vitalsweb.dev
- web.dev: Largest Contentful Paint (LCP)web.dev
- web.dev: Interaction to Next Paint (INP)web.dev
- web.dev: Cumulative Layout Shift (CLS)web.dev
- web.dev: Time to First Byte (TTFB)web.dev
- web.dev: First Contentful Paint (FCP)web.dev
- Chrome for Developers: CrUX methodologydeveloper.chrome.com
- Chrome for Developers: Lighthouse performance scoringdeveloper.chrome.com
- Astro Docs: Islands architecturedocs.astro.build
- Astro Docs: @astrojs/cloudflaredocs.astro.build
- Cloudflare Docs: Workers pricingdevelopers.cloudflare.com
- Cloudflare Docs: D1 pricingdevelopers.cloudflare.com
- Cloudflare Docs: R2 pricingdevelopers.cloudflare.com
- Cloudflare Docs: Workers Buildsdevelopers.cloudflare.com
