Web fingerprinting is worse than I thought - Bitestring’s Blog
How browser fingerprinting works and what you can do about it (if you use Firefox).
How browser fingerprinting works and what you can do about it (if you use Firefox).
Jen pointed me to this proposal, which should help smooth over some of the inconsistencies I documented in iOS when it comes to the Web Audio API.
I’ve preemptively add this bit of feature detection to The Session:
if ('audioSession' in navigator) {
navigator.audioSession.type = "playback";
}
So much ink spilled supposedly explaining what “the web platform” is …when the truth is you can just swap in the “the web” every time that phrase is used here or anywhere else.
Anyway, the gist of this piece is: the web is good, actually.
All twelve are out, and all twelve are excellent deep dives into exciting web technologies landing in browsers now.
A while back I wrote a blog post called Web Audio API weirdness on iOS. I described a bug in Mobile Safari along with a hacky fix. I finished by saying:
If you ever find yourself getting weird but inconsistent behaviour on iOS using the Web Audio API, this nasty little hack could help.
Recently Jonathan Aldrich posted a thread about the same bug. He included a link to my blog post. He also said:
Thanks so much for your post, this was a truly pernicious problem!
That warms the cockles of my heart. It’s very gratifying to know that documenting the bug (and the fix) helped someone out. Or, as I put it:
Yay for bugblogging!
Forgive the Germanic compound word, but in this case I think it fits.
Bugblogging doesn’t need to involve a solution. Just documenting a bug is a good thing to do. Recently I documented a bug with progressive web apps on iOS. Before that I documented a bug in Facebook Container for Firefox. When I documented some weird behaviour with the Web Share API in Safari on iOS, I wasn’t even sure it was a bug but Tess was pretty sure it was and filed a proper bug report.
I’ve benefited from other people bugblogging. Phil Nash wrote Service workers: beware Safari’s range request. That was exactly what I needed to solve a problem I’d been having. And then that post about Phil solving my problem helped Peter Rukavina solve a similar issue so he wrote Phil Nash and Jeremy Keith Save the Safari Video Playback Day.
Again, this warmed the cockles of my heart. Bugblogging is worth doing just for the reward of that feeling.
There’s a similar kind of blog post where, instead of writing about a bug, you write about a particular technique. In one way, this is the opposite of bugblogging because you’re writing about things working exactly as they should. But these posts have a similar feeling to bugblogging because they also result in a warm glow when someone finds them useful.
Here are some recent examples of these kinds of posts—tipblogging?—that I’ve found useful:
All three are very handy tips. Thanks, Eric! Thanks, Rich! Thanks, Stephanie!
I feel like it’s high time I revived some interest in my proposal for button type="share"
. Last I left it, I was gathering use cases and they seem to suggest that the most common use case for the Web Share API is sharing the URL of the current page.
If you want to catch up on the history of this proposal, here’s what I’ve previously written:
Remember, my proposal isn’t to replace the JavaScript API, it’s to complement it with a declarative option. The declarative option doesn’t need to be as fully featured as the JavaScript API, but it should be able to cover the majority use case. I think this should hold true of most APIs.
A good example is the Constraint Validation API. For the most common use cases, the required
attribute and input type
s like “email”, “url”, and “number” have you covered. If you need more power, reach for the JavaScript API.
A bad example is the Geolocation API. The most common use case is getting the user’s current location. But there’s no input type="geolocation"
(or button type="geolocation"
). Your only choice is to use JavaScript. It feels heavy-handed.
I recently got an email from Taylor Hunt who has come up with a good litmus test for JavaScript APIs that should have a complementary declarative option:
I’ve been thinking about how a lot of recently-proposed APIs end up having to deal with what Chrome devrel’s been calling the “user gesture/activation budget”, and wondering if that’s a good indicator of when something should have been HTML in the first place.
I think he’s onto something here!
Think about any API that requires a user gesture. Often the documentation or demo literally shows you how to generate a button in JavaScript in order to add an event handler to it in order to use the API. Surely that’s an indication that a new button type
could be minted?
The Web Share API is a classic example. You can’t invoke the API after an event like the page loading. You have to invoke the API after a user-initiated event like, oh, I don’t know …clicking on a button!
The Fullscreen API has the same restriction. You can’t make the browser go fullscreen unless you’re responding to user gesture, like a click. So why not have button type="fullscreen"
in HTML to encapsulate that? And again, the fallback in non-supporting browsers is predictable—it behaves like a regular button—so this is trivial to polyfill. I should probably whip up a polyfill to demonstrate this.
I can’t find a list of all the JavaScript APIs that require a user gesture, but I know there’s more that I’m just not thinking of. I’d love to see if they’d all fit this pattern of being candidates for a new button type
value.
The only potential flaw in this thinking is that some APIs that require a user gesture might also require a secure context (either being served over HTTPS or localhost
). But as far as I know, HTML has never had the concept of features being restricted by context. An element is either supported or it isn’t.
That said, there is some prior art here. If you use input type="password"
in a non-secure context—like a page being served over HTTP—the browser updates the interface to provide scary warnings. Perhaps browsers could do something similar for any new button type
s that complement secure-context JavaScript APIs.
This is a terrific analysis of why frameworks exist, with nods to David Hume’s is-ought problem: the native features are what is, and the framework features are what somebody thinks ought to be.
I’ve been saying at conferences for years now that if you choose to use a framework, you need to understand that you are also taking on the philosophy and worldview of the creators of that framework. This post does a great job of explaining that.
After I jotted down some quick thoughts last week on the disastrous way that Google Chrome rolled out a breaking change, others have posted more measured and incisive takes:
In fairness to Google, the Chrome team is receiving the brunt of the criticism because they were the first movers. Mozilla and Apple are on baord with making the same breaking change, but Google is taking the lead on this.
As I said in my piece, my issue was less to do with whether confirm()
, prompt()
, and alert()
should be deprecated but more to do with how it was done, and the woeful lack of communication.
Thinking about it some more, I realised that what bothered me was the lack of an upgrade path. Considering that dialog
is nowhere near ready for use, it seems awfully cart-before-horse-putting to first remove a feature and then figure out a replacement.
I was chatting to Amber recently and realised that there was a very different example of a feature being deprecated in web browsers…
We were talking about the KeyboardEvent.keycode
property. Did you get the memo that it’s deprecated?
But fear not! You can use the KeyboardEvent.code
property instead. It’s much nicer to use too. You don’t need to look up a table of numbers to figure out how to refer to a specific key on the keyboard—you use its actual value instead.
So the way that change was communicated was:
Hey, you really shouldn’t use the
keycode
property. Here’s a better alternative.
But with the more recently change, the communication was more like:
Hey, you really shouldn’t use
confirm()
,prompt()
, oralert()
. So go fuck yourself.
Safari has been subjected to a lot of ire recently. Most of that ire has been aimed at the proposed changes to the navigation bar in Safari on iOS—moving it from a fixed top position to a floaty bottom position right over the content you’re trying to interact with.
Courage.
It remains to be seen whether this change will actually ship. That’s why it’s in beta—to gather all the web’s hot takes first.
But while this very visible change is dominating the discussion, invisible changes can be even more important. Or in the case of Safari, the lack of changes.
Compared to other browsers, Safari lags far behind when it comes to shipping features. I’m not necessarily talking about cutting-edge features either. These are often standards that have been out for years. This creates a gap—albeit an invisible one—between Safari and other browsers.
Jorge Arango has noticed this gap:
I use Safari as my primary browser on all my devices. I like how Safari integrates with the rest of the OS, its speed, and privacy features. But, alas, I increasingly have issues rendering websites and applications on Safari.
That’s the perspective of an end-user. Developers who have to deal with the gap in features are more, um, strident in their opinions. Perry Sun wrote For developers, Apple’s Safari is crap and outdated:
Don’t get me wrong, Safari is very good web browser, delivering fast performance and solid privacy features.
But at the same time, the lack of support for key web technologies and APIs has been both perplexing and annoying at the same time.
Alas, that post also indulges in speculation about Apple’s motives which always feels a bit too much like a conspiracy theory to me. Baldur Bjarnason has more to say on that topic in his post Kremlinology and the motivational fallacy when blogging about Apple. He also points to a good example of critiquing Safari without speculating about motives: Dave’s post One-offs and low-expectations with Safari, which documents all the annoying paper cuts inflicted by Safari’s “quirks.”
Another deep dive that avoids speculating about motives comes from Tim Perry: Safari isn’t protecting the web, it’s killing it. I don’t agree with everything in it. I think that Apple—and Mozilla’s—objections to some device APIs are informed by a real concern about privacy and security. But I agree with his point that it’s not enough to just object; you’ve got to offer an alternative vision too.
That same post has a litany of uncontroversial features that shipped in Safari looong after they shipped in other browsers:
Again: these are not contentious features shipping by only Chrome, they’re features with wide support and no clear objections, but Safari is still not shipping them until years later. They’re also not shiny irrelevant features that “bloat the web” in any sense: each example I’ve included above primarily improving core webpage UX and performance. Safari is slowing that down progress here.
But perhaps most damning of all is how Safari deals with bugs.
A recent release of Safari shipped with a really bad Local Storage bug. The bug was fixed within a day. Yay! But the fix won’t ship until …who knows?
This is because browser updates are tied to operating system updates. Yes, this is just like the 90s when Microsoft claimed that Internet Explorer was intrinsically linked to Windows (a tactic that didn’t work out too well for them in the subsequent court case).
I don’t get it. I’m pretty sure that other Apple products ship updates and fixes independentally of OS releases. I’m sure I’ve received software updates for Keynote, Garage Band, and other pieces of software made by Apple.
And yet, of all the applications that need a speedy update cycle—a user agent for the World Wide Web—Apple’s version is needlessly delayed by the release cycle of the entire operating system.
I don’t want to speculate on why this might be. I don’t know the technical details. But I suspect that the root cause might not be technical in nature. Apple have always tied their browser updates to OS releases. If Google’s cardinal sin is avoiding anything “Not Invented Here”, Apple’s downfall is “We’ve always done it this way.”
Evergreen browsers update in the background, usually at regular intervals. Firefox is an evergreen browser. Chrome is an evergreen browser. Edge is an evergreen browser.
Safari is not an evergreen browser.
That’s frustrating when it comes to new features. It’s unforgivable when it comes to bugs.
At least on Apple’s desktop computers, users have the choice to switch to a different browser. But on Apple’s mobile devices, users have no choice but to use Safari’s rendering engine, bugs and all.
As I wrote when I had to deal with one of Safari’s bugs:
I wish that Apple would allow other rendering engines to be installed on iOS devices. But if that’s a hell-freezing-over prospect, I wish that Safari updates weren’t tied to operating system updates.
It would be nice to be able to animate the transition between pages if we want to on the web without resorting to hacks or full-blown architecture choices to achieve it.
Amen, Chris, amen!
The danger here is that you might pick a single-page app just for this ability, which is what I mean by having to buy into a site architecture just to achieve this.
This is a very thoughtful and measured response to Alex’s post Platform Adjacency Theory.
Unlike Alex, the author doesn’t fire off cheap shots.
Also, I’m really intrigued by the idea of certificate authorities for hardware APIs.
This is a good round-up of APIs you can use to decide if and how much JavaScript to load. I might look into using storage.estimate()
in service workers to figure out how much gets pre-cached.
I spent the last couple of weekends rolling out a new feature on The Session. It involves playing audio in a web page. No big deal these days, right? But the history involves some old file formats…
The first venerable format is ABC notation. File extension: .abc
, mime type: text/vnd.abc
. It’s an ingenious text format for musical notation using ASCII. The metadata of the piece of music is defined in JSON-like key/value pairs. Then the contents are encoded with letters: A, B, C, etc. Uppercase and lowercase denote different octaves. Numbers can be used for note lengths.
The format was created by Chris Walshaw in 1997 when dial-up was the norm. With ABC, people were able to swap tunes on email lists or bulletin boards without transferring weighty image or sound files. If you had ABC software on your computer, you could convert that lightweight text file into sheet music …or audio.
That brings me to the second old format: midi files. File extension: .mid
, mime-type: audio/midi
. Like ABC, it’s a lightweight format for encoding the instructions for music instead of the music itself.
Think of it like SVG: instead of storing the final pixels of an image, SVG stores the instructions for drawing the image instead. The instructions in a midi file are like “play this note for this long on this instrument.” Again, as with ABC, you need some software to turn the instructions into sound.
There was a time when lots of software could play midi files. Quicktime on the Mac, for example. You could even embed midi files in web pages. I mean literally embed them …with the embed
element. No Geocities page was complete without an autoplaying midi file.
On The Session, people submit tunes in ABC format. Then, using the amazing ABCJS JavaScript library, the ABC is turned into SVG on the fly! For years I’ve also offered midi files, generated on the server from the ABC notation.
But times have changed. These days it’s hard to find software that plays midi files. Quicktime doesn’t do it anymore. And you’d need to go to the app store on iOS to find a midi file player. It’s time to phase out the midi files on The Session.
I still want to provide automatically-generated audio though. Fortunately ABCJS gives me a way to do this. But instead of using the old technology of midi files, it uses a more modern browser feature: the Web Audio API.
The end result sounds like a midi file, but the underlying technique is more like a synthesiser. There’s a separate mp3 file for each note. The JavaScript figures out how long each “sample” needs to be played for, strings them all together, and outputs them with Web Audio. So you’ve got cutting-edge browser technology recreating a much older file format. Paul Rosen—the creator of ABCJS—has a presentation explaining how it all works under the hood.
Not only is there a separate short mp3 file for each note in seven octaves, but if you want the sound of a different instrument, you need samples for all seven octaves in that instrument. They’re called soundfonts.
Paul provides soundfonts for ABCJS. It’s a repo that was forked from this repo from Benjamin Gleitzman. And here’s where it gets small worldy…
The reason why Benjamin has a repo of soundfonts is because he needed to create midi-like audio in the browser. He wanted to do this for a project on September 28th and 29th, 2013 …at Science Hack Day San Francisco!
I was there too—working on my own audio-related hack—and I remember the excellent (and winning) hack that Benjamin worked on. It was called Symphony of Satellites and it’s still online along with the promo video. Here’s Benjamin’s post-hackday write-up from seven years ago.
It’s rare that the worlds of the web and Irish music cross over. When I got to meet Paul—creator of ABCJS—at a web conference a couple of years ago it kind of blew my mind. Last weekend when I set out to dabble with a feature on The Session, I certainly didn’t expect to stumble on a connection to Science Hack Day! (Aside: the first Science Hack Day was ten years ago—yowzers!)
Anyway, I was able to get that audio playback working on The Session. Except for some weirdness on iOS that I had to fix. But that’s a hack for another day.
Principles behind the design of web APIs:
- Put user needs first (Priority of Constituencies)
- It should be safe to visit a web page
- Trusted user interface should be trustworthy
- Ask users for meaningful consent when appropriate
- Support the full range of devices and platforms (Media Independence)
I should add these to my collection.
This is a wonderful tale of spelunking into standards from Darius Kazemi—I had no idea that HTTP status codes have their origin in a hastily made decision in the days of ARPANET.
20 people got together at MIT in 1972 for a weekend workshop. On the second day, a handful of people in a breakout session decided it would be a good idea to standardize error messages between two services for transferring data, even though those two services had not necessarily planned to speak to one another. One thing led to another, and now 404 is synonymous with “I can’t find the thing.”
This story is exactly the kind of layering of technologies that I was getting at in the first chapter of Resilient Web Design.
HTTP status codes are largely an accident of history. The people who came up with them didn’t plan on defining a numerical namespace that would last half a century or work its way into popular culture. You see this pattern over and over in the history of technology.
This sounds like seamful design:
How to enable not users but adaptors? How can people move from using a product, to understanding how it hangs together and making their own changes? How do you design products with, metaphorically, screws not nails?
John weighs in on the clashing priorities of browser vendors.
Imagine if the web never got CSS. Never got a way to style content in sophisticated ways. It’s hard to imagine its rise to prominence in the early 2000s. I’d not be alone in arguing a similar lack of access to the sort of features inherent to the mobile experience that WebKit and the folks at Mozilla have expressed concern about would (not might) largely consign the Web to an increasingly marginal role.
The latest newsletter from The History Of The Web is a good one: The Browser Engine That Could. It’s all about the history of browsers and more specifically, rendering engines.
Jay quotes from a 1992 email by Tim Berners-Lee when there was real concern about having too many different browsers. But as history played out, the concern shifted to having too few different browsers.
I wrote about this—back when Edge switched to using Chromium—in a post called Unity where I compared it to political parties:
If you have hundreds of different political parties, that’s not ideal. But if you only have one political party, that’s very bad indeed!
I talked about this some more with Brian and Stuart on the Igalia Chats podcast: Web Ecosystem Health (here’s the mp3 file).
In the discussion we dive deeper into the naunces of browser engine diversity; how it’s not the numbers that matter, but representation. The danger with one dominant rendering engine is that it would reflect one dominant set of priorities.
I think we’re starting to see this kind of battle between different sets of priorities playing out in the browser rendering engine landscape.
Webkit published a list of APIs they won’t be implementing in their current form because of security concerns around fingerprinting. Mozilla is taking the same stand. Google is much more gung-ho about implementing those APIs.
I think it’s safe to say that every implementor wants to ship powerful APIs and ensure security and privacy. The issue is with which gets priority. Using the language of principles and priorities, you could crudely encapsulate Apple and Mozilla’s position as:
Privacy, even over capability.
That design principle would pass the reversibility test. In fact, Google’s position might be represented as:
Capability, even over privacy.
I’m not saying Apple and Mozilla don’t value powerful APIs. I’m not saying Google doesn’t value privacy. I’m saying that Google’s priorities are different to Apple’s and Mozilla’s.
Alas, Alex is saying that Apple and Mozilla don’t value capability:
There is a contingent of browser vendors today who do not wish to expand the web platform to cover adjacent use-cases or meaningfully close the relevance gap that the shift to mobile has opened.
That’s very disappointing. It’s a cheap shot. As cheap as saying that, given Google’s business model, Chrome wouldn’t want to expand the web platform to provide better privacy and security.
On Monday, I linked to Tom’s latest video. It uses a clever trick whereby the title of the video is updated to match the number of views the video has had. But there’s a lot more to the video than that. Stick around and you’ll be treated to a meditation on the changing nature of APIs, from a shared open lake to a closed commercial drybed.
It reminds me of (other) Tom’s post from a couple of year’s ago called Pouring one out for the Boxmakers, wherein he talks about Twitter’s crackdown on fun bots:
Web 2.0 really, truly, is over. The public APIs, feeds to be consumed in a platform of your choice, services that had value beyond their own walls, mashups that merged content and services into new things… have all been replaced with heavyweight websites to ensure a consistent, single experience, no out-of-context content, and maximising the views of advertising. That’s it: back to single-serving websites for single-serving use cases.
A shame. A thing I had always loved about the internet was its juxtapositions, the way it supported so many use-cases all at once. At its heart, a fundamental one: it was a medium which you could both read and write to. From that flow others: it’s not only work and play that coexisted on it, but the real and the fictional; the useful and the useless; the human and the machine.
Both Toms echo the sentiment in Anil’s The Web We Lost, written back in 2012:
Five years ago, if you wanted to show content from one site or app on your own site or app, you could use a simple, documented format to do so, without requiring a business-development deal or contractual agreement between the sites. Thus, user experiences weren’t subject to the vagaries of the political battles between different companies, but instead were consistently based on the extensible architecture of the web itself.
I know, I know. We’re a bunch of old men shouting at The Cloud. But really, Anil is right:
This isn’t our web today. We’ve lost key features that we used to rely on, and worse, we’ve abandoned core values that used to be fundamental to the web world. To the credit of today’s social networks, they’ve brought in hundreds of millions of new participants to these networks, and they’ve certainly made a small number of people rich.
But they haven’t shown the web itself the respect and care it deserves, as a medium which has enabled them to succeed. And they’ve now narrowed the possibilites of the web for an entire generation of users who don’t realize how much more innovative and meaningful their experience could be.
In his video, Tom mentions Yahoo Pipes as an example of a service that has been shut down for commercial and idealogical reasons. In many ways, it was the epitome of what Anil was talking about—a sort of meta-API that allowed you to connect different services together. Kinda like IFTTT but with a visual interface that made it as empowering as something like the Scratch programming language.
There are services today that provide some of that functionality, but they’re more developer-focused. Trys pointed me to Pipedream, which looks good but you need to know how to write Node.js code and import npm packages. I’m sure it’s great if you’re into serverless Jamstack lambda thingamybobs but I don’t think it’s going to unlock the potential for non-coders to create cool stuff.
On the more visual pipes-esque Scratchy side, Cassie pointed me to Cables:
Cables is a tool for creating beautiful interactive content.
It isn’t about making mashups, but it does look something that non-coders could potentially use to make something that looks cool. It reminds me a bit of Bret Victor and his classic talk on Inventing On Principle—always worth revisting!
80 geocoding service plans to choose from.
I’m going to squirrel this one away for later—I’ve had to switch geocoding providers in the past, so I have a feeling that this could come in handy.