Web Monetization Community

loading...
Cover image for Exploring integration of Web Monetization into the Web Platform — Grant Report #1
Exploring Web Monetization through Firefox

Exploring integration of Web Monetization into the Web Platform — Grant Report #1

Sid Vishnoi
Prototyping Web Monetization in Firefox (Gecko)
・7 min read

Project Update

The primary objectives for this milestone were to decide whether to use the <meta> or <link> tag and then implement the same in Gecko (Firefox's browser engine). I'm happy to inform you that both of these goals have been successfully accomplished!

Spoiler alert: using <link> is my recommended way forward for the Web Monetization community. More details below.

Progress on objectives

The objectives under the current milestone were:

  1. Study relevant specifications and Gecko infrastructure.
  2. Discuss and decide whether to use the <meta> or <link> element.
  3. Integrate the said element's behavior in Gecko.

<link> is the way forward

Following a discussion outlining various pros and cons of each tag, and a deep dive into various specifications and Gecko infrastructure, we decided to go with the <link> tag. This means the browser should support:

<link rel="monetization" href="URL" />`
Enter fullscreen mode Exit fullscreen mode

Instead of:

<meta name="monetization" content="$paymentPointer" />
Enter fullscreen mode Exit fullscreen mode

This is a breaking change to the specification, and, because of the impact of the change, a difficult decision for the WM community to adopt. We would essentially be abandoning "payment pointers" — which are well-known in the Web Monetization community — with something that better aligns with the web platform: using regular URLs. I won't get into the technical details here, but you can read the summary of my research in the GitHub issue.

Bringing it to the browser

Once the WM community reached consensus to to go with the <link>, I proceeded to implement this declarative API in a fork of Firefox at GitHub. Note that the present implementation only handles the fetching and processing of the monetization endpoint (payment pointer), and not the actual monetization.

You can download the current implementation from GitHub. At the time of writing, it supports:

  • Getting monetization details from the first valid <link> element at any time. That is, if you add or remove or modify the link elements, the monetization info is updated. This way, dynamic monetization tags support revenue sharing and single-page applications (SPA) use cases.
  • Monetizing only the currently visible tab in the browser (no background tabs).
  • Fetching the payment info with proper HTTP headers, while respecting CORS policy and cache-control behavior, as defined by the SPSP protocol.
  • To preserve user's privacy, no referrer information (i.e., the URL of current website) or cookies are sent to the monetization receiver (e.g. Uphold).
  • Allowing only legitimate payment pointers through the use of a Content Security Policy (CSP). By using the monetization-src <source>; CSP directive, we can enforce monetizing only certain payment pointers so that malicious actors cannot steal your money.
  • Logging error messages and other information to the browser console.

A more up-to-date implementation status can be read in the project's wiki.

The implementation presently does not support monetization of embedded content like iframes. That needs more discussion from the security and performance perspective, and also requires specification of various edge cases. Nevertheless, those cases have been captured in a GitHub issue.

Key activities

Note: This section contains some technical details and my journey.

Initial research

I started with going through with various specifications, specifically HTML, DOM, Fetch, InterLedger Protocol, Payment Pointers, Web Monetization, W3C Tag Design Principles, RFC8288 (Web Linking) and RFC2718 (Guidelines for new URL Schemes), to get a better understanding of the platform as a whole.

After familiarizing myself with the specs, I went through Firefox code-base and documentation to analyze how the existing Gecko infrastructure can be used to support <meta> or <link> monetization tags.

After studying for a few weeks and various discussions with Marcos Cáceres, I started to summarize my notes into a write-up that can be used by the Web Monetization community to settle the debate whether we should move forward with <meta> or <link> tag.

As of today, we've settled on using the <link> tag.

Set up development environment

Now as we can't just implement a specification that is not presently on standards track into a browser, I created my own fork of Firefox on GitHub. This allowed me to prototype quickly, without the hassle of integrating a particular feature flag for Web Monetization (generally, something that can be time consuming to add).

Aside: One thing I found interesting is that GitHub doesn't let you push a large repository (4GB in this case) in one go. I had to write a script to split the repository into smaller batches of commits and push them instead (that took a while).

I'll write more on temporarily maintaining a fork of a project as large as Firefox, and my Firefox development workflow some other day on my website.

Let the coding begin!

The easiest part was to support the HTMLLinkElement.relList.supports() API. I just had to add a new string literal for rel="monetization". This can be easily used to detect whether a browser supports Web Monetization. Feels good to see some quick progress - git commit!

During the earlier prototyping, I decided to implement the <link rel=monetization> support entirely in C++, as it would've been more performant and would easily allow low level communication with the WM agent. But after getting stuck at various times to reach a half working implementation, I asked some Mozilla engineers and Emilio advised me to try prototyping in JSM (a Mozilla dialect of JavaScript modules that can talk directly to privileged browser code). Let's say that turned out to be a much more delightful experience than fighting with the linker in C++! Funnily, 2 lines of JS had the same effect as 300 lines of C++ (this is not a language comparison, but related to Gecko's architecture).

The JSM approach required a change in thinking — from low level hyper-optimized stuff to high level design. Though, it felt weird to not have any type-checking/hinting support in the editor — I had to jump into WebIDL definitions to understand what JSM can do. Fast forward a few days, I had a working implementation of what's mentioned above (except CSP, which required a lot more fiddling across 18 files).

Creating a Nightly release

Satisfied with the current implementation, I created a Firefox Nightly release for you to try! You can find the download links in the wiki.

After extracting the downloaded archives, you need to run it from command line as:

./firefox --jsconsole
Enter fullscreen mode Exit fullscreen mode

The --jsconsole flag opens Firefox with a "multi process browser console" window, which will display various Web Monetization metadata, logs and error messages.

Remaining activities

Next, I'll work towards bringing the actual Web Monetization support in Firefox. For this, we'll first need to specify the role of WM agent (browser extension) and the communication between the WM agent, browser, and the website. Once that's done, we'll hopefully have a working native implementation of Web Monetization. While we discuss and decide above, we'll try to formalize the specification based on the things we've learned so far.

We're already discussing the role of WM agent over GitHub. Feel free to join!

What community support would benefit your project?

I'm curious to understand how we should go with the monetization of iframes and other embedded content like images and videos. Say, you're the page owner, how do you think we should monetize third party content embedded in your site? Conversely, how would you like your content to be monetized if it's embedded in some other website? One idea that comes to mind is to only allow the visible content to be monetized as the user scrolls through the site, but it adds quite a lot of complexity to the browser and has many edge cases. Is this something you would love to see in the first version of the Web Monetization standard, or it can be deferred for later? Let us know what you think in comments below or at GitHub.

Additional comments

Thanks to the Grant for the Web for supporting my workstation purchase. I can't emphasize enough what a difference this has made to my development flow: I'm able to compile Gecko in record time - nearly 7 minutes, compared to 80 minutes on my previous laptop. This enabled me to quickly prototype various implementation strategies without wasting hours waiting for Gecko to compile!

Relevant links/resources

  • Implementation of Web Monetization in Mozilla Firefox:

Discussion (3)

Collapse
adrianhopebailie profile image
Adrian Hope-Bailie

@sid

This is fantastic progress, well done!

I think the decision to move to the <link> tag is a good one. One challenge we'll need to explore is what we do with link relations in HTTP headers, have you given that any thought? It's not something we can support from the extension because extensions don't have access to the response headers as far as I know.

On the topic of Payment Pointers, I wouldn't say we're abandoning them but rather that if we use the <link> tag then we'd need to use the full URL form of the Payment Pointer as opposed to the shortened form which is primarily for user transcription and readability.

As an aside, a Payment Pointer is just a URL, but it is a URL that we expect to have very specific behaviours when dereferenced. In this case the resource it is locating is an account that we can send money to via Interledger. We're doing a lot of work in the Open Payments specification to expand on the use cases for Payment Pointers and Interledger beyond just Web Monetization (think of a Payment Pointer as a Web-native credit card number but with super-powers and better security).

Finally, how do we get some more smart people like yourself to repeat this awesome work on some other browser engines?

@chrislarry and @erikad how can we get more Technical Scholars into the Grant for the Web Program to do this work?

Collapse
sid profile image
Sid Vishnoi Author • Edited

Thanks Adrian!

One challenge we'll need to explore is what we do with link relations in HTTP headers, have you given that any thought?

With independent non-HTML documents like PDF, images etc., I think it should be fairly straightforward - it's similar to web pages. If we were to use Link header along with <link> elements, it gets a bit more interesting as we need to use either of them. HTTP headers come before response body, so it might make sense to use Link even when a <link> is present.

When such content is embedded into a web page, we run into same problems as with iframes. From implementation perspective, it's easier to run as many payment streams as their are embedded content, but this can be very bad performance wise. If we were to monetize only "visible" or "active" content, it gets difficult to implement with all the edge cases (what if someone adds 100 1px images in a row etc.). Also, with the overhead of setting up payment, user might scroll away from the content before we even set up the payment.

[on payment pointers]

I mean we'll have to use WHATWG URLs, but I get your point. I'll update the report to make it clearer.

We're doing a lot of work in the Open Payments specification to expand on the use cases for Payment Pointers and Interledger beyond just Web Monetization (think of a Payment Pointer as a Web-native credit card number but with super-powers and better security).

This sounds exciting! I feel like we should again look into the pay:// URL scheme 😄

Collapse
erikad profile image
Erika

@adrianhopebailie We are very enthusiastic about expanding the Technical Scholars program to additional browsers teams. We're drafting info for potential host organizations that will be shared soon. In the meantime, interested team leads are welcome to reach out to @chrislarry and myself directly.