Here are a few simple example scripts that will teach you how to work with the Web Monetization API.
The first thing you want to do is detect if a visitor supports web monetization at all.
let testLink = document.querySelector('link[rel=monetization]') if (testLink && testLink.relList.supports("monetization")) { // browser supports Web Monetization }
First we take a test link: the first <link rel="monetization">
in the document - for this script it doesn't matter which link we use. Then we see if the keyword monetization
is supported by its relList
; that is, if the keyword is allowed as a value of rel
. If so the browser supports web monetization.
Support does not mean that the visitor actually sends a payment stream. It only proves the browser could send a payment stream. In order to find out if it actually does so you'll have to wait for the first monetization
event.
It's possible to switch the payment pointer of a <link >
tag.
let newPointer = 'https://my.other.pointer/pay'; let link = document.querySelector('link[rel=monetization]'); link.setAttribute('href',newPointer);
Setting the href
attribute of the <link>
tag is enough. The next time the web monetization agent requests a payment it will use the new payment pointer, and the payment stream will go to the new payment receiver. Any payments that are pending when the href
is changed will still go to the old payment receiver, though.
You could opt to show part of the content of your site only to paying visitors. This is one script you could use; it loads the content of one section only once a payment arrives.
<section id="premiumContent"> <link rel="monetization" href="https://example.com/premiumcontent/pay"> <div></div> </section>
We place the <link>
in the <section>
. This is not required, but it makes the script easier since we can treat the entire section as one monetized unit. The empty <div>
will eventually hold the premium content.
let section = document.querySelector('#premiumContent'); let target = section.querySelector('div'); section.addEventListener('monetization',function(e) { fetch('premium-content.txt') .then(function(response){ response.text() .then(function(text){ target.innerHTML = text; })}); } },{once:true})
We define an event listener for monetization
that fires only once ({once:true}
). The event fires on the link and bubbles up to the section, where we capture it and read out its currentTarget
, i.e. the element the event is being handled on. This is the section. (e.target
would be the element the event fires on, which is the link. But it's easier to handle everything on the section.)
Then we send out a fetch
request for the premium content and show it in the div
.
If the visitor does not send a payment stream the monetization
event never fires and the function is never executed.
In the next example we have a video on the page that will only play if a payment stream is detected. We start with similar HTML as in the previous example; and note that the video doesn't have controls and doesn't play.
<video src="myvideo"> <link rel="monetization" href="https://example.com/video/pay"> </video>
Again the <link>
tag could be anywhere, but placing it in the video
element keeps things easy. Like in the previous example, we wait for a monetization
event.
let video = document.querySelector('#myvideo'); video.addEventListener('monetization',function(e) { video.controls = true; video.play(); } },{once:true})
Again, this event fires only once, and when it does it shows the video's controls and starts playing it. Note that, depending on the browser, the play()
command may not work if the user hasn't yet interacted with the page - this is a safety precaution against playing videos automatically and without the user asking for it. But the user can use the controls to start up the video manually, if necessary. Maybe you even want to remove the play()
entirely and leave it to the user to start the video in all situations.
You could also opt to show the premium content only after you received a certain amount of money. That requires you to keep listening to the monetization
event until the payment stream passes the threshold.
let item = [the item you want to monetize]; let receivedAmount = 0; let threshold = 0.002; item.addEventListener('monetization',checkAmount); function checkAmount(e) { let amount = e.amount; let scale = e.assetScale; let received = amount * (10 ** -scale); receivedAmount += received; if (receivedAmount > threshold) { // fetch content or play video item.removeEventListener('monetization',checkAmount) } }
When a monetization
event fires you check the amount and multiply it by 10 to the power of negative the scale; i.e. if amount
is 17 and scale
is 3 you received 17 * 10^-3 = 0.017. Add this amount to receivedAmount
, and then check if it has gone above the threshold. If it hasn't, wait for the next event. If it has, show the premium content and remove the event listener - it is no longer needed.
The load
event fires when a payment pointer JSON file has loaded successfully, and the and error
event fires when something has gone wrong with retrieving it - either it doesn't exist at all or it is malformed. Sometimes you want to read the status of your requests, especially when a page contains multiple <link>
tags and one of them is misbehaving.
document.addEventListener('load',monitorLoading,true); document.addEventListener('error',monitorLoading,true); function monitorLoading(e) { let node = e.target; if (node.nodeName === 'LINK' && node.getAttribute('rel') === 'monetization) { let pointer = node.getAttribute('href'); if (e.type === 'load') { console.log(pointer + ' loaded correctly') } else if (e.type === 'error') { console.log('Attempting to load ' + pointer + ' caused an error') } } }
If the page contains multiple <link>
tags it's easiest to capture both events at the document level so that all events from all tags end up at the same function. Since other elements can fire load
or error
events as well we have to check if the event originates from a <link rel="monetization">
. If it does we write a console message with more information, also giving the payment pointer the <link>
refers to.
It seems I need a server-side component for receipt validation, and I am currently unable to write one. So I'm afraid I cannot write an example script.