How to use Gumroad to receive payments for a Chrome Extension

I created a Chrome Extension and decided to charge for it using Gumroad. I saw that Gumroad allows you to use and verify license Keys and while the documentation is pretty clear I couldn’t find anything written specifically for Chrome Extensions.

The top level overview is

  1. Set the correct permissions in the manifest file

  2. When the user clicks on the extension for the first time it will ask for the license Key.

  3. The user gets the license key from gumroad

  4. The user has to enter the license key in the extension

  5. We verify the license key and store it using the Chrome Storage API so that we don’t have to ask every time

  6. (Optional) Check if the user if the subscription was canceled or refunded.

chrome extension gumroad verify

In this example we are going to use a Chrome extension that uses a browser action. In my popup html I have one container that shows when the license key hasn’t been entered (unactivatedContainer). This view asks for the license key. The other view (activatedContainer) is the working view if the license key works.

I have both views set to display none and using the popup javascript file I decide which one is set to display.

Set the correct permissions in the manifest.json file.

The important parts here is the permissions for storage (to store the license key), and permissions for the gumroad API. In my extension I also use the activeTab permissions to execute the script if the license key is correct.

{
  "manifest_version": 2,
  "name": "",
  "version": "",
  "description": "",
  "offline_enabled": false,
  "author": "",
  "permissions": ["storage", "*://api.gumroad.com/*", "activeTab"],
  "icons": {"","" },
  "browser_action": {
    "default": "16.png",
    "default_popup": "popup.html"
  }
}

Check if the license key has been entered already

The popup.html file links to the popup.js. In the popup.js file I check if we have the license key stored already using the chrome.storage API.

If it is stored then I use the fetch api to verify if the key is correct by querying Gumroad’s verification API.

If no key is stored then I show the view when the license key hasn’t been entered.

We also check that the purchase has not been refunded or chargebacked. I don’t have a subscription model for my extension but if you did you can check that the subscription_cancelled_at and subscription_failed_at fields too.

If everything is successfull I show the view when the license key verification works. If something fails I show the view that they have to enter their license key.

Please see the example code.

chrome.storage.sync.get("key", function (res) {
  if (typeof res.key === "undefined") {
    unActivatedContainer.style.display = "block";
  } else {
    fetch("https://api.gumroad.com/v2/licenses/verify", {
      method: "POST",
      headers: {
        Accept: "application/json",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        product_permalink: "[Enter your product permalink]",
        license_key: res.key,
        increment_uses_count: false,
      }),
    })
      .then((res) => res.json())
      .then(function (data) {
        if (
          data.success &&
          data.purchase.refunded === false &&
          data.purchase.chargebacked === false
        ) {
          activatedContainer.style.display = "block";
          getInfo(); //Execute your extension logic
        } else {
          unActivatedContainer.style.display = "block";
        }
      })
      .catch(function (err) {
        unActivatedContainer.style.display = "block";
      });
  }
});

Get the license key entered by the user

If there is no key stored yet, then the user has to enter the license key. I used an event listener to see if the user entered the license key.

Once again, using fetch and the gumroad api I verify the license key. If it works then store the license key using chrome.storage.sync.set({ key: data.purchase.license_key });.

Now going forward the the extension checks if the key is stored (the previous step) instead of always asking the user to enter the license key. Finally show them the correct view.

If the key is wrong then simply show them the view that they have to enter the license key.

button.addEventListener("click", function () {
  
    fetch("https://api.gumroad.com/v2/licenses/verify", {
      method: "POST",
      headers: {
        Accept: "application/json",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        product_permalink: "[Enter your product permalink]",
        license_key: license_key,
        increment_uses_count: false,
      }),
    })
      .then((res) => res.json())

      .then(function (data) {
        if (
          data.success &&
          data.purchase.refunded === false &&
          data.purchase.chargebacked === false
        ) {
          chrome.storage.sync.set({ key: data.purchase.license_key });
          unActivatedContainer.style.display = "none";
          activatedContainer.style.display = "block";
          getInfo(); //Execute your extension logic
        } else {
          unActivatedContainer.style.display = "block";
          errorMessage.style.display = "block";
        }
      })
      .catch(function (err) {
        errorMessage.style.display = "block";
      });
  
});

Summary

To summarize, when the user clicks on your extension we first check if the license key is already set, if it is then we use that key and continue executing the extension logic. If it is not set (or it fails verification from the gumroad api) then we show a view telling the user to enter a correct key.