Google recently announced the rollout of their Federated Learning of Cohorts (FLoC), a new advertising-surveillance initiative that seeks to replace third-party cookies with a new user profiling technique that garners data generated by the browser itself.
The EFF has written an overview of FLoC and it’s threats and has also developed a useful tool to test if a user’s browser is being used for data collection and fingerprinting.
Plausible Analytics has also chimed in with an article explaining FLoC in relation to users and developers — which was the inspiration for this short guide.
The FLoC Header
The primary way an end-user can avoid being FLoC’d is to simply not use Chrome, and instead choose a privacy-respecting browser such as Mozilla Firefox.
But website owners can also ensure that their web servers are not participating in this massive network by opting-out of FLoC.
To do so, the following custom HTTP response header needs to be added:
Permissions-Policy: interest-cohort=()
In this guide you’ll find instructions on how to add custom HTTP response headers to common web and proxy server configurations.
NGINX
Add the following in your NGINX configuration file:
# default.conf
server {
location / {
add_header Permissions-Policy interest-cohort=();
...
}
}
Restart NGINX with the command service nginx restart
The only caveat to be aware of is that the add_header
directive needs to be added within each server block if a single configuration file is used for multiple websites.
Apache
Add the following directive to your Apache configuration file:
# .htaccess
<IfModule mod_headers.c>
Header always set Permissions-Policy: interest-cohort=()
</IfModule>
Restart Apache with the command service apache2 restart
OpenLiteSpeed
Add the following context to your OpenLiteSpeed configuration file:
# vhost.conf
context / {
location $DOC_ROOT
allowBrowse 1
note This header disables FLoC
extraHeaders set Permissions-Policy interest-cohort=()
}
Restart OpenLiteSpeed with the command service lsws restart
Caddy
Add the following to your Caddyfile:
# Caddyfile
example.com {
header Permissions-Policy "interest-cohort=()"
...
}
Restart Caddy with the command caddy reload
Varnish
Add the following to your Varnish configuration file:
# default.vcl
sub vcl_deliver {
...
set resp.http.Permissions-Policy = "interest-cohort=()";
...
}
Restart Varnish with the command service varnish restart
HAProxy
Add the following directive to your HAProxy configuration:
# frontend, listen, or backend section
http-response set-header Permissions-Policy interest-cohort=()
Restart HAProxy with the command service haproxy restart
Traefik
Add the following to your Traefik TOML configuration file:
# traefik.toml
[http.middlewares]
[http.middlewares.floc.headers]
[http.middlewares.floc.headers.customResponseHeaders]
Permissions-Policy = "interest-cohort=()"
Or the following if you’re using a YAML configuration file:
# traefik.yml
http:
middlewares:
floc:
headers:
customResponseHeaders:
Permissions-Policy: "interest-cohort=()"
And if you’re using Traefik with Docker, add the following to your docker-compose.yml
file:
# docker-compose.yml
labels:
- "traefik.http.middlewares.floc.headers.customresponseheaders.Permissions-Policy=interest-cohort=()"
Lighttpd
Add the following to your Lighttpd configuration file:
# lighttpd.conf
server.modules += ( "mod_setenv" )
setenv.add-response-header = ( "Permissions-Policy" => "interest-cohort=()" )
Restart Lighttpd with the command service lighttpd restart
H20
Add the following to your H20 configuration file:
# h2o.conf
hosts:
"example.com":
...
header.set.ifempty: "Permissions-Policy: interest-cohort=()"
...
Restart H20 with the command service h2o restart
Netlify
Add the following to your Netlify configuration file:
# netlify.toml
[[headers]]
for = "/*"
[headers.values]
Permissions-Policy = "interest-cohort=()"
If you prefer to use a _headers
file instead of a TOML configuration file, then add the following to that file instead:
# _headers
/*
Permissions-Policy: interest-cohort=()
On your next build or deploy, Netlify will add and serve the headers.
Vercel
Add the following to your Vercel configuration file:
# vercel.json
{
"headers": [
{
"source": "/(.*)",
"headers": [
{
"key": "Permissions-Policy",
"value": "interest-cohort=()"
}
]
}
]
}
As with Netlify, on your next build Vercel will add and serve the headers.
GitHub Pages
GitHub announced on 2021-04-27 that they will add the necessary FLoC protection header to all GitHub Pages sites served from the github.io
domain.
However, there is no way to add custom HTTP response headers (as yet) when using GitHub Pages with a custom domain.
GitLab Pages
If you use the Community Edition of GitLab you can set HTTP headers by adding the following to your gitlab.rb
file:
# gitlab.rb
gitlab_pages['headers'] = [ "Permissions-Policy: interest-cohort=()" ]
You can also specify headers when running the GitLab Pages binary:
./gitlab-pages -header "Permissions-Policy: interest-cohort=()"
Cloudflare Workers
You can create the following to set response headers:
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
async function handleRequest(request) {
let response = await fetch(request)
let newHeaders = new Headers(response.headers)
newHeaders.set("Permissions-Policy", "interest-cohort=()")
return new Response(response.body, {
status: response.status,
statusText: response.statusText,
headers: newHeaders
})
}
Add that Worker script to a domain by setting that domain as the Worker Route.
WordPress
WordPress allows headers to be set from within it’s codebase via hooks. Add the following at the end of your active theme’s functions.php
file:
# functions.php
add_filter(
'wp_headers',
function ( $headers ) {
if ( empty( $headers['Permissions-Policy'] ) ) {
$headers['Permissions-Policy'] = 'interest-cohort=()';
} elseif (
! empty( $headers['Permissions-Policy'] )
&& false === strpos( $headers['Permissions-Policy'], 'interest-cohort' )
) {
$headers['Permissions-Policy'] .= ', interest-cohort=()';
}
return $headers;
}
);
Save the file in the WordPress admin backend and all new requests will contain the necessary header.
If you’re using any caching mechanisms or plugins (such as NGINX’s FastCGI Cache, W3 Total Cache, etc.) you’ll also need to clear the cache so that it be re-populated with the above addition.
It’s also possible to use a plugin that inserts the Permissions-Policy
header.
The only plugin I’ve tested and can recommend is Disable FLoC by Roy Tanck as it takes into consideration the existence of other headers, and is written by a WP Core Contributor.
Notes
Adding <meta http-equiv="Permissions-Policy" content="interest-cohort=()"/>
to the <head>
of each page in an attempt to set the FLoC opt-out header not work.
This is due to both technical and usability reasons as only a small subset of headers can be set using http-equiv
— of which Permissions-Policy
isn’t one of them.
As an aside, HTTP headers should ideally be set by a web or proxy server in order for them to work as expected.
Acknowledgements
The following people helped to expand the information contained in this blog post:
- Don Marti for clarifying the
<meta>
tag issue that led to it being removed - ‘Chronm’ for suggesting the addition of Traefik
- Bryce Wray for providing the Vercel configuration snippet
- Daniel Corbett for providing the HAProxy configuration snippet
- Jeremy Herve for providing the WordPress code snippet
- Bob Marksie for providing the Cloudflare Workers snippet
- Gina Häußge and Martin Woodward (Sr. Dir. of DevRel @ GitHub) for notifying me about the GitHub Pages blog update where they’ve automatically enabled FLoC
Links
- Google’s FLoC Is a Terrible Idea (EFF) - www.eff.org/deeplinks/2021/03/googles-floc-terrible-idea
- How to fight back against Google FLoC (Plausible Analytics) - plausible.io/blog/google-floc
Permissions-Policy
HTTP Header — www.w3.org/TR/permissions-policy-1- Mozilla Firefox — www.mozilla.org/en-US/firefox/new