I have recently learned that deferred loading of <img>
s with the loading
attribute only works if JavaScript is enabled.
<img loading="lazy" src="/image.jpg" alt="" />
The MDN documentation notes that this is an anti-tracking measure:
Loading is only deferred when JavaScript is enabled. This is an anti-tracking measure, because if a user agent supported lazy loading when scripting is disabled, it would still be possible for a site to track a user's approximate scroll position throughout a session, by strategically placing images in a page's markup such that a server can track how many images are requested and when.
While the purpose of this behaviour seems reasonable on the surface, it made me thinks about two things:
1. The goal of disabling JS
This anti-tracking measure assumes that a user's goal of disabling JS is to prevent websites from tracking them and their actions on pages. This assumption justifies loading more resources on the user's device even if they do not scroll far enough down a page to need them.
I can't personally speak of the intention of disabling JS, but I am unsure how I feel about disabling the feature when JS is disabled in order to prevent tracking. After all, web features get maliciously used all the time.
Disabling deferred loading on img[loading=lazy]
can have a direct impact on the user. I can see a user disabling JS in the browser to save on mobile data while browsing. They may not need to scroll all the way down to all pages. That is; they may not need to download all the images on all pages they visit. In this case, the anti-tracking measure backfires.
2. The noscript tracking paths
There are plenty of user-behaviour tracking approaches that work without JS.
The loading attribute on iframe
The loading
attribute also works on <iframe>
s. The current implementation of the loading
attribute on <iframe>
works even when JS is disabled. iFrame tracking pixels can be used to workaround the anti-tracking measure on images.
The ping attribute on anchor tags
The ping
attribute on an anchor tag is typically used for tracking. It accepts a space-separated list of URLs to which the browser sends POST requests when the link is followed:
<a
href="/contact"
ping="https://example.com/my-tracker https://example.com/my-other-tracker"
>
Contact Us
</a>
The ping
attribute works even when JS is disabled. It is disabled by default in Firefox though.
The noscript tag
The <noscript>
element can be used to conditionally load different/additional tracking pixels when JS is disabled:
<noscript>
<!-- add tracking pixels here -->
</noscript>
The CSS approach
CSS provides a number of ways to conditionally apply styles. It also provides a number of ways to load external resources such as images. So it is entirely possible to make use of this to track users without the need of JS.
Using media queries:
@media (prefers-color-scheme: dark) {
#tracker {
background-image: url(/my-tracker.png);
}
}
Using feature queries and browser-specific prefixed CSS properties:
@supports (-webkit-overflow-scrolling: touch) {
#tracker {
background-image: url(/my-tracker.png);
}
}
CSS also provides a number of ways to apply styles based on user interactions. For example, you can track some user actions in a similar manner to the above using pseudo-classes. And I'm sure there are more novel ways to make use of other CSS features for tracking.
Final thoughts
Built-in anti-tracking measures is a very nice goal in theory, but it seems very hard to implement without sacrificing something else in return.
So this begs the question: is "whether JS is enabled in the browser" the right criterion for enforcing built-in anti-tracking measures?
This article was first published on hussein-alhammad.com on 20 February 2021
Top comments (0)