Skip to content

What Isn’t Cached ​

Speedy only caches pages it can be sure are the same for everyone.

Not cachedWhy
Visitors who are logged inThey may see personal content, and editors need to see changes straight away
Visitors with a Commerce cartHeaders often show the cart. Set skipWhenCart to false if yours don’t
Visitors with something in their sessionSuch as the second step of a multi-page form, or a “Thanks for your message” flash. See below
Ajax requestsLibraries like htmx and Unpoly, and X-Requested-With requests, often get part of a page at the same URL
Cookies you list in skipCookiesSuch as a consent banner rendered on the server. See below
Pages that send VaryVary: User-Agent or Vary: Cookie means the page differs per visitor. Vary: Accept-Encoding is fine
Hosts that aren’t a site’sA request with someone else’s domain in its Host header. Sites whose base URL is @web accept any host
URLs with a query string?q=, ?page= and filters usually change the page. Tracking parameters (utm_*, gclid, fbclid…) are ignored
URLs matching Never cacheSuch as checkout/* or account*
Pages that set a cookieA cookie usually means something personal. Craft’s CSRF and session cookies are fine
Pages marked privateCache-Control: private or no-store, from your template or a plugin
Responses that aren’t a 200 HTML page404s, redirects, JSON and feeds
POST requests and actionsForm submissions and actions/… URLs
Live preview and share linksThey show drafts
Pages that call craft.speedy.skip()See Templates

The X-Speedy header on each response says SKIP and the reason.

Never cache ​

Add URL paths on the settings page, one per line, or in config/speedy.php. * matches anything:

php
'neverCache' => [
    'checkout/*',
    'account*',
    'search',
    'members/*',
],

Multi-page forms and flash messages ​

Some pages depend on what a visitor did a moment ago: a multi-page form that reloads the page for each step remembers the step in the visitor’s session, and a “Thanks for your message” notice is a flash message kept there too. Cached, one visitor’s step or message would be shown to everyone, and other visitors would be stuck on the cached step.

So while a visitor’s session holds anything, Speedy:

  • doesn’t cache the pages it builds for them (X-Speedy: SKIP session);
  • sets a speedy_state cookie, so it and the web server rules build their pages fresh instead of serving cached copies;
  • removes the cookie once the session is empty again, such as when the form is finished.

Everyone else keeps getting cached pages. Forms that move between steps with Ajax don’t use the session this way and need nothing.

Cookies that change pages ​

If a template reads a cookie, such as a consent banner that’s only shown until accepted, a cached copy would show one visitor’s choice to everyone. List those cookies, and visitors who have them get pages built for them:

php
// config/speedy.php
'skipCookies' => ['cookie_consent', 'currency'],

Names are matched by part, and the server rules include them, so copy the rules again after changing this. Better still, render the banner for everyone and hide it with JavaScript when the cookie is set; then every page can be cached.

Pages that differ by device or location ​

Pages that change with the browser (craft.app.request.isMobileBrowser) or the visitor’s location can’t be told apart by URL. Use CSS or JavaScript for the differences, or add {% do craft.speedy.skip() %} to those templates.

Response headers ​

Headers your templates or plugins send, such as X-Robots-Tag, Link, Content-Language and Content-Security-Policy, are saved with the page and sent again when PHP serves it. Pages served by the web server get the headers in your server configuration instead.

Pagination ​

Craft paginates with paths like /news/p2, which are cached like any page. If your site paginates with ?page=2, those pages aren’t cached by default.