revenuecat-troubleshoot
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chineserevenuecat-troubleshoot: diagnose RevenueCat integration problems
revenuecat-troubleshoot:诊断RevenueCat集成问题
Use this skill when the user reports a RevenueCat behavior that does not match expectations: empty offerings, missing products, an entitlement that does not unlock after a successful purchase, a paywall that fails to render, or sandbox transactions that never reach the dashboard.
This skill combines two angles:
- Code-side diagnosis — turn on debug logging, walk a universal checklist, drop into platform specifics.
- Dashboard inspection — use the RevenueCat MCP server to read the project, apps, products, entitlements, offerings, and webhooks, and offer fixes.
Work them in order. Most reports resolve before you reach the platform specifics.
当用户反馈RevenueCat行为不符合预期时使用此技能:offerings为空、产品缺失、成功购买后entitlement未解锁、付费墙无法渲染,或是沙盒交易从未出现在仪表盘中。
此技能从两个维度进行排查:
- 代码端诊断 —— 开启调试日志,执行通用排查清单,深入平台特定细节。
- 仪表盘检查 —— 使用RevenueCat MCP服务器读取项目、应用、产品、entitlements、offerings和webhooks,并提供修复方案。
按顺序执行这两项排查。大多数问题在深入平台特定细节前就能解决。
1. Detect the platform
1. 检测平台
Inspect the working directory and pick the first match, from top to bottom:
- React Native: has a
package.jsonentry, orreact-native-purchasesas a dependency → readreact-native. Ifplatforms/react-native.mdis also a dependency, note it as an Expo project.expo - Flutter: exists at the project root → read
pubspec.yaml.platforms/flutter.md - Kotlin Multiplatform: contains a
build.gradle.ktsmultiplatform source sets block, or depends onkotlin { … }→ readcom.revenuecat.purchases:purchases-kmp*.platforms/kmp.md - Android (native): applies
build.gradle(.kts)(and is not KMP) → readcom.android.application.platforms/android.md - iOS (native): ,
Package.swift,*.xcodeproj, or*.xcworkspaceat the project root → readPodfile.platforms/ios.md
If several match (e.g. an folder inside a Flutter project), pick the outermost project, the one that owns the build. If still ambiguous, ask the user which platform the bug reproduces on.
ios/检查工作目录,按从上到下的顺序选择第一个匹配项:
- React Native:包含
package.json条目,或依赖react-native-purchases→ 查看react-native。如果同时依赖platforms/react-native.md,则标记为Expo项目。expo - Flutter:项目根目录存在→ 查看
pubspec.yaml。platforms/flutter.md - Kotlin Multiplatform:包含
build.gradle.kts多平台源码集块,或依赖kotlin { … }→ 查看com.revenuecat.purchases:purchases-kmp*。platforms/kmp.md - Android(原生):应用了
build.gradle(.kts)(且非KMP项目) → 查看com.android.application。platforms/android.md - iOS(原生):项目根目录存在、
Package.swift、*.xcodeproj或*.xcworkspace→ 查看Podfile。platforms/ios.md
如果多个平台匹配(例如Flutter项目内包含文件夹),选择最外层的项目,即负责构建的项目。如果仍有歧义,请询问用户问题在哪个平台复现。
ios/2. Universal code-side checklist
2. 通用代码端排查清单
Walk these nine items in order. Most reports are resolved by steps 1 through 5.
- Turn on debug logging and reproduce. The SDK narrates what it is doing. Roughly 80% of reports are diagnosable from the log output alone. Each platform file shows how to set to debug.
logLevel - Verify the API key platform matches the app. iOS apps must use an public SDK key. Android apps must use
appl_…(orgoog_…for Amazon). A mismatched key produces an authentication error on the first network call. On iOS this surfaces as anamzn_…error code. On Android it surfaces asINVALID_CREDENTIALS.PurchasesErrorCode.InvalidCredentialsError - Verify the bundle ID / applicationId matches the dashboard. Open the RevenueCat dashboard → Project → Apps. The bundle identifier (iOS) or applicationId (Android) registered there must match the built app exactly, including capitalization. A mismatch causes offerings to come back empty because the app is not recognized.
- Verify offerings in the dashboard. Dashboard → Products → Offerings. The offering marked "current" must have at least one package attached, and each package must reference a store product. An offering with zero packages returns an empty list even though
availablePackagessucceeds.getOfferings - Verify store products are live. Products must be in "Ready to Submit" on App Store Connect or "Active" on Google Play Console. A product in a draft state will not be returned by the store, even in sandbox. If the SDK logs show offerings arriving from RevenueCat but products failing to resolve, this is almost always the cause.
- Verify the testing account. iOS: the device must be signed into a Sandbox Apple ID under Settings → App Store → Sandbox Account (set on iOS 14+ after the first sandbox prompt). Android: the tester's Gmail must be added to Google Play Console → Setup → License testing, and the app must be installed via the Internal Testing opt-in link, not sideloaded.
- Verify the network. Corporate VPNs, captive portals, and some DNS filters silently block the RevenueCat API or the store APIs. Try a different network before digging deeper.
- Verify the appUserID. If was called with an ID that does not match what the user expects, entitlements appear missing because they are attached to a different RC user. Print
logIn(appUserID)(iOS) /Purchases.shared.appUserID(Android) and confirm it matches.Purchases.sharedInstance.appUserID - Reset and retry. Uninstall the app, re-sign into the sandbox / tester account, reinstall from the correct channel, relaunch.
按顺序执行以下9项检查。大多数问题可通过步骤1至5解决。
- 开启调试日志并复现问题。SDK会记录自身操作。约80%的问题仅通过日志输出就能诊断。每个平台文档都说明了如何将设置为debug。
logLevel - 验证API密钥与平台匹配。iOS应用必须使用格式的公开SDK密钥。Android应用必须使用
appl_…(亚马逊平台使用goog_…)。密钥不匹配会在首次网络请求时产生认证错误。在iOS上表现为amzn_…错误码,在Android上表现为INVALID_CREDENTIALS。PurchasesErrorCode.InvalidCredentialsError - 验证Bundle ID / applicationId与仪表盘匹配。打开RevenueCat仪表盘 → 项目 → 应用。注册的Bundle identifier(iOS)或applicationId(Android)必须与构建的应用完全一致,包括大小写。不匹配会导致offerings返回为空,因为应用未被识别。
- 验证仪表盘中的offerings。仪表盘 → 产品 → Offerings。标记为“current”的offerings必须至少关联一个套餐,且每个套餐必须引用一个商店产品。即使调用成功,无套餐的offerings仍会返回空的
getOfferings列表。availablePackages - 验证商店产品已上线。产品在App Store Connect中必须处于“Ready to Submit”状态,或在Google Play Console中处于“Active”状态。处于草稿状态的产品即使在沙盒环境中也不会被商店返回。如果SDK日志显示offerings已从RevenueCat获取,但产品无法解析,几乎都是这个原因。
- 验证测试账户。iOS:设备必须在“设置 → App Store → Sandbox Account”中登录沙盒Apple ID(iOS 14+需在首次沙盒提示后设置)。Android:测试者的Gmail必须添加到Google Play Console → 设置 → 许可测试,且应用必须通过内部测试的 opt-in链接安装,而非侧载。
- 验证网络。企业VPN、 captive portals和部分DNS过滤器会静默阻止RevenueCat API或商店API。在深入排查前尝试切换网络。
- 验证appUserID。如果调用时使用的ID与用户预期不符,权益会显示缺失,因为它们关联到了另一个RC用户。打印
logIn(appUserID)(iOS)或Purchases.shared.appUserID(Android)并确认匹配。Purchases.sharedInstance.appUserID - 重置并重试。卸载应用,重新登录沙盒/测试账户,从正确渠道重新安装,重新启动应用。
3. Dashboard inspection via the RevenueCat MCP
3. 通过RevenueCat MCP检查仪表盘
Use this when steps 3, 4, or 5 above point at dashboard configuration, when the user has no working app yet, or when you need to confirm a fix landed.
Important: The API key may have access to multiple projects. Always call first. If multiple projects are returned, ask the user which to inspect.
list-projects当步骤3、4或5指向仪表盘配置问题,或用户尚无可用应用,或需要确认修复已生效时使用此方法。
重要提示:API密钥可能有权访问多个项目。请先调用。如果返回多个项目,请询问用户要检查哪个。
list-projectsPhase A: gather context
A阶段:收集上下文
- Symptom — "What specifically isn't working? What error messages are you seeing? Which platform (iOS, Android, Web)?"
- User state — "Is this happening for new purchases or existing subscribers? Sandbox or production?"
- 症状 —— “具体哪里不工作?您看到了什么错误信息?哪个平台(iOS、Android、Web)?”
- 用户状态 —— “这是新购买用户还是现有订阅用户遇到的问题?沙盒环境还是生产环境?”
Phase B: systematic diagnosis
B阶段:系统性诊断
Work through this checklist via MCP tools:
通过MCP工具执行以下排查清单:
Check 1: Project overview
检查1:项目概览
list-projects → ask user to select project if multiple
list-apps (with selected project_id)- Verify project exists and apps are present.
list-projects → 若有多个项目,请用户选择
list-apps (传入选中的project_id)- 验证项目存在且应用已配置。
Check 2: Products
检查2:产品
list-products- Products exist for each store item.
- Store identifiers match App Store Connect / Play Console exactly.
- Product types are correct (subscription vs one-time).
- Play Store: using format.
product_id:base_plan_id
list-products- 每个商店商品都对应存在产品。
- 商店标识符与App Store Connect / Play Console完全匹配。
- 产品类型正确(订阅型 vs 一次性)。
- Google Play:使用格式。
product_id:base_plan_id
Check 3: Entitlements
检查3:Entitlements
list-entitlements
get-products-from-entitlement (for each entitlement)- Entitlements exist for each access level.
- Products are attached to entitlements.
- No orphaned products (products not granting any entitlement).
list-entitlements
get-products-from-entitlement (针对每个entitlement)- 每个访问级别都对应存在entitlements。
- 产品已关联到entitlements。
- 无孤立产品(未关联任何entitlement的产品)。
Check 4: Offerings
检查4:Offerings
list-offerings
list-packages- At least one offering exists with .
is_current: true - Packages contain products.
- Package identifiers use standard conventions (, etc.).
$rc_monthly
list-offerings
list-packages- 至少存在一个的offerings。
is_current: true - 套餐包含产品。
- 套餐标识符使用标准命名规范(如)。
$rc_monthly
Check 5: Webhooks (if server-side issues suspected)
检查5:Webhooks(若怀疑服务器端问题)
list-webhook-integrations- Webhook URL is correct and accessible.
- Environment matches (production vs sandbox).
list-webhook-integrations- Webhook URL正确且可访问。
- 环境匹配(生产 vs 沙盒)。
Phase C: report and offer fixes
C阶段:生成报告并提供修复方案
Diagnostic Report
=================
Project: {project_name}
Checks Passed: ✅
- Project exists and is accessible
- 2 apps configured (iOS, Android)
- 4 products found
Issues Found: ⚠️
1. CRITICAL: Product not attached to entitlement
Product: annual_premium (prod123)
Fix: Attach this product to an entitlement
2. WARNING: Offering has empty package
Offering: default / Package: $rc_annual has no products
Fix: Attach annual_premium to this package
3. INFO: No webhook configured
Optional but recommended for server-side access control
Recommended Actions:
1. Attach annual_premium to "premium" entitlement
2. Attach annual_premium to $rc_annual package
Would you like me to fix issues #1 and #2 now?For each fixable issue, confirm with the user, then execute via MCP:
attach-products-to-entitlementattach-products-to-package
诊断报告
=================
项目:{project_name}
已通过检查:✅
- 项目存在且可访问
- 已配置2个应用(iOS、Android)
- 已找到4个产品
发现问题:⚠️
1. 严重:产品未关联到entitlement
产品:annual_premium (prod123)
修复方案:将此产品关联到一个entitlement
2. 警告:Offerings包含空套餐
Offering:default / 套餐:$rc_annual 无关联产品
修复方案:将annual_premium关联到此套餐
3. 信息:未配置Webhook
可选但推荐配置,用于服务器端访问控制
建议操作:
1. 将annual_premium关联到“premium” entitlement
2. 将annual_premium关联到$rc_annual套餐
是否需要我立即修复问题1和2?对于每个可修复的问题,先与用户确认,再通过MCP执行:
attach-products-to-entitlementattach-products-to-package
4. Platform specific step
4. 平台特定步骤
Read the platform file that matches detection. Each one lists platform specific gotchas not covered above (StoreKit configuration files, Gradle/desugaring, Metro caching, Expo prebuild, etc.).
platforms/ios.mdplatforms/android.mdplatforms/kmp.mdplatforms/flutter.mdplatforms/react-native.md
查看与检测结果匹配的平台文档。每个文档都列出了上述未覆盖的平台特定陷阱(如StoreKit配置文件、Gradle/脱糖、Metro缓存、Expo预构建等)。
platforms/ios.mdplatforms/android.mdplatforms/kmp.mdplatforms/flutter.mdplatforms/react-native.md
5. Verify the fix
5. 验证修复效果
Do not declare the issue fixed until:
- The log that previously showed the error now shows the expected success line (offerings returned with at least one package, purchase completed, entitlement active).
- The dashboard reflects the change. For a purchase, check the Sandbox view on the Customers page and confirm the transaction is attached to the right .
appUserID - The reproduction steps from the original report now pass.
If the user cannot reproduce locally, have them send the full debug log from app launch to the moment of failure. The SDK's own output is usually enough.
满足以下条件后才可确认问题已修复:
- 之前显示错误的日志现在显示预期的成功信息(返回至少一个套餐的offerings、购买完成、entitlement激活)。
- 仪表盘已反映出更改。对于购买问题,查看客户页面的沙盒视图,确认交易已关联到正确的。
appUserID - 原报告中的复现步骤现在可正常执行。
如果用户无法在本地复现修复效果,请他们发送从应用启动到失败时刻的完整调试日志。SDK自身的输出通常已足够。
Reference: SDK error codes
参考:SDK错误码
Common errors
常见错误
| Error code | Likely cause | Solution |
|---|---|---|
| Reserved characters or empty string | Use alphanumeric IDs, underscores, hyphens only |
| Wrong API key or bundle ID mismatch | Verify API key matches app |
| No connectivity or firewall | Check network, verify RevenueCat domains allowed |
| Store downtime, config issue, iOS 18.x bug | Check store status, verify config, see Known iOS Issues below |
| Tampered receipt or config error | Verify In-App Purchase Key (iOS) or service credentials |
| 错误代码 | 可能原因 | 解决方案 |
|---|---|---|
| 使用保留字符或空字符串 | 仅使用字母数字、下划线、连字符作为ID |
| API密钥错误或Bundle ID不匹配 | 验证API密钥与应用匹配 |
| 无网络连接或防火墙拦截 | 检查网络,确认RevenueCat域名已被允许 |
| 商店宕机、配置问题、iOS 18.x bug | 检查商店状态,验证配置,查看下方的已知iOS问题 |
| 收据被篡改或配置错误 | 验证内购密钥(iOS)或服务凭证 |
Purchase errors
购买错误
| Error code | Solution |
|---|---|
| Call |
| Verify product status in App Store Connect / Play Console |
| Check parental controls, payment method |
| Call |
| 错误代码 | 解决方案 |
|---|---|
| 调用 |
| 验证产品在App Store Connect / Play Console中的状态 |
| 检查家长控制设置、支付方式 |
| 调用 |
Reference: debug log interpretation
参考:调试日志解读
Ask the developer to enable debug logging:
- iOS:
Purchases.logLevel = .debug - Android:
Purchases.logLevel = LogLevel.DEBUG
Log emoji indicators: 🍎 Apple/StoreKit · 🤖 Google Play · 📦 Amazon · 😿 RevenueCat backend.
请开发者开启调试日志:
- iOS:
Purchases.logLevel = .debug - Android:
Purchases.logLevel = LogLevel.DEBUG
日志表情标识:🍎 Apple/StoreKit · 🤖 Google Play · 📦 Amazon · 😿 RevenueCat后端。
Reference: known platform issues
参考:已知平台问题
iOS
iOS
iOS 18.0–18.3.2: StoreKit Daemon Connection Failure
- Symptom: (NSCocoaErrorDomain Code 4097) on ~25% of purchases on physical devices.
STORE_PROBLEM - Fix: Upgrade to iOS 18.4+.
iOS 18.4–18.5 Simulator: Products Don't Load
- Symptom: Products return empty in simulator with sandbox.
- Affected: Simulator only — physical devices and production unaffected.
- Fix: Test on physical device, or use Xcode 26+ with iOS 26+ simulators.
iOS 18.0–18.3.2: StoreKit守护进程连接失败
- 症状:约25%的物理设备购买会出现(NSCocoaErrorDomain Code 4097)错误。
STORE_PROBLEM - 修复方案:升级至iOS 18.4+。
iOS 18.4–18.5模拟器:产品无法加载
- 症状:沙盒环境下模拟器中产品返回为空。
- 影响范围:仅模拟器——物理设备和生产环境不受影响。
- 修复方案:在物理设备上测试,或使用Xcode 26+搭配iOS 26+模拟器。
Android
Android
ProxyBillingActivity NullPointerException
- Typically from automated testing or Play Store pre-launch reports on LG Nexus 5X / rooted devices.
- Safe to ignore/silence in crash reporting tools.
NoCoreLibraryDesugaringException / NoClassDefFoundError
- Fix: Enable core library desugaring in or raise
build.gradle.minSdk
ProxyBillingActivity空指针异常
- 通常出现在LG Nexus 5X / 已root设备的自动化测试或Play Store预发布报告中。
- 可在崩溃报告工具中忽略或屏蔽此异常。
NoCoreLibraryDesugaringException / NoClassDefFoundError
- 修复方案:在中启用核心库脱糖,或提高
build.gradle版本。minSdk
Reference: platform configuration checklists
参考:平台配置检查清单
iOS
iOS
- Paid Applications agreement signed in App Store Connect.
- In-App Purchase Key uploaded to RevenueCat (StoreKit 2 / SDK 5.x+).
- Products show "Ready to Submit" or "Approved" status.
- Bundle ID matches exactly in Xcode, App Store Connect, and RevenueCat.
- New products: wait 24h for propagation.
- 在App Store Connect中签署了付费应用协议。
- 将内购密钥上传至RevenueCat(StoreKit 2 / SDK 5.x+)。
- 产品状态显示为“Ready to Submit”或“Approved”。
- Bundle ID在Xcode、App Store Connect和RevenueCat中完全匹配。
- 新产品:等待24小时以完成同步。
Android
Android
- App published to at least closed testing track (internal testing won't work).
- Test account added as licensed tester in Play Console.
- Service account credentials (JSON) uploaded to RevenueCat with Finance permissions.
- Subscriptions use format.
product_id:base_plan_id - New products: wait 24h for propagation.
- 应用至少发布至封闭测试轨道(内部测试无效)。
- 测试账户已添加至Play Console的许可测试列表。
- 将服务账户凭证(JSON)上传至RevenueCat并授予财务权限。
- 订阅使用格式。
product_id:base_plan_id - 新产品:等待24小时以完成同步。
Reference: App Store rejection troubleshooting
参考:App Store审核拒绝排查
"Issues fetching products" — Products must be submitted for review with the app on first submission. Create products in App Store Connect, then submit app and products together.
"Error during purchase" (Sandbox) — Apple sandbox downtime. Inform reviewer, provide RevenueCat sandbox dashboard screenshot showing test purchases work, ask to retry.
"Content not unlocked after purchase" — Verify product → entitlement connection in RevenueCat. Ensure app calls after purchase.
getCustomerInfo()“获取产品时出现问题” —— 首次提交应用时,产品必须与应用一同提交审核。在App Store Connect中创建产品,然后将应用和产品一起提交。
“购买过程中出错”(沙盒环境) —— Apple沙盒服务宕机。告知审核人员,提供RevenueCat沙盒仪表盘截图证明测试购买正常,请求重试。
“购买后内容未解锁” —— 验证RevenueCat中产品与entitlement的关联。确保应用在购买后调用。
getCustomerInfo()Reference: common issues
参考:常见问题
User purchased but has no entitlement — Check product → entitlement attachment and verify store identifier matches exactly.
Offering returns empty — Verify a offering exists, packages have products attached, and products exist in the app's store.
currentWebhook not receiving events — Verify URL is internet-accessible and returns 200 OK. Test with webhook.site.
Subscription status out of sync — SDK caches for 5 min (foreground). Force refresh:
CustomerInfoswift
// iOS
Purchases.shared.getCustomerInfo(fetchPolicy: .fetchCurrent) { ... }kotlin
// Android
Purchases.sharedInstance.getCustomerInfoWith(CacheFetchPolicy.FETCH_CURRENT) { ... }SDK crashes on launch (iOS / Xcode 26) — Initialize RevenueCat before other networking libraries.
SDK crashes on launch (Android) — Enable core library desugaring or raise to 24+.
minSdk用户已购买但无entitlement —— 检查产品与entitlement的关联,验证商店标识符完全匹配。
Offering返回为空 —— 验证存在状态的offerings,套餐已关联产品,且产品在应用对应的商店中存在。
currentWebhook未接收事件 —— 验证URL可通过互联网访问且返回200 OK。使用webhook.site进行测试。
订阅状态不同步 —— SDK在前台会缓存5分钟。强制刷新:
CustomerInfoswift
// iOS
Purchases.shared.getCustomerInfo(fetchPolicy: .fetchCurrent) { ... }kotlin
// Android
Purchases.sharedInstance.getCustomerInfoWith(CacheFetchPolicy.FETCH_CURRENT) { ... }SDK启动时崩溃(iOS / Xcode 26) —— 在其他网络库之前初始化RevenueCat。
SDK启动时崩溃(Android) —— 启用核心库脱糖或将提高至24+。
minSdk