DEV Community

Peter-Paul Koch for Coil

Posted on • Edited on

The Web Monetization meta tag and API

Part 1 of this series made clear why web monetization is a good thing. Part 2 described the Coil system at high level. In this third article we're going to take a closer look at details: the <meta> tag and the JavaScript API.

The Coil developer site contains more information about technical topics, including a few example scripts.

The meta tag

During the sign-up process for Coil and Interledger you set up a wallet, which enables you to receive payments. You are given a payment pointer for that wallet in the form $url.of.server/someID. In order to monetize a page you should add a <meta> tag on that page that contains this pointer:

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

Right now you need tthe Coil extension to read out the <meta> tag — but in the future, when browsers support web monetization natively, they will do so themselves. If a page contains multiple monetization <meta>tags the extension uses the first one and ignores the others.

All this works without JavaScript. Neither the current extension nor the future standard are reliant on scripting for the initiation of a payment stream. If you want to get any information, though, or if you want to change the payment stream’s direction, you need JavaScript.

You can change the payment pointer by changing the <meta>tag. It's ugly, but it works:

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

function changePointer() {
    let meta = document.querySelector('#paymentPointer');
    meta.setProperty('content','$url.of.server/myOtherID');
}
Enter fullscreen mode Exit fullscreen mode

The plugin will pick up on this change even in the middle of a session and divert all future payments to the new payment pointer.

One reason to do so is a collaborative article. If an article has, say, three authors, JavaScript could pick one of them at random and send the payment stream their way. Technically, you do this by switching the <meta>tag's content, as shown above. See this article for more information.

You could also use the Intersection Observer to figure out which page element is in view right now, and change the payment pointer based on that information. This could be useful if one page shows art by several creators, for instance. This article gives an overview and a code example.

Future: link

In the future specification the <meta> tag will likely change to a link tag, like this one:

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

The reasons are complex and can be read here. The upcoming Firefox implementation uses this link, and not a <meta>.

That means that in the future any script that changes the payment pointer has to be rewritten, possibly changing the pointer in both the <meta> and the link tag. For that reason it would be nicer if the JavaScript API offered a direct, imperative way of setting the pointer, like:

document.monetization.pointer = '$url.of.server/someOtherID';
Enter fullscreen mode Exit fullscreen mode

Right now the API doesn’t support this, although it is one of the many ideas under discussion.

JavaScript API

Since we’re on the topic anyway, let’s discuss the JavaScript API. It’s a light-weight, useful thing to have in your back pocket while messing about with payment streams. It consists of the document.monetization container, three events, and one property.

This API is part of the proposed standard, and if browsers start supporting web monetization natively they’ll take over this API as well. In that sense, current extension serves as a polyfill and scripts you write now will continue to work in the future.

document.monetization

document.monetization is the container for all API functionality, and its presence indicates that your current visitor supports monetization:

if (document.monetization) {
    // user may monetize you;
    // find out and do something
} else {
    // user is certain not to monetize you
}
Enter fullscreen mode Exit fullscreen mode

document.monetization is a <div> DOM node that is not inserted into the document. Thus you can read document.monetization.nodeName and most other DOM properties, even though there is no practical reason to do so.

Making it a DOM node allows the firing of the custom monetization events we’ll treat in a moment. Without this trick it appears to be quite difficult to fire custom events from extensions, though specific information is surprisingly hard to find.

state

document.monetization.state contains information about the current monetization state. It can take three values:

  • started: a monetization stream has started and you will receive money. At least one valid Interledger package has been received.
  • pending: a monetization stream has not yet started, but the extension is trying to connect.
  • stopped: no monetization stream possible: the page has no <meta> tag, or the pointer is invalid.

If no <meta> tag is found the initial state is stopped. If a <meta> tag is present the initial state is pending.

If the <meta> tag contains no valid payment pointer the state becomes stopped. If a valid payment pointer is present the extension connects to the Interledger server and waits for the first package. Once that package arrives the state becomes started.

The state remains started even if the connection drops — the extension keeps track of the time spent on the site, after all.

If you change the payment pointer the extension first goes to pending and then to either started or stopped, depending on the validity of the new pointer.

So this snippet tells you if the user is currently paying you:

if (document.monetization && document.monetization.state === 'started') {
    // user is currently paying you
}
Enter fullscreen mode Exit fullscreen mode

Events

document.monetization allows you to capture four events, three of which mirror the state property pretty closely:

  • monetizationpending: a monetization stream is being started up, but is not sending payments yet. Fires when the state is set to pending.
  • monetizationstart: a monetization stream has started. Fires when the state is set to started.
  • monetizationprogress: a new single payment has arrived. See below.
  • monetizationstop: a monetization stream has stopped. Fires when the state is set to stopped.

Typically, when a payer enters a payee’s page and a <meta> tag is present. the monetizationpending event will fire, followed by a monetizationstart event and an indeterminate amount of monetizationprogress events. If the payment pointer is invalid monetizationstop fires.

This is exactly the same sequence as with the state property, except that no event will fire if no <meta> tag is present. The sequence restarts at pending whenever you change the payment pointer.

The information the events deliver allows you to build a basic script to show/hide extra content:

if (document.monetization) {
    let extraContent = document.querySelector('#extraContent');
    document.monetization.addEventListener('monetizationstart',function() {
        extraContent.style.display = 'block'; 
        // or any other way of showing content
    });
    document.monetization.addEventListener('monetizationstop',function() {
        extraContent.style.display = 'none'; 
    });
}
Enter fullscreen mode Exit fullscreen mode

Again, this script is fairly easy to hack, and won't work without JavaScript being enabled. It’s not suited for serious use, especially not in web development sites. Still, it serves as an example of using the monetization events.

monetizationprogress

The monetizartionprogress event fires whenever an Interledge package with a non-zero sum arrives from the Coil servers, which is generally every second or so. It contains information about the amount that's been paid so far, and you could use it to build a micropayment counter.

If the connection drops the payment stream also drops and the monetizationprogress event stops firing. If the connection is restored the event resumes after a new connection to the Interledger server has been made. As we saw before, the extension keeps track of the time the user has spent on your site, and the first payment after the restoration of the connection will pay for that entire time. Thus, you cannot assume that the payer stopped paying just because monetizationprogress stops firing.

Event properties

If you want to find out wha the current payment status is you can use the special properties of these events. All these are properties of event.detail.

  • amount is the amount contained in the current Interledger package, as an integer.
  • assetCode is a code for the currency, either a cryptocurrency or a real one.
  • assetScale is the number of places past the decimal for the amount. This serves to keep amount an integer.
  • paymentPointer is the payment pointer the extension read from the <meta> tag.
  • receipt is a proof of payment sent back to the payer.
  • requestID is a transient ID temporarily assigned to your payment stream.

For instance, this gives you the amount the last package delivered:

document.monetization.addEventListener('monetizationprogress',function(e){
    let amt = e.detail.amount;
    let scale = e.detail.assetScale;
    let code = e.detail.assetCode;
    let amount = amt * Math.pow(10,-scale);
    let printableAmount = code + ' ' + amount;
    // do something with amount or printableAmount
})
Enter fullscreen mode Exit fullscreen mode

paymentPointer contains the same information as the <meta> tag. receipt and requestID contain values that are internal to the Interledger packages. You can use it to write a receipt verifyer if you like.

Reading out the amount of money an Interledger package contains requires the amount-related properties. For instance, if amount is 17 and assetScale is 3 you received 17*10^-3, or 0.017, of the currency indicated in assetCode.

That concludes our study of the <meta> tag and API. In the final part we’ll take a look at web monetization’s future, which includes a formal W3C standard.

Top comments (0)