Dev.to WebDev πŸ›  Dev πŸ‘ 0 πŸ“– 7 min read

Your Wix widget loads from whichever deployment rendered the page, and that render can be cached for 35 hours

Observed September to November 2026 on apps built with the Wix CLI. This is platform behaviour we measured from the outside, not a documented contract. It may change. If you build Wix apps with the CLI, every npx wix re

Observed September to November 2026 on apps built with the Wix CLI. This is platform behaviour we measured from the outside, not a documented contract. It may change.

If you build Wix apps with the CLI, every npx wix release creates a new deployment. Your dashboard page picks it up immediately. Your storefront widget, the custom element merchants drop onto their pages, often doesn't. For a week we believed merchants had to republish their sites to receive a widget fix. That was wrong, and the real mechanism is more useful to know.

What we measured

Each release of a CLI app gets a new static host of the form <prefix>-<app-slug>.wix-host.com. The prefix changes on every release. Old deployments stay online.

On 2026-09-23 we released version 1.63.0 of our search widget and, twenty minutes later, ran a read-only census over the external sites that had it installed. We found the widget on 31 published home pages. Nine of them already referenced the new prefix. Nine merchants do not republish within twenty minutes of a release they know nothing about, so "republish to receive the update" could not be the rule.

We then fetched three of the sites that still referenced old prefixes, twice each: once plainly, once with a random query string.

Request server-timing age (seconds) Prefix in HTML
plain GET, site A cache;desc=hit 24,582 (about 6.8 h) old
plain GET, site B cache;desc=hit 50,198 (about 13.9 h) old
plain GET, site C cache;desc=hit 125,021 (about 34.7 h) old
same URL + ?nocache=<random>, all three cache;desc=miss none current (1.63.0)

So the widget's script host is not baked into the page when the merchant publishes. Wix inserts the deployment that is current when it renders the page, and the rendered HTML is then served from a cache. The oldest cached render we have seen was 125,021 seconds old, a little under 35 hours. We haven't found a documented TTL, and we've seen much shorter ones: on our own development sites the HTML switched to a new prefix within 2 to 4 minutes.

Two months later the picture was the same at a larger scale. On 2026-11-03, about an hour after a release of our calendar widget, we fetched the home page of 126 external sites that run it. They referenced eight different deployments of the same app on the same afternoon. The distribution was 50, 38, 22, 8, 3, 2, 2 and 1 sites per deployment. The release from an hour earlier was on two of them.

Why we got it wrong first

On 2026-09-18, right after a release, we checked one live site: old prefix. We published that site from the editor: new prefix. We wrote down "widgets update when the merchant republishes." Three days later, right after another release, two sites served two different old bundles, and then both switched to the new one within minutes while nobody touched them. The lesson for us: one read of a cached page right after a change doesn't tell you the rule. We should have read it again a few hours later and looked at the headers.

How to reproduce it on your own app

You need a published site with your widget on it and the slug part of your app host.

# 1. Which deployment does the cached render reference, and how old is it?
curl -sD - -o /tmp/page.html 'https://<a-site-with-your-widget>/' \
  | grep -iE '^(age|server-timing):'
grep -oE '[a-z0-9]+-<your-app-slug>\.wix-host\.com' /tmp/page.html | sort -u

# 2. Force a fresh render by changing the URL
curl -sD - -o /tmp/fresh.html "https://<a-site-with-your-widget>/?nocache=$RANDOM$RANDOM" \
  | grep -iE '^(age|server-timing):'
grep -oE '[a-z0-9]+-<your-app-slug>\.wix-host\.com' /tmp/fresh.html | sort -u

If step 1 shows cache;desc=hit, a large age and an old prefix, and step 2 shows cache;desc=miss and the prefix of your latest release, you are looking at the same mechanism.

To learn which prefix is current without a browser, fetch a fresh render of your own test site the same way. If you prefer the dashboard, the first segment of the hostname of your app's dashboard iframe is the current prefix, because the dashboard always runs on the latest deployment:

[...new Set([...document.querySelectorAll('iframe')].map(f => {
  try { const h = new URL(f.src).hostname; return h.includes('wix-host') ? h.split('-')[0] : null; }
  catch { return null; }
}))].filter(Boolean)

One thing to watch: the hashed chunk filenames inside the bundle are resolved by Wix's loader at run time and are not in the HTML. To see which chunk a visitor actually loaded, use performance.getEntriesByType('resource') in the page.

What we changed

We stopped telling merchants to republish. Our dashboard used to say the site had to be "published again." It now says: Your site's cached pages still load the older version. Wix refreshes them on its own over time; publishing the site refreshes them right away. That one is true. The old one asked merchants to do work because we had misread a cache.

We also compare prefixes now, and we allow "unknown". The dashboard fetches the merchant's published home page (and, if the widget is not there, a few pages listed in the sitemap), extracts our prefix, and compares it with the prefix the dashboard itself is running from. On the client that is new URL(import.meta.url).origin. Don't use the server's Host header for this; on Wix hosting it is not the public host. The result is tri-state: current, stale, or unknown when either side could not be read. A wrong "stale" sends a merchant off to republish for nothing, and a wrong "current" hides a fix that never arrived, so when we can't read one side we'd rather show nothing.

We ship a build stamp. The build now writes its timestamp into a static file under public/, so every deployment host answers GET /_wix/extensions/public/build with its own build time. Comparing two deployments no longer means diffing minified bundles. A small script fetches each known site's home page, collects the prefixes, probes each prefix's build stamp, and prints a histogram. That is where the "eight deployments across 126 sites" number came from.

Another thing we stopped doing: storing a deployment host anywhere. A GitHub Actions cron of ours called our server through a repository variable that held a host. Over four days and five releases it kept running a stale build, while we believed a server fix was live for every merchant. The host is now resolved at run time.

And we verify releases with a cache-busting fetch. After each release we open our own site with a fresh query string and compare the served bundle with the local dist/ byte for byte, using cmp. Opening the page plainly and seeing the old bundle is not evidence that the release failed.

What still trips us up

  • Cart and checkout plugins behave differently. For the site plugin slots (cart, checkout), republishing alone did not change the bundle. The host changed only after the merchant updated the app through the app installer and then published again (measured 2026-09-22). Those slots appear to pin the app version into the published site.
  • The query-string trick is not guaranteed. One of our test sites kept serving the previous day's build even with ?nocache=. Publishing from the editor refreshed it. We don't know what made that cache stickier.
  • Prefix is not version. A site that had installed major version 2 of our calendar served a deployment host from the version 3 line. The host tells you which build served the file. What the widget then does depends on your own code paths, not on the host. Don't read "new prefix" as "this merchant is on the new major".
  • The browser has its own cache. Even after Wix re-renders, your browser may hold the old page. Add a query parameter when you check.
  • Old hosts answer 200 forever. If you measure against an old prefix you'll keep seeing "nothing changed", for as long as you like.

So this is how we think about it now: a widget release reaches a visitor when Wix next renders that page, which depends on the site's cache and not on anything the merchant did. We plan our checks around that, and we wrote the dashboard text around it too.

Written by a backend engineer with ten years of experience, building small Wix and Shopify apps as operix.

The calendar widget whose 126-site spread appears above is on the Wix App Market: https://www.wix.com/app-market/a5d62bae-8405-4635-a985-8743d9ad50d7?utm_source=blog&utm_medium=article&utm_campaign=wix-widget-cached-render-35h

Related: npx wix release does not build: how we shipped yesterday's dist/ by mistake

πŸ“° Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes β€” full credit and traffic to the original publisher.