- Usage Guide
- API
- Use with React
- Testing with Sandbox
- Migration guide from the old checkout JS
- Contributing
Here's a simple example to get you started.
<select id="licenses">
<option value="1" selected="selected">Single Site License</option>
<option value="2">2-Site License</option>
<option value="unlimited">Unlimited Sites License</option>
</select>
<button id="purchase">Buy Button</button>
<script
type="text/javascript"
src="https://checkout.freemius.com/js/v1/"
></script>
<script type="text/javascript">
const handler = new FS.Checkout({
plugin_id: '9885',
plan_id: '16634',
public_key: 'pk_ccca7be7fa43aec791448b43c6266',
image: 'https://your-plugin-site.com/logo-100x100.png',
});
document.querySelector('#purchase').addEventListener('click', (e) => {
handler.open({
name: 'My Awesome Plugin',
licenses: document.querySelector('#licenses').value,
// You can consume the response for after purchase logic.
purchaseCompleted: function (response) {
// The logic here will be executed immediately after the purchase confirmation.
// alert(response.user.email);
},
success: function (response) {
// The logic here will be executed after the customer closes the checkout, after a successful purchase.
// alert(response.user.email);
},
});
e.preventDefault();
});
</script>
Please find detailed guides below.
NOTE: If you're migrating from the old checkout JS, please see the migration guide.
To use the hosted CDN, simply include the script tag in your HTML.
<script
type="text/javascript"
src="https://checkout.freemius.com/js/v1/"
></script>
This will add the global FS.Checkout
class which you can instantiate.
You can also load the script using the async
or defer
attribute on the
script tag. Note, however, that with asynchronous loading any API calls will
have to be made only after the script execution has finished. For that you'll
need to hook to load
event of window
or use window.onload
.
<script
type="text/javascript"
src="https://checkout.freemius.com/js/v1/"
async
defer
></script>
<script type="text/javascript">
window.addEventListener('load', () => {
const handler = new FS.Checkout({
plugin_id: '1234',
public_key: 'pk_xxxx',
});
handler.open({
// plan
plan_id: 9999,
// number of sites
licenses: 1,
// billing cycles
billing_cycle: 'annual',
});
});
</script>
You can also use the official npm package.
npm i @freemius/checkout
# If using yarn
yarn add @freemius/checkout
Once installed you can import the package and use it in your project.
import { Checkout } from '@freemius/checkout';
// instantiate
const handler = new Checkout({
plugin_id: '1234',
public_key: 'pk_xxxx',
});
// Call the API
document.querySelector('#mybutton').addEventListener('click', (e) => {
e.preventDefault();
// call the open method
handler.open({
// plan
plan_id: 9999,
// number of sites
licenses: 1,
// billing cycles
billing_cycle: 'annual',
});
});
Both the constructor and the open
method accepts the following set of options.
All the official options are supported here, along with some additional options.
interface AdditionalCheckoutOptions {
/**
* Optional callback to execute when the iFrame opens.
*
* @new
*/
afterOpen?: () => void;
/**
* An optional callback to execute when the iFrame closes.
*
* @new
*/
afterClose?: () => void;
/**
* Optional callback to trigger on exit intent. This is called only when the
* checkout iFrame is shown, not on global exit intent.
*
* @new
*/
onExitIntent?: () => void;
/**
* If you would like the dialog to open in sandbox mode,
*/
sandbox?: {
ctx: string;
token: string;
};
/**
* The URL of the image to display while the checkout is loading. By default a loading indicator from Freemius will be used.
*/
loadingImageUrl?: string;
/**
* The alt text for the loading image. By default 'Loading Freemius Checkout' will be used.
*/
loadingImageAlt?: string;
}
For testing with sandbox API, see the relevant section.
The main class exported by the package is Checkout
. For the hosted CDN it is
available under the global FS
namespace.
const handler = new FS.Checkout({
plugin_id: '1234',
public_key: 'pk_xxxx',
});
If you're using the package from npm, you simply import it and create an instance.
import { Checkout } from 'freemius-checkout-js';
// instantiate
const handler = new Checkout({
plugin_id: '0001',
public_key: 'pk_xxxx',
});
Note that the plugin_id
and public_key
are required parameters and must be
supplied during instantiation.
Now you can simply call the open
method to show the checkout popup.
handler.open();
You can also pass additional options
handler.open({
// plan
plan_id: 9999,
// number of sites
licenses: 1,
// billing cycles
billing_cycle: 'annual',
});
This is useful when you have multiple checkouts related to different plans, billing cycles, licenses, trials etc.
See the source code of the demo to learn more.
To close the popup programmatically, call the close
method.
handle.close();
We will make a small react hook. Here we assume the plugin_id
and public_key
are available in
some environment variable.
checkout.ts
import { Checkout, CheckoutOptions } from '@freemius/checkout';
import { useState, useEffect } from 'react';
export const checkoutConfig: CheckoutOptions = {
plugin_id: process.env.REACT_APP_PLUGIN_ID as string,
public_key: process.env.REACT_APP_PUBLIC_KEY as string,
};
export function useFSCheckout() {
// create a Checkout instance once
const [fsCheckout] = useState<Checkout>(() => new Checkout(checkoutConfig));
useEffect(() => {
// close and destroy the DOM related stuff on unmount
return () => {
fsCheckout.destroy();
};
}, [fsCheckout]);
return fsCheckout;
}
Now we use in our component.
App.tsx
import React from 'react';
import { useFSCheckout } from './checkout.ts';
export default function App() {
const fsCheckout = useFSCheckout();
return (
<button
onClick={(e) => {
e.preventDefault();
fsCheckout.open({
plan_id: 1234,
licenses: 1,
billing_cycle: 'annual',
success: (data) => {
console.log(data);
},
});
}}
>
Buy Plan
</button>
);
}
To get the sandbox token and ctx, follow the steps:
- Go to the Developer Dashboard.
- Under Plans click on the "Get Checkout Code" button.
- Go to the Sandbox tab.
- Copy the
sandbox_token
andtimestamp
values.
The value of sandbox
is token and value of s_ctx_ts
is ctx. So for the above
value, the configuration would look like
const config = {
// ...
sandbox: {
token: 'xxxxxxxx',
ctx: '00000000',
},
};
NOTICE: Use this only during development and never publish the token and
context. In this repository we use the .env
file for storing sandbox data.
If you've been using the old checkout.freemius.com/checkout.min.js
script then
this guide is for you. We have introduced a compatibility layer using which you
can very easily migrate to the new checkout JS.
In your code, where you do
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="https://checkout.freemius.com/checkout.min.js"></script>
- Remove the jQuery script tag if you aren't using jQuery.
- Replace the checkout script with the new one.
<script src="https://checkout.freemius.com/js/v1/legacy/"></script>
Now all your existing code should work as is.
const handler = FS.Checkout.configure({
plugin_id: '1234',
plan_id: '5678',
public_key: 'pk_ccca7be7fa43aec791448b43c6266',
image: 'https://your-plugin-site.com/logo-100x100.png',
});
document.querySelector('#purchase').addEventListener('click', (e) => {
handler.open({
name: 'My Awesome Plugin',
licenses: document.querySelector('#licenses').value,
// You can consume the response for after purchase logic.
purchaseCompleted: function (response) {
// The logic here will be executed immediately after the purchase confirmation.
// alert(response.user.email);
},
success: function (response) {
// The logic here will be executed after the customer closes the checkout, after a successful purchase.
// alert(response.user.email);
},
});
e.preventDefault();
});
Please note that because of the singleton pattern of the old checkout JS, we do
recommend using the new API directly. The compatibility layer is only for quick
migration. With the singleton pattern, every time you call the configure
the
original option will be overridden. While managing multiple checkouts, this can
lead to confusion.
We welcome contributions! Please see the contribution guide.