mcpField
F
freemius-troubleshooting

freemius-troubleshooting

github.com/freemiusDevelopment3103 installsUpdated 15w ago
Repository

About freemius-troubleshooting

A diagnostic skill for developers integrating Freemius, organized around common checkout, webhook, SDK, and configuration failures. It maps symptoms to likely causes and targeted reference guides, including links to related Freemius skills.

Key features

  1. 01Symptom-to-fix troubleshooting index
  2. 02Webhook and redirect diagnostics
  3. 03SDK type and event guidance
  4. 04Checkout and customer portal checks
  5. 05Cross-references to related skills

Use cases

  1. 01Diagnose missing access after checkout
  2. 02Investigate webhook signature failures
  3. 03Resolve SDK type or event errors
  4. 04Check portal, upgrade, or entitlement issues

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/freemius/freemius-ai --skill freemius-troubleshooting

After installing, type/freemius-troubleshootingin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

references/
checkout-and-portal.md
sdk-types-and-events.md
stack-and-porting.md
webhooks-and-redirect.md

Details

From the project README

Freemius Troubleshooting

When a Freemius integration breaks, the failure is almost always in one of five places: webhooks/redirect plumbing, SDK types/events, the stack/porting layer, checkout/portal wiring, or secrets/dashboard config. This Skill is a diagnostic index — find the symptom, jump to the reference, apply the fix.

Source FAQ: https://freemius.com/help/documentation/ai/lovable/#troubleshooting

How to use this Skill

  1. Match your symptom in the table below.
  2. Open the linked reference for the root cause + fix.
  3. If it is a freemius-core / freemius-checkout / freemius-customer-portal concern, the reference points you back to the exact section of those Skills.

Symptom → fix index

SymptomLikely causeReference
Checkout completes but the user never gets accessRedirect URL or webhook not configured / not publicreferences/webhooks-and-redirect.md
Webhook signature verification failsRaw body was parsed before handing to the listenerreferences/webhooks-and-redirect.md
TS error: Type '"lifetime"' is not assignable on an entitlement typeEntitlement type is subscription | oneoff, not lifetimereferences/sdk-types-and-events.md
Subscribing to license.quota.changed does nothing / type errorThat event does not exist in @freemius/[email protected]references/sdk-types-and-events.md
TS error: Object is possibly 'false' on license in a webhook handlerArray-subscription license is a union incl. the deleted shapereferences/sdk-types-and-events.md
prisma generate / client fails wanting a driver adapter; url rejectedPrisma 7 dropped classic datasource url — pin Prisma 6references/stack-and-porting.md
process.env.NEXT_PUBLIC_* is undefined in the browserVite uses import.meta.env.VITE_*, not process.envreferences/stack-and-porting.md
@/... or @shared/... import cannot be resolvedMissing alias in vite.config.ts + tsconfig pathsreferences/stack-and-porting.md
Installed skills via npx skills add but Claude Code (CLI) doesn't see them / slash commands missingClaude Code isn't a default install target; skills went to ~/.agents/skills/ with no ~/.claude/skills/ symlinkreferences/stack-and-porting.md
Tried the npx skills add … -a claude-code CLI route on Claude Desktop (Claude.ai app) and it doesn't applyThe CLI / -a claude-code flag is a Claude Code concept only; Desktop installs each Skill as a per-Skill .zip via Customize → Skills → "+" → Upload a skill (core first; Code execution enabled under Settings → Capabilities)references/stack-and-porting.md
Secret key / API token leaks to the browser, or 401 from FreemiusA Freemius call was made client-side instead of server-sidereferences/checkout-and-portal.md
Checkout overlay opens empty / unconfiguredOverlay not primed from a server-created CheckoutSerializedreferences/checkout-and-portal.md
Upgrade route 500s: "Payment method update is not allowed for lifetime licenses"checkout.create({ licenseId }) calls a payment-method-update endpoint that rejects renewing licenses (expiration: null) — use setLicenseUpgradeByKeyreferences/checkout-and-portal.md
User "upgraded" but now has two subscriptions / double-billedUpgrade offered as a plain subscribe checkout to an already-subscribed user — use a license-upgrade checkout (setLicenseUpgradeByKey) + entitlement-aware surfacesreferences/checkout-and-portal.md
Portal actions 404 / token invalidOne /api/portal endpoint must serve data and signed actionsreferences/checkout-and-portal.md
One-off / lifetime purchase doesn't behave like the subscription demoDifferent modality — use billing_cycle: 'lifetime', type oneoffreferences/checkout-and-portal.md
Upgraded to Lifetime but still gated / credits still charged / not shown as active (invoice is correct)freemius.entitlement.getActive() filters to type: 'subscription' — a one-off Lifetime row is invisible, so getUserEntitlement() returns nullreferences/sdk-types-and-events.md
Coupon'd subscription "renews" ~100 years out (USD 0 · renews 2126)100%-off coupon scoped to "First payment and renewals"references/checkout-and-portal.md
Re-subscribe blocked ("already on an active subscription") after a cancelAdmin cancelled the license, leaving the subscription orphaned-activereferences/checkout-and-portal.md
Subscribed user still sees the paywall / 402 despite an active subscription; user_fs_entitlement table is emptyCheckout used the bare hosted redirect with no overlay purchaseCompleted sync and no Dashboard checkout-redirect URL — nothing ever wrote the entitlement rowreferences/checkout-and-portal.md
user_fs_entitlement empty for every user; sync POST returns 400 "License ID is required in the request body" (frontend .catch() hides it)The overlay purchaseCompleted POST was routed through checkout.request.createProcessor / processRedirect (or syncEndpoint pointed at /api/checkout/redirect?action=process_purchase). That path expects a signed redirect / license_id in the body the overlay payload lacks. Overlay sync must be a plain POST /api/purchase that reads the license from the payload → syncEntitlementByLicenseId — separate endpoint from the hosted GET /api/checkout/redirectfreemius-checkout → references/checkout-provider.md
A gated feature (e.g. image OCR on Premium) shows a generic "OCR failed. Please try another file."The server's tier/entitlement gate (403/402 with a reason like tier_upgrade_required/image_requires_pro) was swallowed into the catch-all error. A gate is not a failure — branch on status+reason and open the paywall with an upgrade path, not the error toastfreemius-checkout → references/paywall.md
Purchase succeeds but there's no pricing page / no way to browse or buy plans without hitting a paywall firstBuild shipped the paywall but skipped the standalone pricing route — a dedicated /pricing page (Subscribe + Topup tables from GET /api/checkout/pricing) + nav link is a required deliverablefreemius-checkout → references/pricing-tables.md
Success toast says "credits added to your account" after buying a subscription (or wrong copy for Lifetime)Post-purchase copy didn't branch on the synced purchase type — use the re-fetched entitlement tier: lifetime → "Lifetime access unlocked", subscription → "<tier> unlocked", credits pack → "page credits added"freemius-checkout → references/checkout-provider.md
Credit balance shows the old value after an OCR (metered) run until a manual page refreshThe server debits credits correctly (credit -= pages), but the metered action's success handler never refreshes the displayed balance — the badge is stale until a full reload. Refresh the display without a reload: either read the new balance from the action's response, or await the same refreshEntitlement() (GET /api/entitlement → credit) the purchase flow uses. This is the consumption twin of the post-purchase entitlement refreshfreemius-checkout → references/paywall.md
/pricing shows nothing for a Lifetime / top-tier holder ("nothing is shown anymore")Every buy surface is correctly hidden (they own the top tier), but hiding them all leaves a blank page. Render a friendly "you own everything" empty-state instead — never a blank page. (A credits-only viewer must still see Subscribe + Topup.)freemius-checkout → references/pricing-tables.md
Account-page "Change plan" renders as a bare underlined link with no padding, misaligned next to Cancel"Change plan" is a router <Link> given a button class (e.g. btn-outline) that only inherits padding / radius / text-decoration:none from a base .btn class — applied alone to an <a> it loses all of it. Make the button/outline class self-contained, or put both base+modifier classes on the <Link>freemius-customer-portal → references/subscription-and-upgrade.md
Retention coupon: clicking "Apply discount & keep my plan" just closes the wizard, nothing happens, Dashboard shows 0 redemptionsThe apply POST sent an empty {} body — the SDK's renewal-coupon action requires { couponId: <coupons[0].coupon_id> } and 400s otherwise; AND the wizard ignored res.ok, so the failed call closed as if it succeeded. Send the real couponId and check res.ok (show error + keep open on failure)freemius-customer-portal → references/cancellation-and-coupon.md
After a hosted checkout/upgrade the browser lands on /checkout-result?success=true showing a blank page with only the headerThe server GET redirect handler bounces to /checkout-result, but the SPA router (App.tsx <Routes>) has no matching client route — the redirect target is a real page the build forgot to ship. Add a /checkout-result route that reads success, refreshes entitlement once on mount, shows the confirmation, and routes back into the appfreemius-core → references/purchase-processing.md
Entitlement doesn't update after a cancel/renew; webhook seems dead — but handler, URL and signature all check outLifecycle event fired before the webhook URL was active/propagated in the Dashboard — never delivered (not retro-sent)references/webhooks-and-redirect.md

First-resort checks (the Lovable FAQ baseline)

The official FAQ's top recommendations, applied to this stack:

  1. Ask the agent to re-run the failing step. These Skills are modular — re-invoke the specific reference (e.g. freemius-core → purchase-processing.md) rather than re-doing the whole integration.
  2. Webhooks + checkout redirect are the two critical paths. Verify both end to end first; most "no access after paying" reports are one of these misconfigured. Freemius emails you when webhook processing fails — paste that email content into the agent to pinpoint the failure.
  3. After publishing/deploying, update all URLs. A redirect or webhook URL still pointing at localhost (or an old domain) silently breaks the flow. PUBLIC_APP_URL must be the live domain.
  4. One-off purchases need a different approach than the subscription path — see the checkout/portal reference for the lifetime modality.
  5. Still stuck? Contact Freemius support ([email protected]) with the product id, the failing step, and screenshots.

Capturing new entries

This Skill is meant to grow. When a Skill defect is found during a validation gate, log it in the gate's "Skill defects found" table, fix the offending Skill, then add a troubleshooting entry here (symptom → cause → fix) so the next integrator skips the stumble.

Comments

Markdown supported