- Notifications
You must be signed in to change notification settings - Fork76
The JavaScript library for ExtensionPay.com — payments for your browser extensions, no server needed.
License
Glench/ExtPay
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
The JavaScript library forExtensionPay.com, a service to easily add payments to browser extensions. So far ExtensionPay has earned extension creatorsover $500k and counting!
// Example code// your-extension/background.jsconstextpay=ExtPay('your-extension-id');extpay.startBackground();extpay.getUser().then(user=>{if(user.paid){// ...}else{extpay.openPaymentPage()}})
Below are directions for using this library in your browser extension. If you learn better by example, you can also view the code for asample extension. This library usesMozilla's webextension-polyfill library internally for compatability across browsers which means it should work on almost all modern browsers.
"It hasn't even been 1 year yet and I'm already going topass $4,000 in annual subscriptions on an extension that I never in a million years thought I would be able to make a penny from. Thanks so much for creating this tool! I would not have even tried to monetize if I had to use Stripe directly, and you made it so easy.It took less than an hour to set it up and test it. Definitely have plans to create more extensions now that I know howeasy it is to monetize them." - David, Neobuyer extension
- Install
- Configure your
manifest.json
- Add
ExtPay
tobackground.js
(required!) - Use
extpay.getUser()
to check a user's paid status - Use
extpay.openPaymentPage()
to let the user pay - Use
extpay.getPlans()
to list available payment plans - Use
extpay.onPaid.addListener()
to run code when the user pays - Use
extpay.openPaymentPage()
to let the user manage their subscription - Use
extpay.openTrialPage()
to let the user sign up for a free trial - Use
extpay.openLoginPage()
to let the user log in if they've paid already
Note: ExtPay.js doesn't contain malware or track your users in any way. This library only communicates with ExtensionPay.com servers to manage users' paid status.
If you like this library, please star it! ⭐️ It helps us out :)
npm install extpay --save
If you're not using a bundler, you can copy thedist/ExtPay.js file into your project (orExtPay.module.js for ESM /ExtPay.common.js for Common JS).
ExtPay needs the following configuration in yourmanifest.json
(for both manifest v2 and v3):
{"permissions": ["storage" ]}
ExtPay will not show a scary permission warning when users try to install your extension.
Note: For Firefox, you may have to include"https://extensionpay.com/*"
in your extension manifest's "permission" for ExtPay to work properly.
If you have a"content_security_policy"
in your manifest or get aRefused to connect to 'https://extensionpay.com...'
error, you'll have to addconnect-src https://extensionpay.com
to your extension's content security policy.See Mozilla's documentation for more details.
You need to putExtPay
in your background file, often named something likebackground.js
. If you don't includeExtPay
in your background file it won't work correctly. If you're using a bundler you canimport 'ExtPay'
orrequire('ExtPay')
right in yourbackground.js
.
With either Manifest V3 or Manifest V2 you'll need tosign up and register an extension. When you register an extension you'll create an extension id that you'll use when initializingExtPay
. We'll usesample-extension
as the extension id in the following examples.
{"background": {"service_worker":"background.js" }}
// background.jsimportScripts('ExtPay.js')// or `import` / `require` if using a bundlervarextpay=ExtPay('sample-extension');// Careful! See note belowextpay.startBackground();
Note about service workers: In the example aboveextpay
will become undefined when accessed in service worker callbacks. To useextpay
in service worker callbacks, redeclare it like so:
chrome.storage.local.get('foo',function(){varextpay=ExtPay('sample-extension');// ...})
Make sure not to useextpay.startBackground()
in callbacks — it should only be called once.
If you're not using a bundler, addExtPay.js
tomanifest.json
:
{"background": {"scripts": ["ExtPay.js","background.js"] }}
// background.jsconstextpay=ExtPay('sample-extension')extpay.startBackground();
This method makes a network call to get the extension user's paid status and returns auser
object.
extpay.getUser().then(user=>{if(user.paid){// ...}else{// ...}})
or useawait
:
asyncfunctionfoo(){constuser=awaitextpay.getUser();if(user.paid){// ...}}
It is possible forextpay.getUser()
to throw an error in case of a network failure. Please consider this possibility in your code e.g.extpay.getUser().then(/* ... */).catch(/* handle error */)
Theuser
object returned fromextpay.getUser()
has the following properties:
property | description |
---|---|
user.paid | true orfalse .user.paid is meant to be a simple way to tell if the user should have paid features activated. For subscription payments,paid is only true ifsubscriptionStatus isactive . |
user.paidAt | Date() object that the user first paid ornull . |
user.email | The user's email if there is one ornull . |
user.installedAt | Date() object the user installed the extension. |
user.trialStartedAt | null orDate() object the user confirmed their free trial. |
user.plan | null or theplan the user is on. For example:{unitAmountCents: 1000, currency: 'usd', nickname: null, intervalCount: 1, interval: 'month'} . Unpaid users never have a plan. Seeextpay.getPlans() elsewhere in this README for more detail. |
subscription only | |
user.subscriptionStatus | One ofactive ,past_due , orcanceled .active means the user's subscription is paid-for.past_due means the user's most recent subscription payment has failed (expired card, insufficient funds, etc).canceled means that the user has canceled their subscription and the end of their last paid period has passed.You can read more about how subscriptions work here. |
user.subscriptionCancelAt | null orDate() object that the user's subscription is set to cancel or did cancel at. |
Opens a new browser tab where the user can pay to upgrade their status.
extpay.openPaymentPage([planNickname])
The payment page looks like this:
The plan buttons take you to a Stripe Checkout page:
Note:extpay.openPaymentPage()
can fail to open the tab if there is a network error. Please consider this possibility in your code.
You can optionally include yourplanNickname
as an argument toextpay.openPaymentPage(planNickname)
to directly open the Stripe payment page for that plan. For example:extpay.openPaymentPage('my_plan_nickname')
. Plan nicknames can be edited in the ExtensionPay.com extension settings page.
While developing your extension in test mode, you will need to enter your account password in order to proceed to the Stripe Checkout page. This is to prevent fraudulent access to your extension. You can useStripe's test cards in order to test the payment experience in development.
It is best to open the payment page when the user has a clear idea of what they're paying for.
Depending on how you configure your extension, users that have paid before can log in to activate their paid features on different browsers, profiles, or after uninstalling/reinstalling.
You should turn on as manypayment methods in your Stripe settings as possible to maximize your revenue.
Also seeour guide for how to create coupon / discount codes for your extensions.
For example, an extension with a $10 monthly and $99 yearly plan might look like this:
>awaitextpay.getPlans();[{unitAmountCents:1000,currency:'usd',nickname:null,intervalCount:'month',interval:1},{unitAmountCents:9900,currency:'usd',nickname:null,intervalCount:'year',interval:1}]
The specification for plans looks like this:
interfacePlan{unitAmountCents:number;currency:string;nickname:string|null;interval:'month'|'year'|'once';intervalCount:number|null;}
property | description |
---|---|
plan.unitAmountCents | The amount in cents that the user pays in one interval. |
plan.currency | The ISO 4217 currency the unit amount is in. For example:'usd' |
plan.nickname | An optional plan nickname for the developer to use in identifying plans. Can be editing in extension settings. |
plan.interval | The recurring interval the plan is charged. One of'month' ,'year' , or'once' . |
plan.intervalCount | null ifinterval is'once' , otherwise the number of intervals the plan is charged. For example: anintervalCount of2 with aninterval of'month' would mean the plan charges every 2 months. |
If you want to run some code when your user pays for the first time, useextpay.onPaid.addListener()
:
extpay.onPaid.addListener(user=>{console.log('user paid!')})
To use this feature, you will need to include the following content script configuration in yourmanifest.json
:
{"content_scripts": [ {"matches": ["https://extensionpay.com/*"],"js": ["ExtPay.js"],"run_at":"document_start" } ]}
The content script is required to enableextpay.onPaid
callbacks. It will add a permissions warning when installing your extension. If you're using a bundler, you can create a file called something likeExtPay_content_script.js
that only containsimport 'ExtPay'
orrequire('ExtPay')
and use that in the"js"
field above.
You can add as many callback functions as you want.
Note:onPaid
callbacks will be called after a user pays as well as after a user "logs in" (e.g. activates their paid account on a different browser/profile/install). This may change in the future -- if you'd like this to work differently, please contact me with a detailed explanation of your use case :)
If your extension is configured for subscription payments, you should let the user manage/cancel their subscription from within the extension with the same function you used to let them pay:
extpay.openPaymentPage()
The subscription management page looks something like this:
Obviously you should allow your users to access this page in order to cancel their subscription!Note: please read thedetailed docs on subscriptions here.
If you want to give your users a trial period of your extension, you can useextpay.openTrialPage()
, which looks something like this:
The user will be sent an email with a link that they can use to start their free trial. Once the user clicks the link, you can use thetrialStartedAt
property fromextpay.getUser()
in your extension to check if the trial has expired.
For example, if you wanted a 7 day trial period, you could use a check like this:
constextpay=ExtPay('sample-extension');extpay.getUser().then(user=>{constnow=newDate();constsevenDays=1000*60*60*24*7// in millisecondsif(user.trialStartedAt&&(now-user.trialStartedAt)<sevenDays){// user's trial is active}else{// user's trial is not active}})Afterusersstartatrial,theuserobjectwillhavethe`trialStartedAt`propertypopulated.Ifusersuninstallandreinstallyourextensionandthenattempttostartanewtrialusingthesameemailtheypreviouslyused,theywillbeinstantly "loggedin" to their existing free trial without needing to confirm instead of starting a new trial or being rejected. Their `trialStartedAt` will be the same. If this is confusing, please try it out in development!
Note thatextpay.openTrialPage(displayText)
takes an optional string argument that is displayed to the user on the trial page. For example,extpay.openTrialPage('7-day')
would change the trial prompt fromEnter an email to start your free trial
toEnter an email to start your *7-day* free trial
. This is meant to give your users a better idea of what they're signing up for.
You can also useextpay.onTrialStarted.addListener()
to run functions when the user's trial starts. LikeonPaid
, you need to include the following in yourmanifest.json
to make it work:
{"content_scripts": [ {"matches": ["https://extensionpay.com/*"],"js": ["ExtPay.js"],"run_at":"document_start" } ]}
A page will open that will allow the user to enter the email they paid with to receive a magic login link. This page can also be accessed through the normal payment screen.
npm install
- Edit
ExtPay.dev.js
npm run dev
npm run dist
before committing changes.
About
The JavaScript library for ExtensionPay.com — payments for your browser extensions, no server needed.
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Uh oh!
There was an error while loading.Please reload this page.