Emoji of a document, a lock, and a gear side by side on a turquoise to purple gradient background.

Loading Fathom Analytics’ script.js under a strict Content-Security-Policy

Post #3, posted in
  • How to
  • Web design


The standard directive “strict-origin-when-cross-origin” is also suitable for loading the Fathom script under a strict CSP, as Daniel Davis points out on Twitter. It enforces, that path and query string are passed on only on the same origin or cross-origin on the same protocol security level between origin and target page (HTTPS -> HTTPS).

If you follow me on Twitter, you are most likely aware, that I am a big fan of the privacy-first website analytics solution Fathom Analytics. A less known fact may be, that I am no expert on the topic of Content-Security-Policies (CSP). 🤷‍♂️

The problem

When it came to introduce a strong CSP to a client’s web presence, I hit a wall, trying to load the Fathom script.js. The obvious solution was to add the custom domain used to circumvent add blockers (there’s nothing fishy about that, seriously—more info on the use of custom domains in Fathom’s documentation) as a resource to the script-src directive, of course.
Browsers kept throwing a 403 Forbidden Error for the above-mentioned request at me, all the same.
Disabling the CSP reinstated the analytics functionality, so the problem was obviously with it.

Searching up and down the interwebs, I didn’t get any wiser.
I tried introducing a nonce to the script-src directive. No luck.
Asking for help on Twitter and reaching out to Paul and Jack of Fathom via email didn’t give me any pointers. Although Paul replied in a very timely fashion—as usual. The problem was on my end, not their’s, after all.

The epiphany

When trying to explain what I was experiencing, to post that to StackOverflow in search for help, it hit me. I revisited the CSP, turning off one directive after another. I had done that before, but obviously had missed something.
Commenting out the “Referrer-Policy” solved the issue.
That Fathom cannot do its work, if they don’t know which website was calling the script, is a no-brainer. Why the server returns a 403—rather than just failing to do its thing—is beyond me, though.

Completing the CSP

But now I was left without a “Referrer-Policy”—in the CSP, that is. Luckily we had opted for rel="noreferrer" attributes on the anchor tags of external links before, so there was a policy in place. It wasn’t obvious to the CSP, though.
To mitigate for that, I added an empty directive to the policy—like so Header always set Referrer-Policy ""—, thus telling it, that there is an alternative approach in effect.

Lessons learned (again)

  • Do not hesitate to formulate your problem—in written form or in a discussion. That might trigger you thinking about it differently.
  • Always try testing by exclusion. Multiple times, if need be.