Web Monetization

Web Monetization allows websites to automatically receive payments from users, facilitated by the user agent and a user's preferred monetization provider.

This specification is a work in progress within the community on the best shape it should take. Please see the documentation for more info.

The specification reflects the desired end-state of the Web Monetization APIs as currently anticipated and agreed to between the contributors. The specification is being prepared here, in this format, to collect the input of the Web community and prepare the work to ultimately follow the W3C standards track should it have the necessary support to do so.

For the most accurate reflection of the APIs that have been implemented by providers see the API documentation.

Usage examples

Checking if Web Monetization is supported

Call {{DOMTokenList/supports()}} on a [^link^] element’s {{HTMLLinkElement/relList}} passing the `"monetization"` keyword to check if Web Monetization is supported by the user agent.

Monetizing a web page

Monetization events

The {{MonetizationEvent}} DOM events provide information such as the amount sent, the currency of the payment, and a link to the incoming payment at the [=monetization receiver=] which can be used to verify the receipt of payment. As in the previous example above, these events are dispatched to [^link^] elements and bubble up the DOM tree.

To listen for {{MonetizationEvent}} events, an [=event listener=] needs to be added to the relevant [^link^] element (or to one of its ancestors) via JavaScript:

Verifying a payment

The {{MonetizationEvent}}'s {{MonetizationEvent/incomingPayment}} attribute is a URL that can be used to verify the payment at the [=monetization receiver=].

In most cases requests to the {{MonetizationEvent/incomingPayment}} URL will need to be authenticated as they fetch sensitive details such as the `receivedAmount`. The specifics of this authentication are agreed by the website and the [=monetization receiver=] when setting up the receiving account.

Below is a hypothetical naive verification method that will make a request to the {{MonetizationEvent/incomingPayment}} URL and simply return the results. For simplicity it has no logic for authenticating the request.

A more sophisticated implementation SHOULD track the `receivedAmount` property and ensure it is increasing after each {{MonetizationEvent}} to verify that a new payment has been received.

Monetizing media

The following example shows how to monetize various types of media using different [=wallet addresses=].

Model

Monetization:
Payments made by a user to a website, facilitated through a [=monetization provider=].
Monetized:
A [^link^] element is monetized when it has the `monetization` keyword; its `href` then gives a [=wallet address=]. A [=document=] is monetized when it contains a monetized [^link^] element.
Monetization provider:
The party making payments on behalf of the user. A monetization provider leverages the [[[Interledger]]] suite of protocols and technologies (e.g., [[[open-payments]]] based on [[STREAM]]) to provide a high-level way to pay a [=monetization receiver=].
Monetization receiver:
The party receiving payments on behalf of the website, whose details are provided by a [=wallet address=].
Wallet address:
A [=URL=] to an Open Payments API entry-point (i.e., a JSON resource containing details that facilitate payment to an account).
Payment session
A session between a [=monetization provider=] and [=monetization receiver=] initiated by the [=user agent=] at the [=monetization receiver=]. One or more payments can be [=initiated=] by the [=monetization provider=] in a single session. A payment has an amount (a {{PaymentCurrencyAmount}}), an incoming payment [=URL=], and a [=wallet address=].
Initiated payment
A payment that the [=monetization provider=] has started towards the [=monetization receiver=] within a [=payment session=]. The underlying payment layers could complete a payment asynchronously, so an initiated payment is not a guarantee that the [=monetization receiver=] has received the amount.

Goals

  • Suitable for static HTML documents, without requiring backend infrastructure.
  • Doesn't require user interaction, but user retains control over which sites they monetize and how much they spend.
  • Developers have a way to associate payments with their users, in order to provide a range of experiences.
  • Users retain control of if, when, and how payments are made to the site. For example, micropayments of a predetermined monetary value could be "streamed" to the site over time. Alternatively, the user could make one or many discrete "one-off" payment(s) of any arbitrary monetary amount, even while micropayments are simultaneously being streamed.

Link type "monetization"

The `monetization` keyword indicates a [=wallet address=] used to monetize the document. It indicates that some aspect of the document is [=monetized=].

The `monetization` keyword MAY be used with [^link^] elements. This keyword creates an [=external resource link=]. This keyword is body-ok.

A user agent MUST NOT delay the load event for this link type.

A user agent MAY restrict the number of concurrent [=payment sessions=] it simultaneously supports.

The default type for resources given by the `monetization` keyword is `application/json`.

A [^link^] element with this link type has an associated payment session, a [=payment session=] or null. It is initially null.

The appropriate times to fetch and process this type of link are:

  • When the [=external resource link=] is created on a [^link^] element that is already [=browsing-context connected=].

  • When the [=external resource link=]'s [^link^] element becomes [=browsing-context connected=].

  • When the [^link/href^] attribute of the [^link^] element of an [=external resource link=] that is already [=browsing-context connected=] is changed.

  • When the [^link/disabled^] attribute of the [^link^] element of an [=external resource link=] that is already [=browsing-context connected=] is set, changed, or removed.

  • When the [^link/crossorigin^] attribute of the [^link^] element of an [=external resource link=] that is already [=browsing-context connected=] is set, changed, or removed.

  • When the [^link/type^] attribute of the [^link^] element of an [=external resource link=] that is already [=browsing-context connected=] is set or changed to a value that does not or no longer matches the Content-Type metadata of the previous obtained external resource, if any.

  • When the [^link/type^] attribute of the [^link^] element of an [=external resource link=] that is already [=browsing-context connected=], but was previously not obtained due to the [^link/type^] attribute specifying an unsupported type, is set, removed, or changed.

The fetch and process the linked resource algorithm for this type, given a [^link^] element |element|, is as follows:

  1. Stop |element|'s [=associated payment session=], if any, and set it to null.
  2. Run the default fetch and process the linked resource given |element|.

The linked resource fetch setup steps for this type of linked resource, given a [^link^] element |element:HTMLLinkElement| and [=request=] |request|, are:

  1. If |element|'s [^link/disabled^] attribute is set, return false.

  2. If |element|'s [=Node/node document|node document=] is not [=allowed to use=] the "monetization" feature, return false.

  3. Set |request|'s [=request/initiator=] to "`document`".

  4. Set |request|'s [=request/destination=] to "`monetization`".

  5. Set |request|'s [=request/mode=] to "`cors`".

  6. Set |request|'s [=request/credentials mode=] to the [=CORS settings attribute credentials mode=] for |element|'s [^link/crossorigin^] content attribute.

  7. Return true.

To process this type of linked resource given a [^link^] element |element|, boolean |success|, and [=response=] |response|:

  1. If, since the resource in question was fetched, it has become appropriate to fetch it again, return.

  2. If |element| no longer creates a `monetization` [=external resource link=], or is not [=browsing-context connected=], return.
  3. If |response|'s status is not an OK status, then set |success| to false.

  4. Otherwise, if |response|'s Content-Type metadata is not `application/json`, then set |success| to false.

  5. Let |json| be the result of [=parse JSON bytes to an Infra value=] passing |response|'s [=Response/body=].
  6. If |json| is an exception, then set |success| to false.
  7. If the user agent has exhausted the number of allowed [=payment sessions=], set |success| to false.

  8. If |success| is true, start a new [=payment session=] and set it as |element|'s [=associated payment session=].
  9. [=Queue an element task=] on the [=networking task source=] given |element| and the following steps:
    1. If |success| is true, [=fire an event=] named `"load"` at |element|.
    2. Otherwise, [=fire an event=] named `"error"` at |element|.

When a [^link^] element stops creating a "monetization" [=external resource link=], or stops being [=browsing-context connected=], a user agent MUST stop its [=associated payment session=], if any, and set it to null.

`disabled` attribute

This specification patches the [[HTML]] specification's [^link^] element's `disabled` attribute:

The `disabled` attribute is a boolean attribute that is used with the `stylesheet` or `monetization` link type. The attribute must only be specified on [^link^] elements that have a [^link/rel^] attribute that contains the `stylesheet` or `monetization` keyword.

Events

Extensions to `GlobalEventHandlers` interface

The {{GlobalEventHandlers}} interface is defined in [[HTML]].

          partial interface mixin GlobalEventHandlers {
            attribute EventHandler onmonetization;
          };
        
onmonetization

The attribute MUST be an [=event handler IDL attribute=] and [=event handler content attribute=] for the {{monetization}} event supported by all [=element=]s, {{Document}} objects, and {{Window}} objects. The user agent uses it to notify that a payment has been [=initiated=] for a [=monetized=] [^link^].

monetization event

When the [=payment session=] has [=initiated=] a |payment| with a non-zero amount, perform the following steps:

  1. Let |target:HTMLLinkElement| be the {{HTMLLinkElement}} associated with the [=payment session=].
  2. If |target| is `null`, then return.
  3. [=Queue a task=] on the [=monetization task source=] to perform the following steps:
    1. If |target| is not connected, return.
    2. Let |amountSent:MonetizationCurrencyAmount| be the result of [=create a monetization currency amount|creating a monetization currency amount=] given |payment|'s amount and |target|'s [=relevant realm=].
    3. [=Fire an event=] named `"monetization"` at |target| using {{MonetizationEvent}}, with its {{MonetizationEvent/amountSent}} attribute initialized to |amountSent|, its {{MonetizationEvent/incomingPayment}} attribute initialized to |payment|'s incoming payment URL, its {{MonetizationEvent/walletAddress}} attribute initialized to |payment|'s wallet address, the deprecated attributes likewise, and its {{Event/bubbles}} attribute initialized to true.

Task sources

The following [=task source=] is defined by this specification.

The monetization task source
Used by this specification to queue up non-blocking {{MonetizationEvent}}s.

`MonetizationCurrencyAmount` interface

The `MonetizationCurrencyAmount` interface maps directly to the {{PaymentCurrencyAmount}} dictionary.

          [SecureContext, Exposed=Window]
          interface MonetizationCurrencyAmount {
            readonly attribute DOMString currency;
            readonly attribute DOMString value;
          };
      

currency member

The currency of the MonetizationCurrencyAmount. The default is an ISO 4217 three-letter alphabetic code; see the definition of the `currency` member of {{PaymentCurrencyAmount}} in [[payment-request]] for details.

value member

The amount of the MonetizationAmount. See the definition of the `value` member of {{PaymentCurrencyAmount}} in [[payment-request]] for details.

Creating a `MonetizationCurrencyAmount`

To create a monetization currency amount, given a {{PaymentCurrencyAmount}} |paymentAmount| and a [=ECMAScript/realm=] |realm|, run the following steps:

  1. Let |amount| be a new {{MonetizationCurrencyAmount}} in |realm|.
  2. Set |amount|'s {{MonetizationCurrencyAmount/currency}} to |paymentAmount|["currency"].
  3. Set |amount|'s {{MonetizationCurrencyAmount/value}} to |paymentAmount|["value"].
  4. Return |amount|.

`MonetizationEvent` interface

        [SecureContext, Exposed=Window]
        interface MonetizationEvent : Event {
          constructor(DOMString type, MonetizationEventInit eventInitDict);
          readonly attribute MonetizationCurrencyAmount amountSent;
          readonly attribute USVString? incomingPayment;
          readonly attribute USVString walletAddress;

          // Following are deprecated
          readonly attribute DOMString? amount;
          readonly attribute DOMString? assetCode;
          readonly attribute octet? assetScale;
          readonly attribute DOMString? receipt;
          readonly attribute USVString paymentPointer;
        };

        dictionary MonetizationEventInit : EventInit {
          required PaymentCurrencyAmount amountSent;
          required USVString? incomingPayment;
          required USVString walletAddress;

          // Following are deprecated
          required DOMString? amount;
          required DOMString? assetCode;
          required octet? assetScale;
          required DOMString? receipt;
          required USVString paymentPointer;
        };
      

The [=event constructing steps=] for {{MonetizationEvent}}, given |event| and |eventInitDict|, are:

  1. Set |event|'s {{MonetizationEvent/amountSent}} to the result of [=create a monetization currency amount|creating a monetization currency amount=] given |eventInitDict|["amountSent"] and |event|'s [=relevant realm=].

The {{MonetizationEvent/amount}}, {{MonetizationEvent/assetCode}}, {{MonetizationEvent/assetScale}}, {{MonetizationEvent/paymentPointer}} and {{MonetizationEvent/receipt}} attributes are deprecated.

All [=monetization receivers=] should be migrating from generating a [[[Receipt]]] to supporting incoming payments via [[open-payments]] and will no longer be returning receipts to the browser.

As such the {{MonetizationEvent}} no longer represents an amount received; it represents an amount sent and returns a URL as the {{MonetizationEvent/incomingPayment}} attribute that can be used to determine the amount received.

amountSent attribute

The amount sent. When getting, returns the {{MonetizationCurrencyAmount}} it was initialized to.

incomingPayment attribute

A [=URL=] representing an incoming payment at the [=monetization receiver=]. When getting, returns the value it was initialized with.

walletAddress attribute

A [=URL=] representing the [=wallet address=] the payment was initiated for. When getting, returns the value it was initialized with.

amount attribute (deprecated)

The amount received as reflected in the receipt from the [=monetization receiver=]. When getting, returns the value it was initialized with.

assetCode attribute (deprecated)

The three letter asset code identifying the amount's units (e.g., "USD" for US dollars). When getting, returns the value it was initialized with.

assetScale attribute (deprecated)

The scale of the amount. For example, USD would have an `assetScale` of `2` when denominated in cents. When getting, returns the value it was initialized with.

receipt attribute (deprecated)

`null` or a base64-encoded [[[Receipt]]] issued by the [=monetization receiver=] to the [=monetization provider=] as proof of the total amount received in the [=payment session=]. When getting, returns the value it was initialized with.

paymentPointer attribute (deprecated)

A [=URL=] representing the [=wallet address=] the payment was initiated for. When getting, returns the value it was initialized with.

Permissions Policy integration

This specification defines a [=policy-controlled feature=] identified by the string "monetization". Its default allowlist is `'self'`.

Content Security Policy

monetization-src directive

The monetization-src directive restricts the URLs from which a [=wallet address=] is loaded. The syntax for the directive's name and value is described by the following ABNF:

          directive-name  = "monetization-src"
          directive-value = serialized-source-list
        

`monetization-src` Pre-request check

This directive's pre-request check is as follows:

Given a [=request=] (|request|) and a [=violation/policy=] (|policy|):

  1. Let |name| be the result of executing "Get the effective directive for request" on |request|.
  2. If the result of executing "Should fetch directive execute" on |name|, `monetization-src`, and |policy| is "No", return "Allowed".
  3. If the result of executing "Does request match source list?" on |request|, this directive's value, and |policy| is "Does Not Match", return "Blocked".
  4. Return "Allowed".

`monetization-src` Post-request check

This directive's post-request check is as follows:

Given a [=request=] (|request|) and a [=violation/policy=] (|policy|):

  1. Let |name| be the result of executing "Get the effective directive for request" on |request|.
  2. If the result of executing "Should fetch directive execute" on |name|, `monetization-src`, and |policy| is "No", return "Allowed".
  3. If the result of executing "Does response to request match source list?" on |response|, |request|, this directive's value, and |policy| is "Does Not Match", return "Blocked".
  4. Return "Allowed".

Get fetch directive fallback list

This spec patches the [[CSP]] specification's directive fallback list

Given a string |directiveName|:

  1. Switch on |directiveName|:
    ...
    `monetization-src`
    `<< "monetization-src", "default-src" >>`
  2. Return `<< >>`.

Get the effective directive for request

This spec patches the [[CSP]] specification's effective directive for request

Given a request (|request|):

  1. ...
  2. Switch on |request|'s destination:
    ...
    `"monetization"`
    1. Return `monetization-src`.
  3. Return `connect-src`.

Fetch destination type

This spec patches the [[FETCH]] specification's [=destination type=].

A destination type is one of: the empty string, "audio", "audioworklet", "document", "embed", "font", "frame", "iframe", "image", "json", "manifest", "monetization", "object", "paintworklet", "report", "script", "serviceworker", "sharedworker", "style", "track", "video", "webidentity", "worker", or "xslt".

Security considerations

It is RECOMMENDED that a user agent provide some UI or indicator that allows the user to know when [=monetization=] is possible and/or when [=monetization=] is occurring. Providing such a UI allows the users to retain control of the monetization process by taking action (e.g., stop or start monetization of a particular site if they wish to do so).

As [=wallet addresses=] are generally provided as a service, a XSS attack could inject malicious [=wallet addresses=] into a page that uses the same service. To mitigate such an attack, it is RECOMMENDED that developers:

  • host a [=wallet address=] on their own servers and proxy [[open-payments]] requests on the server as needed.
  • Set the `monetization-src` CSP directive to restrict requests to origins they control and trust to host [=wallet addresses=].

Privacy considerations

Web Monetization is designed to be privacy-preserving: the user agent only shares data with the [=monetization provider=] and the [=monetization receiver=] as they need it.

The [=monetization provider=] only receives what it needs to send a payment: the amount, and the [=wallet address=] to pay. The user agent does not send the URL of the document, or of any other page the user visits, to the [=monetization provider=].

The user agent does not send data about the user to the [=monetization receiver=]. To set up a [=payment session=], it fetches the [=wallet address=] instead.

Relation to Web Payments

Unlike [[[Payment-Request]]] and the [[[Payment-Handler]]], which only supports "one-off" payments, Web Monetization provides a [=payment session=] that supports both continuous payments and "one-off" payments.