mcpField
F
freemius-checkout

freemius-checkout

github.com/freemius开发399 次安装14 周前更新
代码仓库

关于 freemius-checkout

freemius-checkout 是面向 React 前端的 Freemius 结账集成技能,用于呈现订阅与一次性购买选项并打开结账覆盖层。价格和结账上下文由后端提供,购买结果也由后端验证与同步。

主要功能

  1. 01订阅月付与年付价格表
  2. 02一次性与额度充值价格表
  3. 03结账覆盖层与自定义按钮
  4. 04付费墙展示对应购买选项
  5. 05购买后向后端同步权益

适用场景

  1. 01在 React 应用中呈现订阅方案
  2. 02为用户提供一次性或额度充值购买
  3. 03按功能门控状态显示付费墙
  4. 04购买后由后端核验并更新权益

安装

复制下面的命令,在终端中运行。

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

安装后在 Claude Code 中输入/freemius-checkout确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
checkout-provider.md
custom-buttons.md
paywall.md
pricing-tables.md
vite-hono-porting.md

详细介绍

Freemius Checkout

在 React 前端渲染定价信息并打开 Freemius Checkout 覆盖层,让用户购买任意类型的商品——定期订阅或**一次性/充值(积分)**购买,并在服务端同步结果。

来源:React Starter Kit Checkout 组件 https://freemius.com/help/documentation/saas-sdk/react-starter/components/#checkout-components

框架说明。 本 Skill 中的示例基于 Vite/Hono,但并不要求使用该技术栈:服务端(由 freemius-core 管理)适用于任何支持 Web 标准 Request/Response 路由的框架;React Starter Kit 组件适用于 React 19+、shadcn UI 和 Tailwind,可通过 npx shadcn@latest add https://shadcn.freemius.com/all.json 安装。如果应用未使用 shadcn/React,请下载 Starter Kit,并将其作为参考,在应用自己的框架中实现相同的 UI。优先复用应用现有组件(按钮、输入框、卡片、对话框),而不是重新创建基础组件——将 Starter Kit 的结构和行为移植到应用自己的设计系统中,而非引入新的基础组件。

沙盒。 请在沙盒模式下构建和验证——这种结账模式接受测试信用卡(不是折扣;无需使用或涉及优惠券)。该模式通过专用的 FREEMIUS_SANDBOX 环境变量接入(绝不使用 NODE_ENV),由 freemius-core 管理;服务端创建的结账已包含沙盒标志,本 Skill 会继承该标志。

黄金规则(不得违反)

  1. 浏览器中运行的只有覆盖层。 它使用由服务器创建的序列化结账对象进行初始化(来自 freemius-core 的 checkout.serialize())。secretKey/apiKey 绝不会传到客户端。
  2. 浏览器永远不能信任自身。 覆盖层购买成功后会触发回调,将载荷 POST 到后端;后端会从 Freemius 重新获取权威购买记录,并更新或插入权益。付费墙在服务器端强制执行(HTTP 402);UI 门控仅用于改善用户体验。
    • ⛔️ 覆盖层同步与托管重定向是两个独立端点,使用不同的载荷契约——绝不要将它们合并。 覆盖层的 purchaseCompleted 回调会将 JSON 请求体 POST 到专用的 POST /api/purchase;该处理程序从覆盖层载荷中读取 license_id,并调用 syncEntitlementByLicenseId(licenseId)。托管返回使用另一个独立端点 GET /api/checkout/redirect,在已签名的查询字符串上运行 freemius.checkout.processRedirect(url, PUBLIC_URL)(参见 freemius-core → purchase-processing)。不要通过 freemius.checkout.request.createProcessor(...) / processRedirect(...) 处理覆盖层 POST,也不要将 syncEndpoint 指向 /api/checkout/redirect?action=process_purchase。这些 SDK 路径要求提供已签名的重定向,或使用覆盖层载荷不包含的格式提供 license_id,因此 POST 会返回 400 "License ID is required in the request body";前端的 .catch() 会吞掉此错误,而 user_fs_entitlement 对所有用户都将保持空值,尽管 UI 看起来正常。(createProcessor 属于客户门户的无头端点,而非覆盖层购买同步——不要在这里借用它。)
  3. 定价数据来自一个服务器端点。 前端从后端获取方案、价格和每个方案的结账上下文(GET /api/checkout/pricing);绝不会直接调用 Freemius API。
  4. 覆盖所有购买模式。 订阅使用计费周期切换开关(monthly/annual);一次性/充值方案通过 billing_cycle: 'lifetime' 打开覆盖层。两种模式都要渲染——不要将演示版中仅支持订阅的路径写死。
  5. 绝不要要求开发者重新说明订阅模式。 定价表会从 GET /api/checkout/pricing 自动获取方案和价格,其数据来源为 Freemius Dashboard。Dashboard 是方案和定价的唯一可信来源——根据该数据检测购买模式(仅有 lifetime 的方案 → Topup;monthly/annual 方案 → Subscribe);不要在构建提示词或收集信息的问题中将其硬编码。
  6. 购买后的确认体验由应用负责。 打开覆盖层时设置 show_confirmation_dialog: false(跳过 Freemius 的确认弹窗),改为显示应用内成功状态——参见应用内成功消息。在同一个 onPurchase 处理程序中,隐藏付费墙,并清除受门控操作因 402 产生的任何过时门控错误/结果,然后重新检查权益——否则受门控界面会一直显示“需要订阅”/“升级”消息,直到重新加载。
  7. 购买界面必须识别用户权益。 绝不要向已订阅用户显示普通的 Subscribe 按钮(普通订阅结账会创建第二个并行订阅,导致重复扣费);他们应使用服务器构建的许可证升级结账路径(获取许可证 + setLicenseUpgradeByKey——参见 freemius-customer-portal;不要使用 checkout.create({ licenseId }),它会对续订中的许可证返回 500)。对拥有有效无限量订阅的用户隐藏积分充值选项;标记已拥有的方案;对订阅用户注明或隐藏 Lifetime。参见 references/pricing-tables.md →“Entitlement-aware rendering”。

组件

将这些组件移植为可编辑的 shadcn/ui 风格 React 源码(而非不透明的包)。 每个组件都有专门的参考文档——阅读所需的文档:

组件功能参考
CheckoutProvider持有一个覆盖层实例;提供 useCheckout()references/checkout-provider.md
Subscribe订阅定价表(月度/年度切换)references/pricing-tables.md
Topup一次性/点数定价表(lifetime 计费)references/pricing-tables.md
Paywall在功能受限时显示相应定价表的覆盖层references/paywall.md
自定义按钮调用 useCheckout().open(...) 的任意元素references/custom-buttons.md

Next.js→Vite/Hono 的移植范围(环境变量、@/@shared 别名、两个服务端端点)见 references/vite-hono-porting.md。

快速开始

1. 安装前端 SDK
npm install @freemius/checkout
2. 使用服务端创建的结账信息初始化提供程序
// The base checkout is created server-side (freemius-core) and exposed at
// GET /api/checkout → { options, link, baseUrl }. Load it, then wrap the UI.
const checkout = await getBaseCheckout(); // CheckoutSerialized

<CheckoutProvider
  checkout={checkout}
  syncEndpoint="/api/purchase" // POST target for the success callback
  fetcher={portalFetch} // attaches auth headers
  onPurchase={refreshEntitlement} // re-fetch entitlement after success
>
  <Subscribe />
  <Topup />
</CheckoutProvider>;
3. 为选定方案打开覆盖层
const checkout = useCheckout();

// Subscription (with billing cycle):
checkout.open({
  plan_id: planId,
  billing_cycle: 'annual',
  show_confirmation_dialog: false, // default — the app shows its own success state
});

// One-off / top-up (consumable credits):
checkout.open({
  plan_id: planId,
  billing_cycle: 'lifetime',
  show_confirmation_dialog: false,
});

open() 会将你的参数与基础选项合并,并接入 purchaseCompleted 回调;该回调会向 syncEndpoint 发送 POST 请求。

在每次调用 open() 时,将 show_confirmation_dialog: false 设为默认值(或将其写入提供程序):这样会跳过 Freemius 自带的购买后确认弹窗,改由应用显示成功状态——体验更好,也只需一个弹窗。由于 Freemius 弹窗已关闭,应用必须自行显示确认信息(见下一节)。

应用内成功提示(购买后)

当 show_confirmation_dialog: false 时,应用需在两种购买流程中自行提供确认体验:

  • 覆盖层流程 — purchaseCompleted → 提供程序向 /api/purchase 发送 POST 请求(同步权益)→ 触发 onPurchase。使用此回调来(1)重新获取权益/余额;(2)显示可见的成功状态——例如 Toast/横幅,订阅时显示**“购买完成——已解锁高级功能”,充值时显示“点数已添加到账户”**。绝不要在不提示用户的情况下完成购买。
  • 托管重定向流程 — Freemius 会将用户重定向回你的购买重定向处理程序(freemius-core → purchase-processing);其结果页面必须显示相同的成功提示。

接线方式见 references/checkout-provider.md → “应用内成功提示”。

工作原理

Server (freemius-core)              Frontend (this Skill)                 Freemius
  GET /api/checkout ───────────────▶ getBaseCheckout()
  { options, link, baseUrl } ──────▶ new Checkout(options,…) (one instance)
  GET /api/checkout/pricing ───────▶ <Subscribe/> + <Topup/> tables
                                      user clicks "Subscribe"/"Buy"
                                      useCheckout().open({plan_id, billing_cycle}) ─▶ overlay
                                      user pays ───────────────────────────────────▶ license/payment
  POST /api/purchase ◀────────────── purchaseCompleted(data) callback
  (re-fetch + upsert entitlement)
  402 on gated feature ────────────▶ <Paywall/> shows the right table

托管结账回退方案

如果无法加载 @freemius/checkout(或想要最简单的方案),定价响应中的每个方案也都包含托管的 checkoutLink。将浏览器导航到该链接;Freemius 会将用户重定向回你的购买重定向处理程序(由 freemius-core → purchase-processing 处理)。为了获得更好的体验,优先使用覆盖层;同时保留该链接作为平稳降级方案。

仪表板配置(交由人工处理)

在 Freemius Developer Dashboard(https://dashboard.freemius.com/)中:

  • Product → Plans → 定义各项计划及其定价。仅设有 lifetime 价格(无月付/年付)的计划会显示在 Topup 表格中;设有月付/年付价格的计划会显示在 Subscribe 中。
  • 充值前提条件: 只有当产品中存在仅限 lifetime 的计划时,一次性/充值模式才会显示。如果制作方希望提供充值(或你需要演示/验证该模式),请让他们先创建一个计划——将此视为受理/前提条件问题,并在 oneoff 返回空内容时妥善隐藏 Topup 表格。
  • Checkout → appearance / behaviour → 可选的叠加层品牌设置。
  • Webhook 和重定向 URL 的设置由 freemius-core 负责。

购买所授予用户的权益(功能解锁、额度余额)由服务端处理,并由 freemius-core 负责——充值额度请参阅 freemius-core → entitlement-logic.md →“基于用量/额度计量 (充值模式)”(余额存放在单独的、以用户为键的表中,绝不能扩展 user_fs_entitlement)。

评论

支持 Markdown