monetizer: A JS library that manages the monetization meta tag (for Web Monetization API)
Tags: gftwhackathon, webmonetization, showdev, react
Published: 2020-06-03 11:07:39

---
title: 'monetizer: A JS library that manages the monetization meta tag (for Web Monetization API)'
published: true
description: My submission to the Grant For The Web x DEV Hackathon!
tags: gftwhackathon, webmonetization, showdev, react
---

## What I built

A JavaScript library that manages the `<meta name="monetization">` tags. It is designed to be used in single-page JavaScript apps that needs to dynamically monetize different creators.

Design goals:

- Build a simple API to integrate with any frontend library or framework (with React hooks integration as the main use case).
- No dependencies.
- Support single page apps with dynamically-changing payment pointer.
- Support [probabilistic revenue sharing](https://webmonetization.org/docs/probabilistic-rev-sharing).
- Has TypeScript type definitions bundled.

The main use case is to allow Single-Page Apps to monetize creators dynamically based on the content displayed. For example, an article website may want to monetize the article’s author when a user is reading their articles, while falling back to monetizing the website owner on other pages. This library allows such use cases to be implemented _declaratively_.

![](https://dev-to-uploads.s3.amazonaws.com/i/gqtdr7uarndrsagkzp7l.png)

### Submission Category:

Foundational Technology

## Demo

### Vanilla JS usage

```jsx
// Starts monetizing
const stopMonetizing = monetize('$dt.in.th')

// Stops monetizing
stopMonetizing()
```

Under the hood, when you call **`monetize`**, it adds a new monetization candidate to an internal candidate pool. When the candidate pool is changed, the library picks a winning candidate and adds/updates/removes the `meta` tag accordingly.

![](https://dev-to-uploads.s3.amazonaws.com/i/6291aa0lgrvtf55z95pq.png)

Likewise, when you call **`stopMonetizing`**, the previously added candidate is removed from the pool, which results in the `meta` tag being removed (if it is the only candidate).

![](https://dev-to-uploads.s3.amazonaws.com/i/0lv5n49stenz8oytqtia.png)

This concept of a “candidate pool” will come in useful when we want to do probabilistic revenue sharing or

### React usage

The API has been designed specifically so that it snaps neatly into a `useEffect` call.

```jsx
function App() {
  // Start monetization on mount, stop on unmount.
  useEffect(() => monetize('$dt.in.th'), [])
  return (
    <Layout>
      <Main />
    </Layout>
  )
}
```

### Vue usage

```js
export default {
  mounted() {
    this.stopMonetization = monetize('$dt.in.th')
  },
  beforeDestroy() {
    if (this.stopMonetization) {
      this.stopMonetization()
    }
  },
}
```

### Probabilistic revenue sharing

If multiple monetization calls are active, it uses probabilistic revenue sharing to divide the revenue.

```jsx
// 50% chance
monetize('$dt.in.th')

// 50% chance
monetize('$twitter.xrptipbot.com/bemusegame')
```

![](https://dev-to-uploads.s3.amazonaws.com/i/d008k9m3ya1k3ipztelz.png)

You can specify a weight (default weight is 1).

```jsx
// 33% chance
monetize({ content: '$dt.in.th', weight: 1 })

// 67% chance
monetize({ content: '$twitter.xrptipbot.com/bemusegame', weight: 2 })
```

![](https://dev-to-uploads.s3.amazonaws.com/i/4j9p37f9j9jbcti4r6b3.png)

### Prioritization

You can also specify the priority. Higher priority wins.

![](https://dev-to-uploads.s3.amazonaws.com/i/hb9rqz13qdsh9jhbrzoe.png)

This essentially lets you implement the main use case aforementioned in the beginning.

```jsx
function App() {
  // Fallback monetization candidate with a default priority of 0
  useEffect(() => monetize('$dt.in.th'), [])
  return (
    <Layout>
      <Main />
    </Layout>
  )
}

function Article(props) {
  const paymentPointer = props.author.paymentPointer

  // Send micropayment to article’s author while viewing author’s article
  // A priority of 1 takes precedence over a priority of 0.
  useEffect(() => monetize({ content: paymentPointer, priority: 1 }), [])

  return ...
}
```

![](https://dev-to-uploads.s3.amazonaws.com/i/q3xtnsznm6hydbeticae.png)

Priority ties are probabilistic-revenue-shared.

```jsx
function Article(props) {
  const paymentPointer = props.author.paymentPointer

  // 50-50 revenue sharing between article author and site developer
  useEffect(() => monetize({ content: '$dt.in.th', priority: 1 }), [])
  useEffect(() => monetize({ content: paymentPointer, priority: 1 }), [])
}
```

![](https://dev-to-uploads.s3.amazonaws.com/i/ztaw00mnfu0lt2mjhorl.png)

This library is being used in [an open-source web-based rhythm game I develop, Bemuse](https://bemuse.ninja/). If you look in the page’s source code you will not see the monetization meta tag, but it is later added in via JavaScript.

## Link to Code

{% github dtinth/monetizer %}

## How I built it

I originally built the `monetizer` package for use with the [open-source web-based rhythm game Bemuse](https://bemuse.ninja). So, I originally implemented this package [right into the Bemuse monorepo](https://github.com/bemusic/bemuse/tree/5af5512164561df8a4cc03796b409793a4f564a4/packages/monetizer). This is beneficial because:

- My initial goal was to ship the `monetization` meta tag to production as quickly as possible, while at the same time, _also_ ending up with an npm package that can be reused in other projects.
- I don’t have to set up a new build pipeline, and the package can benefit from using existing CI/CD pipeline and linter setup.
- If the game needs extra features from the library, it can be updated without requiring version bumps across multiple repositories.

{% github https://github.com/bemusic/bemuse/pull/671 %}

With that, I [released a new version of the game](https://github.com/bemusic/bemuse/blob/master/CHANGELOG.md#v483-2020-05-08). With the library integrated into the game and shipped into production, the original goal has been accomplished. I can now shift my focus to just this library and think about its future.

The `monetizer` package is very generic, and has a potential to be evolve independently of the game, unlike [other packages](https://github.com/bemusic/bemuse/tree/5af5512164561df8a4cc03796b409793a4f564a4/packages) in this monorepo which are more likely to evolve alongside the game. Having realized this, I decided to extract the library into its own standalone repository.

I used [TSDX](https://github.com/jaredpalmer/tsdx) to bootstrap a new TypeScript package. Since this library has no dependencies and also follows standard TypeScript project structure from the beginning, extracting it into a standalone repository turns out to be straightforward. TSDX also generate a GitHub Actions workflow file, so the library has testing right out of the box.

## Additional Resources/Info

- [npm package](https://www.npmjs.com/package/monetizer)