[Web Monetization] Share Useful Information & Earn Real Money From It！
Tags: gftwhackathon
Published: 2020-05-29 12:51:55

## What I built

### Submission Category: Creative Catalyst

The problem we want to solve through this project is that some people might have useful information. But the information is not enough to create a full article or a YouTube video. And most people are not the influencers who have tons of people follow them on Twitter or Facebook. But they might not want to give that information for free. This application applies Web Monetization to solve those kinds of problems.
Everyone can create an account and start sharing their information right away. And the application will base on the number of votes of each post to calculate the probabilistic revenue sharing (the detail about the algorithm will be introduced at the `Link to Code` section).  
All in all, this application is like a Twitter account shared by all people around the world. So everyone can publish useful information here. Moreover, if the post received enough votes, the author can earn the money for it.

## Demo

Link: https://you-might-want.oahehc.now.sh/

There're three types of users on our application.

### 1. Author

Anyone can register through google account and provide their wallet. Then the users can start sharing their information on our application.  
Once the post reaches enough votes, the author will receive the profit share on their wallet.  
![wallet](https://i.imgur.com/Vl6Mp4h.png)

The post is limited by 500 characters because we wish the author can provide the information succinctly. It will allow our readers to consume as much information.  
![post-limit](https://i.imgur.com/zHuqypy.png)

### 2. Normal Reader

Everyone can start reading posts without registration.

### 3. Paid Reader

The paid reader is someone who have joined web monetization and register through Google account.
![join-web-monetization](https://i.imgur.com/hh3wGBG.png)

The paid reader will be able to rate the posts (thumb-up and thumb-down). Because the most important factor that which post should get more profit sharing is coming from the votes. Therefore, it's only the paid reader who can join the rating to decide which article is worthy to receive the money they have paid. And this will also make the rating result more trustable.  
![thumb-up](https://i.imgur.com/xK4jEwD.gif)

And we are planning to provide more advanced features for the paid reader including remove ads, collect posts, and search posts, etc.

## Link to Code

Here is the full repo for reference.  
{% github oahehc/you-might-want no-readme %}

In the below section, I will point out the parts relative to `web monetization`.

### React Hook for web monetization

We create a custom React hook to handle all the events about `web monetization`.

```Typescript
import { useState, useEffect } from 'react';

type MonetizationInfo = {
  state: MonetizationState | undefined;
  isApplied: boolean;
  isStarted: boolean;
  isPending: boolean;
  isStopped: boolean;
  detail: MonetizationEventDetail | undefined;
};

export default function useMonetization(): [MonetizationInfo] {
  const [state, setState] = useState<MonetizationState>();
  const [detail, setDetail] = useState<MonetizationEventDetail>();

  function pendingEventHandler(event: MonetizationEvent) {
    setState('pending');
    setDetail(event.detail);
  }
  function stoppedEventHandler(event: MonetizationEvent) {
    setState('stopped');
    setDetail(event.detail);
  }
  function startedEventHandler(event: MonetizationEvent) {
    setState('started');
    setDetail(event.detail);
  }
  function onprogressEventHandler(event: MonetizationEvent) {
    setDetail(event.detail);
  }

  useEffect(() => {
    if (document !== undefined && document.monetization !== undefined) {
      const defaultState = document.monetization.state;
      setState(defaultState);

      document.monetization.addEventListener('monetizationstart', startedEventHandler);
      document.monetization.addEventListener('monetizationpending', pendingEventHandler);
      document.monetization.addEventListener('monetizationstop', stoppedEventHandler);
      document.monetization.addEventListener('monetizationprogress', onprogressEventHandler);
    }

    return () => {
      if (document !== undefined && document.monetization !== undefined) {
        document.monetization.removeEventListener('monetizationstart', startedEventHandler);
        document.monetization.removeEventListener('monetizationpending', pendingEventHandler);
        document.monetization.removeEventListener('monetizationstop', stoppedEventHandler);
        document.monetization.removeEventListener('monetizationprogress', onprogressEventHandler);
      }
    };
  }, []);

  return [
    {
      state,
      isApplied: typeof state !== 'undefined',
      isStarted: state === 'started',
      isPending: state === 'pending',
      isStopped: state === 'stopped',
      detail,
    },
  ];
}
```

And we apply Typescript to make it easier to maintain and prevent error-prone.

```Typescript
type MonetizationState = 'stopped' | 'pending' | 'started';
type MonetizationEventDetail = {
  /** Your payment account URL. The same value is used as the content in your <meta> tag. */
  paymentPointer: string;
  /** This value is identical to the session ID/monetization ID (UUID v4) generated by the user agent */
  requestId: string;
  /** When true, the monetization tag has been removed or the paymentPointer changed. No more events with this requestId expected. */
  finalized?: boolean;
  /** The destination amount received as specified in the Interledger protocol (ILP) packet. */
  amount?: string;
  /** The code (typically three characters) identifying the amount's unit. A unit, for example, could be a currency (USD, XRP). */
  assetCode?: string;
  /** The number of places past the decimal for the amount. For example, if you have USD with an asset scale of two, then the minimum divisible unit is cents. */
  assetScale?: number;
};
type MonetizationEvent = { detail: MonetizationEventDetail };
interface Document {
  monetization: {
    state: MonetizationState;
    addEventListener: (
      type: 'monetizationstart' | 'monetizationpending' | 'monetizationstop' | 'monetizationprogress',
      cb: (event: MonetizationEvent) => void
    ) => void;
    removeEventListener: (
      type: 'monetizationstart' | 'monetizationpending' | 'monetizationstop' | 'monetizationprogress',
      cb: (event: MonetizationEvent) => void
    ) => void;
  };
}
```

### Algorithm for revenue sharing

Another part about `web monetization` is how we calculate the revenue sharing. Here is our current algorithm. Basically, it's calculated base on the time diff (now - created time) and votes diff (#thumb-ups - #thumb-downs).  
The idea about this algorithm is trying to give a larger portion of profit to the latest or more popular posts.

```Typescript
function getPostPoint({
  created,
  upVotes,
  downVotes,
}: {
  created: string;
  upVotes: string[];
  downVotes: string[];
}): number {
  const votesDiff = upVotes.length - downVotes.length;
  if (votesDiff <= 0) return 0;

  const timeDiff = Date.now() - new Date(created).getTime();
  return (100000000 / timeDiff) ** 1.2 * votesDiff ** 1.2;
}
```

| Time \ Vote Diff |    10 |    100 |   1,000 |
| ---------------- | ----: | -----: | ------: |
| 5 mins           | 1,688 | 26,758 | 424,087 |
| 1 hours          |    86 |  1,357 |  21,500 |
| 1 day            |     2 |     30 |     474 |
| 1 week           |     0 |      3 |      46 |
| 1 month          |     0 |      1 |       8 |

## How I built it

### Stack

React.js, Typescript, Next.js, Vercel(Zeit) Now, AWS DynamoDB, Google OAuth.

### Issues

During the time we were working on this project, we notice that if we want to apply the sharing profit mechanism, the current policy about `web monetization` still has some problems that need to figure out some better alternative.

1. Currently, the user paid $5 per month, and the website will receives $0.0001/s. But once the user exceeds $4.50 in a month, the rate that the website receive will drop to $0.000000186/s. This means that only the user visits your website at the first 12.5 hours every month, then you will receive $0.0001/s. Otherwise, the rate will be $0.000000186/s which has a huge gap.

```
once a user exceeds $4.50 in a month they're dropped to a lower rate allowing
them to still access WM content (although this is not a permanent solution).
The lower rate is such that the user can use WM for the rest of the month
without exceeding $5. You'll mostly encounter users at the $0.0001/s rate
but a few will be sending $0.000000186/s
```

The rate is obviously not enough to attract users to share their information. If our website has 1,000 active paid users which will visit the website 1 hour per day. And we assume that we can get 10% from their first 12.5 hours (the period with $0.0001/s rate). Then the total income per month will be around $470. The amount of total income will not be enough to cover the website's operating fee. So we still have to seek for other monetization (eg. ads).

```
         1.25 hours * $0.0001/s      * 1000
+ (30 - 1.25) hours * $0.000000186/s * 1000
= 450 + 19.251
```

2. Another problem is the current revenue-sharing solution won't guarantee the author will receive the money based on the proportion. The current solution for revenue sharing is to generate different monetization meta tag for each pageview. But the revenue is based on how much time the user spent on our website. Even we can generate the monetization meta tag based on the proportion we want. The active time for each pageview is not under our control which will cause the final amount that each author received might have a large gap compared to the proportion we calculated.

[probabilistic-rev-sharing](https://webmonetization.org/docs/probabilistic-rev-sharing)

## Conclusion

`Web monetization` is an interesting idea. I'm happy to have the chance to join this Hackathon and play around with this technique. It was fun and I got lots of experience from the process.  
Special thanks to @sharafian and @cyberdees who answer our questions on the channel.  
If you have any suggestions about this application. Please feel free to leave your comment or send a message to me. Thanks for reading.

## Additional Resources/Info

- [Web Monetization](https://webmonetization.org/)
- [Announcing the Grant For The Web Hackathon on DEV](https://dev.to/devteam/announcing-the-grant-for-the-web-hackathon-on-dev-3kd1?utm_source=Newsletter+Subscribers&utm_campaign=82fd886961-EMAIL_CAMPAIGN_2020_05_05_10_14&utm_medium=email&utm_term=0_d8f11d5d1e-82fd886961-155126349)
- [Coil Extension](https://help.coil.com/using-coil/coil-extension)
- [Coil Membership Account](https://help.coil.com/accounts/membership-accounts)
- [Test Web Monetization](https://testwebmonetization.com/)