Skip to content

WordPress and WooCommerce sites

cache-boundary

Decides route by route whether a full-page cache may serve one visitor's copy of a page to everyone else, from headers, WordPress markers and Jev's answers.

Kind
Open-source tool
Language
JavaScript
License
MIT
Status
First release
  • caching
  • cli
  • jev
  • page-cache
  • typesafe
  • woocommerce
  • wordpress

When the cached copy belongs to someone else

A page cache stores the HTML one visitor received and hands it to the next. When that page holds a nonce, a cart, a greeting or a session cookie, the next visitor gets the first visitor's copy: a stale form token at best, someone else's cart or name at worst. Cache plugins decide from URL patterns and cookie lists, so a custom members page, or a plugin that starts a session on every product page, can slip through. cache-boundary looks at what each route sends and decides, route by route, whether a shared copy is safe.

Most decisions need no model

Each URL is fetched as a visitor without cookies, or a saved response is read from disk. With --twice, each URL is fetched twice and the copies compared. Code sorts every signal into three levels.

Block signals make a route "do not cache" in code, and nothing about that route is sent anywhere: a Set-Cookie for a session, login, cart or unknown cookie; Cache-Control with private, no-store or no-cache; Vary: *; the WooCommerce Store API's Cart-Token and Nonce headers; the logged-in or admin-bar body class; WooCommerce cart, checkout and account pages; a mini cart with products in it; and, with --twice, a token that changed between two requests without cookies. Cookies set by a CDN or a load balancer, such as __cf_bm and AWSALB, are noted and ignored.

Vary signals allow one stored copy per cookie value: Vary: Cookie, a language or currency cookie, a currency switcher, a password-protected post. Caution signals are printed next to a cache verdict: WordPress nonces that did not change, which stay valid for 12 to 24 hours, so a stored copy that holds one must expire within 12 hours; WooCommerce cart fragments and geolocation; Vary: User-Agent.

Three questions for the routes code cannot settle

Jev, TypeSafe AI's System One model, answers typed questions with probabilities and writes no text. A route that code did not decide gets one request about its path, status, title, body classes and visible text, its caching headers, its forms, and its tokens by name and shape:

  • Does the page show content meant for one particular visitor, such as a name, a cart with items, an order or an account detail?
  • Does it hold a token or nonce that must not be shared between visitors?
  • Which rule should a full-page cache follow for it: cache, cache with vary on cookie, or do not cache?

A greeting such as "Welcome back, Robin" on a custom members page is the kind of thing no marker names and these questions are for. The verdict is made in code with one threshold (0.8 by default), and a route Jev is unsure about goes to review instead of into a rule. Cache and vary also need complete evidence: the response headers and a body under the 2 MB cap. A saved page without its headers can be found unsafe but never safe.

Suggested rules, not settings

The report ends with plain lists drawn from the confident verdicts only: paths not to cache (WooCommerce cart, checkout and account pages with everything below them), cookies that should skip the cache, and cookies to keep one stored copy per value of. They are not settings for any particular cache plugin. A logged-in page or a full cart in the answer to a request without cookies does not become a path rule: the stored copy is the problem, so the report says to purge it.

Fetching your pages carefully

The tool contacts only the hosts in the URLs you give; a redirect to any other host is reported and not followed. Before each connection, and on each of up to three redirects, the host name is resolved and refused if any address is private, loopback, link-local or a cloud metadata address, and the connection goes only to the addresses that passed. Requests go one at a time, half a second apart, with a 10-second limit and at most 2 MB read from each page. TypeSafe never receives cookie values, token values, password fields, the host name, or anything about a route decided in code.

Limits

  • It judges the copy a visitor without cookies gets. Logged-in visitors and visitors with a cart are covered by the cookie rules; to check their view, save the page from your browser and pass the file.
  • The markers cover WordPress core, WooCommerce and common theme and plugin markup. A plugin that prints a greeting in its own markup is left to Jev, which may be unsure.
  • Content chosen from the visitor's IP address, with no cookie or URL change, cannot be seen from one request, and a cache that sends none of the common hit headers goes unnoticed.
  • Text written to steer a model, such as an instruction hidden in a page, can move Jev's answers. English is where it is most accurate.
  • The example in the repository is nine saved responses from a made-up shop, with hand-written probabilities: it shows the report's format, not a live run.

Install and run

It needs Node.js 20 or later and has no dependencies.

npm install -g github:hamzaahmadaslam/cache-boundary
export TYPESAFE_API_KEY=<your-key>
cache-boundary --urls routes.txt --twice --dry-run
cache-boundary https://example.com/ https://example.com/shop/ https://example.com/cart/

The exit code is 1 when a request without cookies got a logged-in page or a cart with items, or a cache served a route that must not be cached, so it can fail a CI job.

Related