View as Markdown

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(...) and showPaywall({ 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.js needs 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 product value 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.
  • product is missing. showPaywall(...) requires a product; 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 onSuccess callback or an access:change listener, 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:change so 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() after hasAccess(...) returns allowed (and allowAds() 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:

  1. Serve only teaser content initially.
  2. Call ezsubscriptions.hasAccess(...).
  3. 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 hasPart object.
  • hasPart.cssSelector matches 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.

Check for common indexing mistakes:

  • Accidental noindex.
  • robots.txt blocking 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 cmd callback.
  • amountCents is an integer number of cents.
  • amountCents is 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:

  1. 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.
  2. 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:

  1. Request a fresh login link from the paywall or the login page.
  2. 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.