DEV Community

Andrew
Andrew

Posted on

[Web Monetization] Share Useful Information & Earn Real Money From It!

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

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

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

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

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 logo oahehc / you-might-want

share something other people might want to know and earn money from those information.

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.

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,
    },
  ];
}
Enter fullscreen mode Exit fullscreen mode

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

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;
  };
}
Enter fullscreen mode Exit fullscreen mode

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.

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;
}
Enter fullscreen mode Exit fullscreen mode
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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
  1. 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

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

Top comments (0)