Placeholder product IDs like com.example.app.monthly or counts that do not match the paywall UI mean purchases fail at the store layer before revenue is ever collected. The StoreKit or Play Billing call returns an unknown-product error, the paywall renders a broken CTA, and every install that reaches the purchase screen churns out with zero attribution. This is pure reference-integrity and placeholder-hygiene failure — the code and the App Store Connect / Play Console records must agree exactly or the integration is dead on arrival.
High because placeholder or mismatched IDs silently break every purchase attempt, destroying conversion before any revenue lands.
Replace every placeholder identifier with the exact reverse-domain IDs created in App Store Connect or the Play Console, and centralize them so the paywall UI and purchase calls cannot drift apart:
// src/constants/iap.ts
export const PRODUCT_IDS = {
MONTHLY: 'com.yourcompany.yourapp.monthly',
ANNUAL: 'com.yourcompany.yourapp.annual',
} as const;
For RevenueCat, manage products in the dashboard and reference entitlement identifiers (premium, pro_monthly) in code — never hardcode store-level product IDs when an SDK is fetching offerings.
app-store-iap-subscriptions.iap-integration.product-idshighios.bundleIdentifier in app.json or CFBundleIdentifier in Info.plist) followed by a product name. Also search for product ID arrays or constants in constants/iap.ts, config/products.ts, lib/iap/products.dart, or inline in paywall components. Check: (1) Product IDs follow the com.domain.appname.product pattern on iOS (required). (2) The number of product IDs in the code matches what you'd expect given the paywall UI (e.g., if the paywall shows Monthly, Annual, and Lifetime, there should be 3 product IDs). (3) Product IDs are not left as template placeholders: YOUR_PRODUCT_ID, com.example.app.monthly, com.yourcompany.app.premium. (4) For RevenueCat/Adapty/Qonversion: check that entitlement identifiers (e.g., "premium", "pro_monthly") match the platform SDK's expected string. Look for Purchases.shared.getOfferings() (RevenueCat), Adapty.getPaywall(id:), or Qonversion.shared().offerings() — these fetch remotely configured products, so hardcoded product IDs may not be needed, but entitlement identifiers must still be correct.YOUR_PRODUCT_ID, com.example.*); product ID count does not match paywall UI; product IDs use incorrect format for the target platform."Product ID 'com.example.app.monthly' is a template placeholder in src/constants/iap.ts" or "Paywall shows 3 tiers but only 1 product ID is defined in src/lib/iap/products.ts"com.yourcompany.yourapp.monthly_4_99) exactly as shown// src/constants/iap.ts
export const PRODUCT_IDS = {
MONTHLY: 'com.yourcompany.yourapp.monthly',
ANNUAL: 'com.yourcompany.yourapp.annual',
} as const;