19
The Web Monetization meta tag and API
The Coil developer site contains more information about technical topics, including a few example scripts.
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">
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');
}
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.
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">
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';
Right now the API doesn’t support this, although it is one of the many ideas under discussion.
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
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
}
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.
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
}
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 thestate
is set topending
. -
monetizationstart
: a monetization stream has started. Fires when thestate
is set tostarted
. -
monetizationprogress
: a new single payment has arrived. See below. -
monetizationstop
: a monetization stream has stopped. Fires when thestate
is set tostopped
.
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';
});
}
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.
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.
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 keepamount
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
})
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.
19