The page is not busy. It is waiting.

The first number worth looking at on duda.co is not the score. It is total blocking time on mobile: 0 ms.

Total blocking time measures how long the main thread was tied up and unable to respond. Zero means the browser had nothing hard to do. No framework was hydrating, no script was parsing for seconds, nothing was jammed. And yet the largest element on the page did not finish drawing until 16.8 seconds in.

That combination rules out most of the usual advice before you start. There is no JavaScript to defer that would matter, and no third-party tag manager to blame. The page is idle, and it is idle because it is waiting for the network.

26 megabytes, and 92% of them are video

The resource inventory from the mobile run:

TypeRequestsBytes
Video (MP4)1824.8 MB
Images752.47 MB
Fonts8214 KB
Stylesheets1191 KB
Document183 KB
Total11327.1 MB

Weight of duda.co by resource type: video 24.8 MB of 27.1 MB total

Every byte the mobile run downloaded, by resource type. The stylesheets everyone tells you to minify are the sliver on the right.

Those 18 media requests cover 11 distinct files: video is fetched in byte ranges, which the CDN advertises, so the request count runs ahead of the file count.

$ curl -sI 'https://vid.cdn-website.com/a8ff2f1c/videos/XNjIfA1PQ76lAJIY1eRP_Drag+v3-v.mp4'

HTTP/1.1 200 OK
Content-Type: video/mp4
Content-Length: 664135
Accept-Ranges: bytes
Cache-Control: max-age=31536000

For scale: the entire CSS of this page is 91 KB, which is 0.3% of its weight. You could delete every stylesheet on duda.co and a visitor on a phone would not notice the download finish any sooner. That is worth saying plainly, because most speed advice — minify, inline, strip unused rules — is aimed at that 0.3%.

The bug is one attribute, and the page already knows the fix

Here is one of the eleven video elements that autoplay:

<video src="https://vid.cdn-website.com/…/XNjIfA1PQ76lAJIY1eRP_Drag+v3-v.mp4"
       data-src="https://vid.cdn-website.com/…/XNjIfA1PQ76lAJIY1eRP_Drag+v3-v.mp4"
       poster="https://irp.cdn-website.com/…/XNjIfA1PQ76lAJIY1eRP_Drag+v3.v2.0000000.jpg"
       loop="true" muted="true" autoplay="true" playsinline="true">
</video>

Screenshot of duda.co with an autoplaying video element outlined

One of the eleven, outlined in blue on the live page. It is a decorative loop in a feature card — and it starts downloading whether or not the visitor ever scrolls this far.

No preload attribute — and it would not help if there were one. preload is a hint about what to fetch before playback; autoplay says playback starts now. A video that plays has to download, so autoplay silently overrides every economy you tried to make.

Now here are the other three video elements on the same page:

<video playsinline webkit-playsinline muted loop preload="metadata" class="video">
  <source src="https://vid.cdn-website.com/…/Deliver+sites+that+perform3-v.mp4" type="video/mp4">
</video>

preload="metadata", no autoplay. That is the correct pairing, it is on this very page, and it accounts for three of the fourteen videos. Nobody made a bad decision here — two component variants coexist in one builder, and the page collected eleven of one and three of the other. This is what platform performance problems usually look like from the inside.

Note the poster attribute in the first snippet. Every one of these elements already ships a poster frame. The bytes to show something in that box are already downloading; the megabytes are optional.

Seven stylesheet preloads, all of them inside the body

<!-- …roughly 200 KB into the document, inside <body> -->
<link rel="preload" as="style" fetchpriority="low" onload="loadCSS(this)"
      href="https://static.cdn-website.com/…/d-css-runtime-flex-new-nav.min.css" />
<link rel="preload" as="style" fetchpriority="low" onload="loadCSS(this)"
      href="https://irp.cdn-website.com/…/a8ff2f1c_home_withFlex_1.min.css?v=428" id="homeCssLink" />

The pattern itself is textbook async CSS: preload as a stylesheet, swap it in on load, never block rendering. The placement undoes it. A browser’s preload scanner races ahead through the head to start downloads while the parser is still working; a hint sitting a couple hundred kilobytes into the body cannot be found early, because “early” is the part the scanner already passed.

All seven of them are in the body. Moving them into <head> is a cut and paste — the tags need no edits — and it is one of the first things the proxy does here.

Three of those seven are font stylesheets, and they look like this:

https://irp.cdn-website.com/fonts/css2?family=Abel:ital,wght@0,400
  &family=Syne:ital,wght@0,400..800;1,400..800
  &family=Tenor+Sans:ital,wght@0,400
  &family=Fahkwang:ital,wght@0,200;0,300;0,400;0,500;0,600;0,700;1,200;…
  … ~30 more families …
  &subset=latin-ext&display=swap

Three requests, roughly sixty font families between them, for a page that renders a handful. Each URL is over a kilobyte of query string before the response is even considered.

102 images with no dimensions, and a lab CLS of 0.003

<img class="image"
     srcset="https://irp.cdn-website.com/…/Deliver+sites+that+perform-c0c7c056.jpg"
     alt="" onerror="handleImageLoadError(this)"/>

No width, no height. That is true of 102 of the 115 img tags on the page.

The interesting part is what Lighthouse says about it: mobile CLS is 0.003. Essentially zero. A reader who trusts that number would conclude the page has no layout stability problem at all, and would be wrong — the lab run loads on a fast wire into a fixed viewport, where images arrive before the pixels they displace are on screen. We measured how far apart the lab number and the markup can sit across our whole audit base; that study is linked at the bottom of this page.

The proxy computes the real aspect ratio server-side from the image headers and writes it into the markup, so the box is reserved without anybody having to open a design file.

The HTML is gzip, and brotli is sitting right there

$ curl -sI -H 'Accept-Encoding: gzip, br' https://www.duda.co/

HTTP/1.1 200 OK
Content-Type: text/html;charset=utf-8
Content-Encoding: gzip
Content-Length: 80013
Cache-Control: no-cache, must-revalidate
Vary: Accept-Encoding,user-agent,accept-encoding

The client offered brotli and got gzip. We compressed the stored copy of this page both ways to see what that costs:

BytesOf original
Uncompressed HTML406,338100%
gzip −983,78720.6%
brotli −1165,43316.1%

18 KB, or 22% off the document, for a server setting. On a page carrying 27 MB it is not what fixes the score — but it is free, it applies to every page on the site rather than this one, and it lands in the first round trip where bytes are worth the most.

What we changed, and what we did not

Through the proxy the same page’s largest element lands at 5.3 s instead of 16.8, and its mobile score moves from 65 to 71.

Metric (mobile)OriginalThrough WebSpeed
PageSpeed score6571
First Contentful Paint4.1 s3.9 s
Speed Index4.1 s3.9 s
Largest Contentful Paint16.8 s5.3 s
Time to Interactive16.9 s5.8 s
Total Blocking Time0 ms20 ms

What the filter log actually did, in order of how much it mattered: hoisted the body’s async-CSS preloads into the head, deferred the body scripts to first interaction, inlined nine small stylesheets (30 KB → 9.7 KB gzipped) so they stop being separate round trips, computed aspect ratios for the 24 unsized images, and lazy-loaded everything below the fold — which took images from 75 requests / 2.47 MB down to 20 requests / 671 KB.

Filmstrip comparing duda.co before and after WebSpeed on a shared timeline

Both runs on one timeline, throttled mobile. WebSpeed has the hero on screen by 0.5 s; the original is still blank and arrives around 1.0 s.

Now the part that matters more than the score. The video is still there. 17.8 MB of MP4 still downloads through the proxy. We did not remove a single one, and we would not — deciding that a company’s hero video should not exist is not a proxy’s call to make.

That is why the score moved only six points while the largest element went from 16.8 s to 5.3 s: the visible load is three times faster, but 18 MB of video still has to arrive, and PageSpeed keeps scoring the weight. Page weight is not the metric the visitor feels. Arrival order is.

Why this is not a Duda problem

It would be easy to read this as “builders are slow”. The measurement does not support that. Duda served the HTML compressed from a CDN, with images already in WebP and a poster frame on every video — decisions the platform got right and that hand-built sites frequently get wrong. It even ships the correctly configured video variant; it just is not the one used eleven times on the homepage.

What a platform cannot do is stop an editor from putting eleven autoplaying videos on one page, because from inside the editor that is eleven drag-and-drop actions and each one looks fine. This is the general shape of builder performance problems, and it is why they respond to sequencing rather than to code changes.

Fix it yourself

None of this needs us. It needs someone to do it, test that nothing broke, and do it again after the next template change — which is the part we sell.

  1. Drop autoplay on anything below the first screen Not preload — autoplay. Eleven of the fourteen video elements on this page carry autoplay with no preload attribute at all, and autoplay outranks any preload hint you could set: a video that plays has to download. The three elements that do carry preload="metadata" are the three that do not autoplay, which is the correct pairing and already exists on this very page.
  2. Let the poster do the work until the viewer arrives Every one of these elements already has a poster image. Show the poster, and start playback from an IntersectionObserver when the section is actually on screen. The visual result above the fold is identical and the first screen stops competing with megabytes it does not need.
  3. Move the stylesheet preloads out of the body All seven async-CSS links on this page sit inside <body>, some 200 KB into the document. The browser's preload scanner reads ahead through the head to start downloads early; a hint placed after that point cannot be found early by definition. Cut and paste into <head> — the tags themselves need no changes.
  4. Ask the font service for the fonts you use Three of those links request a Google Fonts CSS listing roughly sixty families between them, for a page that renders a handful. Each URL is over a kilobyte of query string on its own. Trim the family list to what the site's styles actually reference.
  5. Put width and height back on the images 102 of the 115 img tags have neither. It costs two attributes and it is the difference between the browser reserving the right box and reflowing the page when the image lands. Lab CLS will not thank you for it — see the study linked below for why the lab number stays near zero while real visitors still get the shift.

What we measured, and what got worse

PageSpeed Insights (Lighthouse, mobile and desktop) run against the live site and against the same page served through the WebSpeed proxy, on 23 Jul 2026. Audit 5a4400eba4d9ab — the numbers on this page are frozen at that run and are not restated later.

Proxy response re-checked on 23 Jul 2026: the proxied URL returns the page itself, not a redirect back to the origin. That check exists because a redirect makes both halves of a before/after the same page, and the improvement pure noise.

What the page still loaded

The accelerated run made 47 requests against the original's 113, and transferred 18 MB against 26.5 MB. We print this because a score can rise for two very different reasons — the page got faster, or the page got less of itself — and across our audit base the second is common enough to be worth ruling out in the open.

What got worse or stayed the same

  • Our runtime is not free. The original main thread was idle — total blocking time 0 ms — and through the proxy it becomes 20 ms on mobile. Negligible on a page this network-bound, but it is a cost we add, not one we remove, and on a script-heavy site it would be larger.
  • We did not make the page lighter in any real sense. 18 MB of video still loads through the proxy. What changed is the order in which bytes arrive, not the number of them — no proxy can decide on your behalf that a hero video should not exist.
  • The mobile score barely moved (65 → 71) even though the largest element arrives three times sooner. PageSpeed weights the 18 MB that stays; a six-point gain understates what the visitor actually sees, and we would rather show that than pick the number that flatters us.
  • Desktop barely moved (90 → 94). A page already fast on a desktop connection has little room, and the whole story here is a mobile-bandwidth story.
  • One page, one run, one day. This is a teardown, not a study — nothing here generalises to Duda sites as a class.