Troubleshooting
Use this guide when the onsite script, paywall, checkout, ad removal, donation dialog, SEO markup, or subscriber portal does not behave as expected.
Common Causes
Most onsite issues trace back to a few configuration details. Reviewing the following before investigating a specific symptom often identifies the cause:
- Payment setup is active. Checkout cannot sell access until your payment configuration is active — see Checkout Does Not Open or Has No Products to Sell.
- The product is live with an active price. A draft, disabled, or archived product — or one with no active price — cannot sell access.
- Your code uses the product handle, not the display name.
hasAccess(...)andshowPaywall({ product })take the product handle from your dashboard, not the public product name. - The script is present on the page.
https://sm.ezoic.com/min.jsneeds to load on the pages where subscriptions or donations run. - Your integration runs inside
ezsubscriptions.cmd. The script loads asynchronously, so API calls made outside the command queue can run before the widget is ready.
Setup and Dashboard
Checkout Does Not Open or Has No Products to Sell
Checkout requires an active payment configuration. Until payment setup is active, showPaywall({ product }) and openCheckout({ price }) have nothing to sell, and the paywall may appear empty.
Review your payment status in the dashboard (Subscriptions → Overview → Current status, or the Payments panel):
- Your own Stripe account (Stripe Connect): the account must have charges enabled. If Stripe still shows Requirements due or Details submitted pending review, complete the requested steps in Stripe and refresh the status in Ezoic. See Stripe Account Status.
- Ezoic-managed payments: the application can be Reviewing, Not approved, or Revoked. While a site is under review, you can finish building your product, add the script, and test the flow, but live payments become available only once your site is approved. If it was not approved, connect your own Stripe account instead. See Ezoic-Managed Payments.
You must also have at least one active product with an active price. See Payment Setup and Products, Prices, and Paid Access.
Checkout Fails on a Bring-Your-Own-Login Site
If your domain is set to bring your own login and you have not connected your login system to the widget, checkout cannot run, even though the paywall may still appear. This is a one-time configuration step, not something a visitor triggers.
On a bring-your-own-login domain, you must register an auth adapter with ezsubscriptions.initialize({ auth }), supplying all three methods (getUserEmail, goToLogin, goToCreateAccount). Until you do:
showPaywall({ product })still renders your prices, but selecting one has no effect and logs an error to the browser console.openCheckout({ price })does not render.
This is not related to whether a visitor is signed in. Once your adapter is registered, anonymous visitors are not blocked — they see the standard Log in, Create account, and (when enabled) Continue as guest options at checkout. Register and test your adapter before switching the domain to this mode. See Bring Your Own Login.
A Visitor Doesn't See the Free Trial Option
If the paywall shows the regular price instead of a free trial:
- The visitor already used their trial. Trials are limited to one per product per subscriber, so a visitor (or their card) that already trialed the product is offered the regular price instead. This is expected.
- The price has no trial configured. Confirm the recurring price has Free trial (days) set on its Products page. Trials apply only to recurring prices, not one-time purchases.
A Promo Code Is Rejected at Checkout
If a visitor enters a code and it is not accepted:
- The code is disabled, expired, or has reached its max redemptions. Check its status on the Products page.
- The code is restricted to specific products and the item in checkout isn't one of them.
- The order is below the code's minimum order amount.
- The code is first-time customers only and the visitor has bought before.
- The checkout is for a free trial and the code's duration is Once — once-duration codes can't be used with trials. Use a repeating or forever code instead.
- Only one code applies per checkout, and codes do not apply to donations.
See Promo Codes.
Onsite Script and Access
The Script Does Not Load
Confirm the script is present on the page:
<script src="https://sm.ezoic.com/min.js" async defer></script>
Then check:
- Browser console errors.
- Network errors for
https://sm.ezoic.com/min.js. - Ad blockers or privacy extensions.
- Content Security Policy restrictions.
- Whether the script is included on the page where subscriptions should work.
See Onsite Script Integration for placement guidance.
ezsubscriptions Is Undefined or API Calls Have No Effect
Because min.js loads asynchronously, window.ezsubscriptions and its methods are not available the instant your page runs. If you call the API directly on page load, it may throw ezsubscriptions is undefined or have no effect.
Queue your integration on ezsubscriptions.cmd instead — the callback runs once the widget is ready:
<script>
window.ezsubscriptions = window.ezsubscriptions || {};
ezsubscriptions.cmd = ezsubscriptions.cmd || [];
ezsubscriptions.cmd.push(function (api) {
// api is the resolved ezsubscriptions API, ready to use.
});
</script>
<script src="https://sm.ezoic.com/min.js" async defer></script>
If you need a synchronous check, ezsubscriptions.ready is true once the API is available. See Readiness.
The Paywall Does Not Appear
showPaywall({ product }) is safe to call on every page load — it deliberately renders nothing in several expected cases. The usual explanations:
- The visitor already has access. For a signed-in visitor who already holds the product (or the in-play item), the paywall re-checks access and self-suppresses — this is correct behavior, not a defect. If the paywall appears blank during testing, the account is likely still signed in from a previous purchase. Test in a fresh private or incognito window as an anonymous visitor, who always sees the paywall.
- The product handle is incorrect. The
productvalue must be the product handle from your dashboard, not the public display name. An unknown or inactive handle renders nothing. - The product is not sellable. A draft, disabled, or archived product, or one with no active price, renders nothing. Confirm the product is live with at least one active price on your Products page.
- Payment setup is not active. See Checkout Does Not Open or Has No Products to Sell.
productis missing.showPaywall(...)requires aproduct; without it, the call has no effect.- The call ran before the widget was ready. Place it inside
ezsubscriptions.cmd.
Note that openCheckout({ price }) does not self-suppress for a visitor who already has access — it opens checkout for that price regardless. When wiring a custom buy button, gate it behind your own hasAccess(...) check rather than assuming openCheckout will skip existing subscribers.
A Subscriber Paid but Still Sees the Paywall
Access is established by Ezoic after payment is verified — not the moment the card form submits. Your onSuccess callback runs only once access is confirmed.
Ask the visitor to refresh the page. If that does not work:
- Reveal content from your
onSuccesscallback or anaccess:changelistener, rather than assuming access the instant checkout closes. - Confirm your site waits for access verification before revealing full content.
- Confirm the code checks the same product handle that the purchase grants.
- Have the visitor use the "Already subscribed?" or Log in link in the paywall to restore their session.
Content Does Not Update After Login or Checkout (React, Vue, Next.js)
In a single-page app, the widget cannot observe your client-side route changes, so gated content may become stale after a login or purchase. Load min.js once (in your root layout or shell, not per route), then:
- Re-run
hasAccess(...)when the view changes, and reveal content, remove ads, or open the paywall accordingly. - Subscribe to
access:changeso gated UI updates in place when the visitor logs in or completes checkout. - Let magic-link returns and checkout resumption land on a real URL rather than intercepting them in your client router.
See Single-Page Apps and Frameworks.
Ads Still Appear for a Subscriber
Ad removal is applied on Ezoic's servers, so ezsubscriptions.disableAds() reloads the page once on the page where access is first gained; every page view after that is ad-free. If ads still appear:
- Confirm your code calls
disableAds()afterhasAccess(...)returnsallowed(andallowAds()otherwise). - Note that only ads Ezoic serves are suppressed. Ads from another network, a header-bidding setup you run yourself, or tags you place directly on the page are outside Ezoic's control — remove those for subscribers yourself.
- After sign-out or an expired subscription,
allowAds()restores ads on the visitor's next page view, so a refresh may be needed before ads reappear.
Content Protection and SEO
Full Content Is Visible in the Page Source
If full article content is shipped in the initial HTML, technically advanced visitors may be able to inspect it even if it is visually hidden.
For stronger protection:
- Serve only teaser content initially.
- Call
ezsubscriptions.hasAccess(...). - Fetch or render the protected body only after access is allowed.
The widget provides access checks, paywall UI, checkout, and login. Your site still controls how protected content is delivered. See Protecting Full Content.
Paywalled-Content Markup Fails Validation
Paywalled-content structured data is authored by your site — the widget does not emit it for you. For gated article pages, confirm:
- The page has
isAccessibleForFree: false. - The page has a
hasPartobject. hasPart.cssSelectormatches the gated content container, such as.paywalled-content.- JSON-LD appears in the rendered HTML.
- Google's Rich Results Test can read the markup.
If the page already has article JSON-LD, merge the paywall fields into that object rather than creating conflicting duplicate article records. See SEO and Paywalling Best Practices.
A Gated Page Disappeared From Search
Check for common indexing mistakes:
- Accidental
noindex. robots.txtblocking the URL.- Incorrect canonical tags.
- Server-side gating that blocks crawler access.
- User-agent-only crawler handling.
Do not cloak content. Follow Google's paywalled-content structured data guidance and SEO and Paywalling Best Practices.
Stripe Checkout Does Not Load
If your site uses a strict Content Security Policy, it can block Stripe from loading the checkout. Allow Stripe in your CSP — see Stripe Content Security Policy for the allowlist entries.
Also check browser console errors and confirm payment setup is active.
Donations
The Donation Button Has No Effect
Confirm:
- Donations are enabled in the Ezoic dashboard, with an active donation that has an active price and active payment setup — not only the enable toggle.
openDonation()logs a warning and has no effect on a site with no donation configured. - Your custom button's click handler runs inside a widget
cmdcallback. amountCentsis an integer number of cents.amountCentsis at least the configured minimum donation amount.
Example:
ezsubscriptions.openDonation({ amountCents: 2500 });
2500 means $25.00. openDonation() loads your donation settings on first use, so no setup call is needed. See Donation Integration.
Subscribers and the Portal
A Subscriber Cannot Remove a Card
A saved card may be tied to an active subscription. The subscriber should add or select another card for that subscription first, or cancel the subscription before removing the card. See Subscriber Experience.
A Subscriber Cannot Log In
First, have the subscriber sign in through the standard flow:
- Use the site's Log in link (or the paywall's "Already subscribed?" link) to open the sign-in screen for the site's authentication mode.
- On Ezoic visitor accounts, sign in with email and password (or Continue with Google, if enabled). On bring your own login, sign in through the site's own login.
On Ezoic visitor accounts, if they still cannot sign in — for example, on a new device, or after purchasing as a guest — fall back to the one-time email sign-in link, offered from both the paywall and the login page:
- Request a fresh login link from the paywall or the login page.
- Check their email for the latest link and use the newest one, since links expire (currently after 15 minutes) and are single-use.
On bring your own login, there is no Ezoic-issued sign-in link: the site's Log in link and the paywall both go straight to your own login, so a sign-in problem (for example a forgotten password) is your own system's to resolve.
The subscriber portal (https://subscriber.ezoic.com) will not resolve this either way: it is a separate, billing-only session, and signing in there does not unlock gated content back on your site. To regain onsite access, the subscriber must sign in through your site's Log in link or the paywall's one-time link above.