WMS changes part 1: Breaking changes
Tags: webmonetization, webdev, coil
Published: 2021-10-12 10:00:08

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](https://dev.to/coil/wms-changes-part-2-background-information-45m9) 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](https://webmonetization.org/specification.html) 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](https://dev.to/coil/an-update-from-the-web-monetization-workshop-3ppd) 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">
```

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](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) 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](https://github.com/WICG/webmonetization/issues/19#issuecomment-705407129).

### 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">
```

you replace it with this `<link>` tag:

```
<link rel="monetization" href="https://url.of.server/someID">
```

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](https://paymentpointers.org/syntax-resolution/#resolution) 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');
    meta.setProperty('content','$url.of.server/myOtherID');
}
```

It's ugly, but it works. (For more information about the current JavaScript API, see [this earlier article](https://dev.to/coil/the-web-monetization-meta-tag-and-api-3eh9).)

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');
    meta.setProperty('content','$url.of.server/myOtherID');
    let link = document.querySelector('#otherPaymentPointer');
    link.setProperty('href','https://url.of.server/myOtherID');
}
```

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';
}
```

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](https://dev.to/coil/wms-changes-part-2-background-information-45m9) 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](https://dev.to/coil/the-web-monetization-meta-tag-and-api-3eh9). 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:

```
document.monetization.state
```

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

```
navigator.monetization.state
```

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
}
```

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](https://dev.to/coil/wms-changes-part-2-background-information-45m9) in this series takes a look at a few.