Avoid Caching logged in user with Cloudflare Workers – Effective way to Cache Everything

Cache everything in Cloudflare also caches logged in users which makes admin bar in WordPress to appear to anonymous users. It is not a good thing and cause negative effect to user experience. We can disable admin bar in WordPress from dashboard settings but there is comment section which also shows logged in as message to not logged in users.

So, is it a good idea to use cache everything in Cloudflare? The answer is yes because I am going to show you how to avoid caching logged in users and how to only purge single page which is modified.

There is a plugin, Cloudflare Page Cache which does the same but it purges all the cache including HTML and static contents like image & CSS. Therefore this article is not only about avoiding logged in user in Cloudflare edge cache but also purging those pages only which are changed.

We are going to use Cloudflare WordPress Plugin along with a Cloudflare Workers script. Cloudflare WordPress Plugin handles cache purging while Cloudflare Workers script enables Edge Cache HTML ensuring no logged in users are being cached and bypass HTML cache for users with cookies. Using this method when a comment is made then only that single page is purged from Cloudflare edge cache and when appearance is changed, everything is purged.

To do so you need to install Cloudflare WordPress Plugin and enable automatic cache management.

For this you need to setup plugin with Global API key first. Which can be found in https://dash.cloudflare.com/profile.

Now you need to run a Cloudflare Workers script that enables HTML edge caching.

Clear all previous code and paste this Workers Script then click save. Gist link – Cloudflare edge-cache-only

// Stop CF edge from caching your site when specific wordpress cookies are present
// script found in https://www.mmaton.com/2018/07/02/cloudflare-cache-anonymous-requests/

addEventListener('fetch', event => {
  event.respondWith(noCacheOnCookie(event.request))
})

async function noCacheOnCookie(request) {
  // Determine which group this request is in.
  const cookie = request.headers.get('Cookie')
  // Edge Cache for 1 month
  const cacheSeconds = 2592000
  if (cookie 
    && (
      cookie.includes(`wordpress_logged`)
      || cookie.includes(`comment_`)
      || cookie.includes(`wordpress_sec`)
      || cookie.includes(`woocommerce_`)
    )) {
    const bustedRequest = new Request(request, { cf: { cacheTtl: -1 } })
    const response = await fetch(bustedRequest)

    const newHeaders = new Headers(response.headers)
    newHeaders.append('wp-cache-busted', `true`)
    return new Response(response.body, {
      status: response.status,
      statusText: response.statusText,
      headers: newHeaders
    })
  } else {
    return fetch(new Request(request, { cf: { cacheTtl: cacheSeconds } }))
  }
}

You can change const cacheSeconds = 2592000 to adjust the cache time. It is in second and is equivalent to Edge Cache TTL available in Cloudflare page rules. To deploy workers you have to add a route.

Now your website also became cachy like mine. After doing all the setup, disable your Cache Everything page rule if you have enabled it before. Also you don’t need Edge Cache TTL page rule since it will not work without Cache Everything. The Cloudflare Workers script will take care of both of them.

Cloudflare Workers can do even more. Some examples are changing header on the go and Fast Google Fonts. See How to solve font loading issues due to CORS.

Your super cachy website may also send cache-control header like cache-control: max-age=3600, which tells browser to store cache for that time period.

Since we are also caching HTML pages, it will be also stored in browser cache. Due to this page will not load from server when next time user visits that page again instead it will load from users browser cache unless user refreshes the page.

To avoid this you have to set max-age to low as much as you can. It may depend on how active your site is. I have set it to an hour (3600 seconds). So you don’t get this page updated unless you hit that reload button for an hour. You can set cache-control header using mod_expires rule in Apache web server. This can be done by using ExpiresByType text/html "access 1 hour" inside <IfModule mod_expires.c> </IfModule>. This is what my .htaccess file have in root folder of the site.

<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType text/html "access 1 hour"
ExpiresByType image/jpg "access 1 year"
ExpiresByType image/jpeg "access 1 year"
ExpiresByType image/gif "access 1 year"
ExpiresByType image/png "access 1 year"
ExpiresByType text/css "access 1 month"
ExpiresByType application/pdf "access 1 month"
ExpiresByType application/javascript "access 1 month"
ExpiresByType application/x-javascript "access 1 month"
ExpiresByType application/x-shockwave-flash "access 1 month"
ExpiresByType image/x-icon "access 1 year"
ExpiresByType image/svg+xml "access 1 year"
ExpiresDefault "access 1 hour"
</IfModule>

You can adjust it like ExpiresByType text/html "access 60 seconds".

You also need to set Browser Cache Expiration in Cloudflare to Respect Existing Headers. By doing this Cloudflare will not add its own max-age header.

For the users who are using WP Super Cache plugin, it sets default expire time is 3 seconds only. You need to check that from browser console. If it is you don’t need to edit .htaccess like above. But you can always edit to fine tune Browser Cache Expiration. W3 Total Cache plugin users can set Browser Cache Expiration from settings.

You can check if HTML Edge Cache is working or not using browser’s developer tools (Ctrl+Shift+I).

When user is logged in you can see the wp-cache-busted: true header.

When you browse in private (incognito) mode, you will see cf-cache-status: hit

My site is already boosted with Cloudflare workers let me know how it is working on your site.

Leave a Comment

22 thoughts on “Avoid Caching logged in user with Cloudflare Workers – Effective way to Cache Everything”

  1. Hello Sangam,

    thanks so much for the information. I created now a new CF Account and tried with your previous Worker Script again, and the Script is working, so the answer from CF Support was not correct…

    When testing with Chrome Dev Tools I get on the Pages cf-cache-status: HIT, and logged in to Admin cf-cache-status: DYNAMIC wp-cache-busted: true, perfect.

    Following now the Tutorial is set in the worker script const cacheSeconds = 3600 , and in the htaccess File as well ExpiresByType text/html “access 3600 seconds”

    Cloudflare Caching:

    Caching Level: Standard

    Browser Cache TTL: Respect Existing Headers

    In my Page Rule, I disabled Cache Everything Rule and Edge Cache TTL

    Page Rules:

    *.domain.com/blog/wp-admin/*
    Disable Security, Browser Integrity Check: Off, Always Online: Off, Security Level: High, Disable Apps, Disable Performance: Off

    2
    *.domain.com/blog/wp-login.php*
    Disable Security, Browser Integrity Check: Off, Always Online: Off, Security Level: High, Disable Apps, Disable Performance: Off

    3
    *.domain.com/*
    Always Online: On, Security Level: Medium, Origin Cache Control: On

    Testing Chrome for the cache-control: max-age=3600 Response Header, nothing displayed ..

    The Request Header show cache-control: max-age=0 .

    Do you have an Idea if something else has to be adapted to get the correct max-age=3600 Response Header?

    Thank You,

    Sallida

    Reply
  2. Hello,

    thanks for sharing this article Sangam! I created worker and route with the script in CF Dashboard, when i test the worker script with Get https://worker.domain.workers.dev/ i get 522 Origin Connection Time-out Error

    Do you know, if there is any specific DNS Setup?

    Thank you!
    Sallida

    Reply
  3. Great work Sangam – this is a fantastic tutorial and the results are exactly as described for logged out and logged in users. A major step for us. Thanks a lot!

    Reply
    • The script by Cloudflare purges everything when post or comment is updated if KV is not being used. With the script I described in this blog do not purge caches it only caches and bypass is logged in. Purge is done by Cloudflare plugin.
      I already described all these stuffs in this blog and you are asking it.

      Reply
    • When you make a request to website from new location Cloudflare caches files at their Edge Server (near that location). You can see ‘cf-ray
      5302f099edd7e634-LHR’ header in your files and html. So for the first time cf-cache-status will be MISS. When the cache is cleared and request is made it will be EXPIRED. If you request again then it will be HIT. You can read more about this here – https://support.cloudflare.com/hc/en-us/articles/200172516.
      So a question for you, have you tried testing again? If you did please reply.

      Reply
  4. Hello Sangam, thank you for the guide. I followed the steps and it’s working great.

    However, I got one questions – do we need to disable the `Cache Everying` after adding the edge-cache service worker in CF?

    Reply