Products, Prices, and Paid Access
A product is the paid thing visitors can buy — a subscription, or a one-time purchase. Each product has a product handle and one or more prices, and each price has a price handle. Those two handles drive the onsite integration: you check the product handle with ezsubscriptions.hasAccess(...), and you open checkout with either ezsubscriptions.showPaywall({ product }) or ezsubscriptions.openCheckout({ price }).
Products
You create products in the Ezoic dashboard. A product has:
- A public name, such as
Remove AdsorPremium. - An optional description shown on the paywall.
- A product handle your site code uses.
- One or more prices.
Suppose you create a product named Remove Ads with the product handle remove-ads. On your site, your template checks access with ezsubscriptions.hasAccess("remove-ads"). If the visitor has access, you show the subscriber-only experience. If they do not, you call ezsubscriptions.showPaywall({ product: "remove-ads" }), which opens Ezoic's pre-built paywall and checkout experience for that product's prices.
You can create more than one product on a site — for example, a remove-ads subscription site-wide and a separate poll-access product on results pages — and open whichever one fits the page.
Product Handles
The product handle is the stable identifier your site passes to hasAccess(...) and showPaywall({ product }). Pick a handle when you create the product in your Ezoic dashboard.
Product handles are:
- Domain-scoped and unique per site.
- Case-insensitive and stored lowercase.
- Limited to letters, numbers, hyphens, and underscores.
Examples: remove-ads, premium, poll-access.
Use handles that describe the access level, not the current price or promotion. Avoid changing a product handle after your site is using it unless you also update the site code that references it.
Prices
A price is a way to buy a product. Each price has:
- A label, such as
Monthly,Annual, orLifetime. - An amount and billing interval.
- A price handle your site code can use for custom checkout buttons.
showPaywall({ product }) presents all of a product's active prices and lets the visitor choose. When you want a button that charges one specific price directly — skipping price selection — pass its price handle to ezsubscriptions.openCheckout({ price }).
Price handles follow the same rules as product handles: domain-scoped, unique per site, case-insensitive, and limited to letters, numbers, hyphens, and underscores. Examples: remove-ads-monthly, remove-ads-annual.
One-Time Purchases
A one-time price is a single payment rather than a recurring subscription. When you create one in the dashboard, two extra fields decide exactly what the payment buys:
- What this unlocks — one of three modes (see below).
- Access duration (days, optional) — leave it blank for lifetime access, or enter a number of days for a time-limited pass (for example a 1-day article rental or a 7-day pass). When the window lapses, access stops and the check returns
expired, so always treat a fresh check as the source of truth.
What this unlocks
| Mode | What it grants | Gate the content with |
|---|---|---|
| The whole product | The entire product, exactly like a subscription. | hasAccess({ product }) |
| A single item your site provides | One item you name at checkout (an article id, a download slug). | hasAccess({ product }) || hasPurchased({ item }) |
| The current article automatically | The article the paywall is shown on — Ezoic uses the page URL as the item, so one price covers every article. | hasPurchased({ page: true }) |
Either item mode grants access to that one item only: it never satisfies hasAccess({ product }) and never appears in getProducts().
A single item your site provides
Pass a publisher-chosen item key alongside the price at checkout:
await ezsubscriptions.openCheckout({
price: "article-unlock",
item: "article-12345",
});
You can also let Ezoic's paywall sell it: ezsubscriptions.showPaywall({ product: "premium", item: "article-12345" }). Check it later with ezsubscriptions.hasPurchased({ item: "article-12345" }). The item is a site-wide key — stored verbatim and matched exactly on its own, no price needed — so keep it stable per item.
The current article automatically
Pick this mode when every article sells the same way and you don't want to maintain a per-article id. Put ezsubscriptions.showPaywall({ product: "premium" }) on the article — the paywall sells access to that page — and reveal an already-bought article with hasPurchased({ page: true }):
const access = await ezsubscriptions.hasPurchased({ page: true });
if (access.decision === "allowed") {
revealArticle();
}
{ page: true } tells Ezoic to check the current page using the same normalized page key it stamps at checkout, so your check always matches what was sold — you never compute or pass the item yourself.
Example Product Structures
Ad-Free Subscription
- Product name:
Remove Ads - Product handle:
remove-ads - Price:
Monthly—$4.99 / month— price handleremove-ads-monthly
The most common setup: one product that removes ads for subscribers.
Premium Content Subscription
- Product name:
Premium - Product handle:
premium - Price:
Monthly—$9.99 / month— price handlepremium-monthly
Use this when one paid product unlocks all subscriber-only content.
Subscription With Multiple Prices
- Product handle:
premium - Price:
Monthly—$9.99 / month— price handlepremium-monthly - Price:
Annual—$99.00 / year— price handlepremium-annual
Use this when you want to offer the same product at more than one billing interval. showPaywall({ product: "premium" }) lets the visitor choose; a custom button can call openCheckout({ price: "premium-annual" }) to sell a specific price.
Appearance and Styling
Each product has its own Appearance settings — template, color mode, and accent color — plus a curated set of CSS variables for finer brand matching. See Paywall Appearance and Styling.
Donations Are Separate
Donations are a separate domain-level support option. They do not grant products and do not unlock subscriber-only content. Use Donations if you want readers to contribute without buying a product.
After Creating a Product
After your product is live:
- Add the onsite script to your site.
- Use the product handle in
ezsubscriptions.hasAccess(...). - Use the product handle in
ezsubscriptions.showPaywall({ product }), or a price handle inezsubscriptions.openCheckout({ price }). - Add paywalled-content SEO markup to gated articles.
- Verify checkout as a new visitor.