DEV Community

Peter-Paul Koch for Coil

Posted on • Updated on

WMS changes part 1: Breaking changes

In this two-part series we will look at recent developments in the Web Monetization specification and the Coil extension. This article discusses two upcoming breaking changes, while the next one treats several planned changes that won’t take effect immediately, as well as one piece of background.

This year, two breaking changes will be introduced in the Web Monetization specification and the Coil extension. The payment pointer will move from the <meta> to the <link> tag, and the JavaScript monetization interface will move from document to navigator. We will discuss those two changes and what you have to do to adjust your code.

<meta> to <link>

When a user with the Coil extension — or, in the future, a browser that supports web monetization — visits a monetized page the browser has to fetch a JSON file with monetization information. The location of this file has to be defined somewhere. Where?

One of the decisions made in the Web Monetization workshop was to move this definition from the <meta> tag to the <link> tag.

The old situation

The Coil extension currently uses <meta>; for instance

<meta name="monetization" content="$url.of.server/someID">
Enter fullscreen mode Exit fullscreen mode

Browsers now download the JSON file from url.of.server/someID.

In the first draft of web monetization this tag was useful because <meta> tags do not have any default behavior, and Coil's extension could do anything it liked. Since web monetization was a new idea Coil needed to be able to work unimpeded by earlier decisions and functionalities already baked into browsers. Thus, using a neutral tag like <meta> was a good idea.

Why <link>?

Meanwhile web monetization is entering a new stage, where it has to be made ready for formal specification and native browser support. Use of <meta> is starting to restrict the future standard and the current implementations. By contrast there are several reasons why <link> is more future-friendly.

<link> specifies a relationship of the HTML document it appears in with an external resource, while <meta> gives more information about the HTML document itself. From the browsers' perspective, web monetization is an external resource. It doesn't have anything to do with the rendering process of the page; it merely defines external functionality. Thus, <link> is the correct tag to use here.

In addition, <link> has some useful functionalities that are already built into browsers:

  • With <link>, browsers already have a fetching mechanism for downloading external assets such as style sheets and favicons. Adding the monetization JSON file as a new one is fairly easy.
  • <link>’s referrerpolicy attribute allows you to decide how much information about the page the user is visiting browsers will send while they fetch the JSON.
  • <link> allows you to decide what to do about cross-origin policies. If browsers fetch the JSON file, what kind of information about the user will be sent to the payment end-point? From a privacy perspective the best answer is None, and the crossorigin="anonymous" attribute makes sure nothing is sent. Still, it allows web developers to define other CORS policies if necessary.
  • The disabled attribute allows web authors to disable the monetization link if they want to pause monetization.
  • A <link> tag is equivalent to a Link HTTP header. HTTP headers allow monetization information to be added to non-HTML documents as well — such as a PDF with an article that you'd like to monetize. Right now neither the specification nor the extension support this, but it can be easily added in the future.

Again, the main reason for the switch is that <link> contains these functionalities out of the box. It is possible to add all of them to <meta>, but why bother if browsers already offer a perfectly good alternative? You can read more about <meta> vs. <link> in this discussion.

Changes to your pages

The switch to <link> is a breaking change because you have to add a <link> to your website instead of <meta>. Fortunately that's quite simple. If you have this <meta> tag

<meta name="monetization" content="$url.of.server/someID">
Enter fullscreen mode Exit fullscreen mode

you replace it with this <link> tag:

<link rel="monetization" href="https://url.of.server/someID">
Enter fullscreen mode Exit fullscreen mode

As you see, the content/href of the two is not exactly the same. The current <meta> tag does not use a URL, but the <link> tag is required to — it should link to an external resource, after all, and browsers can only find that resource if you use a proper URL. In this simple example, replacing the custom $ by the standard https:// is all that's necessary.

Unfortunately there are also more complex cases, where <meta content> does not map to <link href> one on one. Be sure to read the payment pointer syntax article in order to convert all your pointers correctly.

The current Coil extension supports both <meta> and <link>, so it should seamlessly switch between the two. Even if it finds both tags in the HTML the extension will make sure only one payment occurs. Once browsers start supporting web monetization natively they will only recognize <link> and ignore <meta>.

Setting the payment pointer

The only minor outstanding problem is the way you change the payment pointer. Up until now the only way to do so was to change the content attribute of the <meta> tag, like so:

<meta name="monetization" content="$url.of.server/someID" id="paymentPointer">

function changePointer() {
    let meta = document.querySelector('#paymentPointer');
Enter fullscreen mode Exit fullscreen mode

It's ugly, but it works. (For more information about the current JavaScript API, see this earlier article.)

Once you use <link>, though, you have to write a slightly different script, and if you use both <link> and <meta> you have to change both of them.

<meta name="monetization" content="$url.of.server/someID" id="paymentPointer">
<link rel="monetization" href="https://url.of.server/someID" id="otherPaymentPointer">

function changePointer() {
    let meta = document.querySelector('#paymentPointer');
    let link = document.querySelector('#otherPaymentPointer');
Enter fullscreen mode Exit fullscreen mode

This is not impossible, but it's not very developer-friendly, either. What we need is a way to set the payment pointer directly in the API instead of messing about with HTML attributes. Ideally, it would be something like this:

function changePointer() {
    document.monetization.pointer = 'https://url.of.server/myOtherID';
Enter fullscreen mode Exit fullscreen mode

Right now the extension supports getting the payment pointer in monetization.pointer, but not setting it. While a settable pointer is under discussion in the standards track, it turns out there are some issues that make it unlikely it will be implemented in the manner shown above. We’ll get back to this problem in the second part of this series.

document to navigator

The monetization interface is a collection of useful properties and events that let you monitor the monetization state of your web pages. The full current API is described here. Up until now it was a part of document, but it’s going to switch to navigator.

This, too, is a breaking change, and it has similar reasons as the switch from <link> to <meta>.

From document to navigator

At the moment the monetization interface is part of the document; for instance:

Enter fullscreen mode Exit fullscreen mode

It's going to move to navigator, and this line of code will become:

Enter fullscreen mode Exit fullscreen mode

Appending monetization to document has never made a lot of sense. Furthermore, document.monetization is a <div> tag, and that has never made any sense either.

In addition, appending monetization to the document could cause problems. It's possible to create a new document in JavaScript, and if monetiztion would be appended to that document it would also be monetized. This could lead to odd situations that it's better to prevent than repair.

Besides, the existence of web monetization is a top-level function of the browser, and not of the page. Moving it to navigator, especially in conjunction with moving the <meta> tag to a <link> tag, makes excellent sense. Also, navigator.monetization will no longer be a <div>.

The Coil extension will add navigator.monetization later this year — right now the road map says November. The Puma browser, which uses the Coil extension, will add it a few weeks later. For now they will also continue to support document.monetization.

Changes to your pages

Although there will be a transition period where the extension supports both, eventually support for document.monetization will end, and by that time this will become a breaking change.

That is, in the future any script that still uses document.monetization will break, since it cannot find the document.monetization interface. It should look for navigator.monetization instead, and you will have to code that explicitly. It’s best to do it right now so that you won’t have to worry again.

I advise you to do the following:

  1. Throughout your scripts, change document.monetization to navigator.monetization.
  2. Add the following snippet at the start of your script:
if (!navigator.monetization) {
    navigator.monetization = document.monetization

if (navigator.monetization) {
    // your scripts that use navigatior.monetization go here
Enter fullscreen mode Exit fullscreen mode

If navigator.monetization does not exist, make it an alias of document.monetization. If your user’s browser does not support monetization document.monetization will not exist, either, but that’s OK.

Then check again if navigator.monetization exists. If it’s either supported natively or it’s an alias of document.monetization your script will run. If it’s still undefined your script will fail gracefully.

With that we have treated the upcoming changes in the Coil extension. Meanwhile, the Web Monetization standard remains in development, and it will likely introduce more changes. The next part in this series takes a look at a few.

Discussion (0)