# Inside the widget speed program: cutting our embed JS by two thirds

A UGC widget lives on someone else’s storefront, so every kilobyte is borrowed. Here is exactly what we cut, what we measured, and the new performance dashboard that shows what your shoppers’ browsers actually experienced.

By Rohin Aggarwal · 2026-08-10

The fastest third-party script is the one that never loads. The second fastest is the one that loads only what this exact visitor, on this exact page, on this exact device actually needs. We spent a sprint holding our own widget to that standard, and this is the honest ledger of what we found and what we changed.

**Quick answer**

- The widget’s critical-path JavaScript drops from roughly 122 KB to about 44 KB gzipped once the full program lands, and an opt-in lite mode paints a grid with ~4.5 KB.
- Pages where a product has no tagged content no longer download the widget at all. Empty means empty, including the network tab.
- Native mobile apps get a supported integration path: a tap bridge, a hosted widget URL, and a self-check panel for support.
- A new Performance page in the dashboard reports what real shoppers’ browsers measured, not lab numbers.

An embedded widget is a guest. It runs on a storefront that already carries a theme, an analytics stack, a consent manager and a dozen other scripts, and the merchant’s Core Web Vitals pay for all of it. We have always engineered against that budget (it is why the widget code-splits every gallery layout), but a deep audit this month found real waste left on the table. This piece walks through the ledger: every line item, the measured saving, and the two changes that matter even more than the kilobytes.

## The ledger: what we cut

| Change | Before | After |
| --- | --- | --- |
| Icon library replaced with generated inline SVGs | 13.9 KB + 1 request | tree-shaken, ~0 |
| React runtime swapped for a compatible 4 KB core | 45.1 KB | 9.7 KB |
| Product modal loads only this session’s variants | 27.9 KB | 22.6 KB |
| Chunk files on the CDN | 148 files | 136 files |
| Critical chunks discovered late (extra round trip) | 4 chunks | 0 |

_Measured on production builds, gzipped sizes. Items ship independently through August 2026._

Two items deserve a word. The icon change sounds trivial and is not: 87 icons pulled in a 40 KB vendor bundle where the actual path data was about 3 KB, so we generated our own components once and deleted the dependency. The modal change is about fairness across devices. A desktop shopper was downloading the mobile bottom-sheet, a Shopify store was downloading the WooCommerce panel, and everyone was downloading one customer’s demo dataset. Each variant now loads only where it can actually render.

## The bigger win: loading nothing

Bundle size is the second-order problem. The first-order problem is loading code on pages that will never show content. A product page whose product has no tagged posts used to download the entire widget, mount it, discover the empty response, and hide. The loader now remembers which galleries came back empty, races first visits against the data response, and skips the bundle when there is nothing to paint. Galleries embedded deep below the fold wait for an intersection observer instead of taxing initial page load.

**~4.5 KB** — JavaScript needed to paint a grid in the new opt-in lite mode (Loader plus a self-contained renderer; the full app hydrates on first interaction or browser idle.)

For merchants who want to go further, an experimental lite mode paints the grid from the data response alone, with the interactive app arriving lazily afterwards. It is a flag on the embed div, it fails open in every path we could think of, and it exists because the honest end state of a widget speed program is first pixels that cost almost nothing.

## Mobile apps: a supported path, not a shrug

Customers kept asking whether the widget works inside their native apps. The truthful answer was “usually, with sharp edges”: WebViews silently drop window.open, so product taps did nothing, and some ship with storage disabled. Both edges are now handled. Every outbound tap goes through a single exit point that can deliver a structured event to React Native, WKWebView or Android instead of opening a popup, storage degrades gracefully, and a diagnostic panel (add idk_appcheck=1 to any URL inside the app) tells support exactly what that WebView allows. None of this changes anything for regular web embeds; the bridge is strictly opt-in.

## Proof over promises: the Performance page

Lab benchmarks flatter everyone. The number that matters is what your shoppers’ browsers measured on your pages, so the widget now reports a small sampled beacon (time to first tile, data latency, LCP, layout shift) to a new Performance page in the dashboard. You see your own percentiles, the trend over time, mobile against desktop, and how you compare with the fleet-wide benchmark across all Idukki widgets. When we say the widget got faster, you should be able to check.

**What to do with this:** Nothing is required from you. The improvements roll out through our normal staging and smoke-test gates during August 2026, existing embeds keep working unchanged, and the opt-in flags (lite mode, the app bridge) are documented for teams that want them. If your product pages show empty galleries today, tag products; the widget will now stay out of the way until there is something worth showing.

---
Canonical: https://idukki.io/blog/widget-speed-program
Tags: performance, widget, core web vitals, engineering
