Caching and CDN Compatibility
Super Speedy Chat is designed to sit happily behind whatever page cache and CDN your site already runs. The golden rule is simple: the front-end HTML that renders the chat bubble is fine to cache, but the chat’s data requests must never be cached. Get that split right and everything else follows.
This guide explains why, and gives the exact exclusion rules for the common stacks.
The one rule: never cache the REST endpoints
All of the chat’s live traffic goes through the REST namespace ssc/v1, under the URL prefix /wp-json/ssc/v1/. The visitor widget hits these routes constantly:
/wp-json/ssc/v1/session– start or resume a conversation/wp-json/ssc/v1/send– send a visitor message/wp-json/ssc/v1/poll– fetch new messages (fires every second or two)/wp-json/ssc/v1/auto-reply– request an LLM auto-reply/wp-json/ssc/v1/email– attach an offline-reply email address
Every one of these is per-visitor and per-moment. A cached /poll response is the failure that breaks live messaging: if a cache layer stores the first poll and replays it to everyone, one visitor sees another visitor’s conversation, and nobody ever sees a new message because the “response” is frozen. A cached /send is just as bad. So the whole /wp-json/ssc/ path must be excluded from:
- the WordPress page cache (WP Rocket, LiteSpeed Cache, W3 Total Cache and so on),
- any CDN or edge cache in front of the site (Cloudflare, a reverse proxy, a host-level cache),
- and, most importantly, any “cache everything” or “cache all pages” rule you have configured. Those aggressive rules are the usual culprit, because they ignore the normal WordPress cache heuristics.
The plugin does defend itself where it can. When Ultra Ajax is active, the mu-plugin (ssc-fast-ajax.php) intercepts matched /wp-json/ssc/v1/ requests and sends Cache-Control: no-cache, no-store, must-revalidate on every JSON response before it dies. That header tells well-behaved caches to leave the response alone. But a header only helps if the cache layer reads it. A “cache everything” edge rule, or a CDN configured to strip or ignore origin cache headers, will happily override it, so you still need an explicit path exclusion. Treat the header as a backstop, not a substitute for the exclusion.
A cached /poll response is the single worst failure: one visitor’s conversation gets replayed to everyone, and new messages never appear because the “response” is frozen. An aggressive “cache everything” rule is almost always the culprit. Exclude the whole /wp-json/ssc/ path explicitly rather than trusting the origin’s no-store header.
The plugin identifies a returning visitor with a single cookie, ssc_visitor_hash. It is set with path=/, SameSite=Lax, HttpOnly, Secure when the site is on HTTPS, and a one-year lifetime. Every visitor endpoint resolves the caller’s own conversation from that cookie and nothing else (see REST API Reference for the full authentication model).
Two things your cache layer must not do to it:
- Do not strip it. Some CDNs and caching plugins drop cookies they do not recognise on cached responses, to improve hit rates. If
ssc_visitor_hashis stripped on the response, the browser never stores it, the visitor looks brand new on every request, and/sendand/pollreturn 403 because there is no session cookie. Addssc_visitor_hashto your cache layer’s cookie allow-list, or simply exclude the/wp-json/ssc/path so the cache never touches those responses at all.
- Vary on it where relevant. The cookie is
HttpOnly, so it never changes what the cached front-end HTML should look like, and you do not need to vary the page cache on it. You do, however, need to make sure it survives round trips, which the path exclusion guarantees.
Why a cached bubble config can go stale
The bubble’s HTML and its JavaScript are static assets and are safe to cache aggressively. The subtlety is the config blob. On each front-end page load the plugin localises a ssc_config object into the page (via wp_localize_script) that carries the REST URL, polling intervals, appearance settings, whether the visitor is logged in (is_logged_in), and a fresh WordPress REST nonce (wp_create_nonce( 'wp_rest' )).
That nonce and the is_logged_in flag are per-user and time-limited. In practice the visitor widget’s public endpoints do not require the nonce (they authenticate purely from the cookie), so ordinary visitors are unaffected by a cached page. But it is the reason you should never cache logged-in admin views, and the reason the wp-admin Chats inbox, which always goes through the full REST API with a live nonce, must sit outside every cache. If you change appearance or behaviour settings and the bubble looks unchanged for logged-out visitors, a stale cached page is the first thing to purge.
Ultra Ajax pairs with, not against, your cache
Ultra Ajax is a performance layer, not a cache. It intercepts /wp-json/ssc/v1/ requests before WordPress fully loads, handles them in single-digit milliseconds, and returns fresh JSON every time with the no-store header shown above. It never serves a stored response, so there is no staleness risk from Ultra Ajax itself. It complements a page cache nicely: the page cache serves the static HTML shell instantly, and Ultra Ajax serves the live chat data instantly. See Ultra Ajax Performance Guide for how the mu-plugin works and how to confirm it is active. Note that a CDN still sits in front of the origin, so the /wp-json/ssc/ exclusion is still required even with Ultra Ajax on; the mu-plugin only runs once the request reaches your server.
Stack-specific notes
WP Rocket. Add /wp-json/ssc/(.*) under Advanced Rules, “Never Cache URL(s)”. WP Rocket does not cache logged-in users by default, so the admin inbox is safe out of the box. Do not add the bubble script to delayed/deferred JS aggressively without testing, as the widget needs its config present at load.
LiteSpeed Cache. Add /wp-json/ssc/ to Cache > Excludes > “Do Not Cache URIs”. If you run LiteSpeed at the server (LSCache) as well as the plugin, apply the exclusion in both. Keep ssc_visitor_hash off any cookie-stripping list.
Cloudflare. If you use a “Cache Everything” Page Rule or a Cache Rule for the domain, add a matching bypass rule for /wp-json/ssc/* (Cache Level: Bypass, or “Bypass cache” in the newer Cache Rules). By default Cloudflare does not cache /wp-json/ responses, so you only need this if you have opted into caching HTML or the REST API. Make sure “Origin Cache Control” is respected so the plugin’s no-store header is honoured.
Reverse proxies and host caches (Varnish, NGINX FastCGI cache). Exclude the /wp-json/ssc/ prefix and pass the ssc_visitor_hash cookie through to the origin unmodified.
- The
/wp-json/ssc/path is excluded from the page cache - The same path is bypassed at the CDN or edge, including any “cache everything” rule
- The
ssc_visitor_hashcookie is on the cookie allow-list, not stripped from responses - Logged-in admin views and the Chats inbox are never cached
- After changing appearance or behaviour, the front-end page cache is purged
If live messaging is not updating, a cached or stripped data request is the most likely cause. Confirm the endpoint exclusions above, then see Troubleshooting and FAQ. For deciding where the bubble even loads (which affects which cached pages carry the widget at all), see Showing or Hiding the Chat on Specific Pages.
Further reading
ssc/v1 routes you must exclude and the cookie auth model
Comments