Cookie consent across subdomains with Material for MkDocs
This post looks at why you'd want shared cookie consent across your subdomains, then outlines the key features to be aware of when setting this up with Material for MkDocs, and provides a code sample to help you get started.
The scenario
A common pattern for company websites is to have multiple subdomains, all built as different sites, but existing for the user as a more or less continuous experience. For example:
- mydomain.com: the main product website. Built with anything from a static site generator to WordPress to . . .
- docs.mydomain.com: the documentation site. Built with Material for MkDocs (of course)
- community.mydomain.com: the product forum. Perhaps powered by something like Disqus.
- app.mydomain.com: the product itself. Again, could be built with anything.
Ideally, these should have a fairly unified feel. One way to support this is to ensure users only have to accept cookies once. In other words, if a user clicks Accept (or Decline) on the main website, they shouldn't get prompted again when they navigate to the docs.
However, behind the scenes, the main website and the docs site are entirely different sites: different tooling, code bases, deployments, and so on. This can make setting up shared cookie consent tricky.
Configuring Material for MkDocs to handle shared cookie consent
I was recently given cookie code from the main website, and told to add it to the docs. The main website stored user consent in a cookie named companyname-consent
. This seemed simple enough: I just needed to set and read that same cookie on the docs site. In practice, there were a couple of gotchas.
Gotcha 1: Material for MkDocs uses local storage to track consent
This was the first thing that caught me out when investigating this. Material remembers user choice in local storage, in an object named __consent
. So instead of reading or setting a cookie, you need to do:
Gotcha 2: All Material for MkDocs code runs before any extra JavaScript
MkDocs supports users adding their own JavaScript. You can set extra_js
in your mkdocs.yml
to tell MkDocs where to find your code (more info in the MkDocs documentation). In my first attempt, I used this to add my functionality.
However, the theme's JavaScript runs before the extra JS. This means that Material for MkDocs has already checked __consent
and decided whether or not to display the docs cookie banner, before the extra JS has a chance to run and check for other cookies. This led to the banner still displaying when users had already accepted cookies on the main website.
Luckily, MkDocs also supports a system of theme overrides, and Material for MkDocs is carefully designed with this type of theme extension in mind.
So, instead of using extra JS, I overrode the theme's consent JavaScript:
- Set up an overrides directory (more info).
- Add
partials/javascripts/consent.html
- Copy in the contents of Material consent.html.
- Modify as needed, ensuring my script preceded the theme's.
Thanks to Squidfunk for pointing out this was the approach I needed.
The code
You'll probably need to modify the following code to suit your own setup. It assumes cookie consent is stored in a cookie on the main website. This is just an example to get you started.
Add the following at the start of your partials/javascripts/consent.html
file in your overrides directory:
Wrap up
As Material's creator tactfully noted, this is a rather "exotic" case. It's one of the joys of MkDocs, and the Material theme, that it's so easily extendable and overrideable when you need to do something that isn't supported by default.
Hopefully this blog post will help you get started with this use case (or at least save me some time next time I forget the script execution order 🙄).