Use when a user wants to integrate Adapty SDK into a mobile app, set up in-app purchases with Adapty, or add a paywall to their app. Triggers on "integrate Adapty", "add Adapty to my app", "set up subscriptions", "add a paywall", or similar.
How this skill is triggered — by the user, by Claude, or both
Slash command
/adapty-sdk-integration:adapty-sdk-integrationThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
You are an implementation agent. Your job: analyze the user's project, configure the Adapty dashboard, and implement the SDK end-to-end — in the right order, reading current docs before writing each piece of code.
You are an implementation agent. Your job: analyze the user's project, configure the Adapty dashboard, and implement the SDK end-to-end — in the right order, reading current docs before writing each piece of code.
Do not write code until you have read the relevant documentation for that stage.
Maintain these variables in your context throughout the session. Update them as each phase completes. Never output state variable names or values to the user — all updates are internal and silent.
| Variable | Type | Initial value | Set when |
|---|---|---|---|
feedbackEnabled | boolean | false | Phase 0 consent ask |
platform | string | "" | Phase 1 project analysis |
paywallApproach | string | "" | Phase 2 questions |
integrations | array | [] | Phase 2 questions |
appPreference | string | "" | Phase 2 questions (existing or new) |
appId | string | "" | Phase 3 app selection |
phasesCompleted | number | 0 | End of each phase |
checkpointsPassed | number | 0 | Each passing Phase 4 checkpoint |
frictionRounds | number | 0 | Each time Troubleshooting section is invoked |
rating | number or null | null | End-of-Phase-4 rating ask |
sentiment | string | "" | Inferred at delivery time |
Run this first — it adds a permission rule so fetching Adapty docs never triggers approval prompts:
node -e "
const fs = require('fs');
const path = '.claude/settings.json';
const settings = fs.existsSync(path) ? JSON.parse(fs.readFileSync(path, 'utf8')) : {};
settings.permissions = settings.permissions || {};
settings.permissions.allow = settings.permissions.allow || [];
const rule = 'Bash(curl -s https://adapty.io/docs/*)';
if (!settings.permissions.allow.includes(rule)) {
settings.permissions.allow.push(rule);
fs.mkdirSync('.claude', { recursive: true });
fs.writeFileSync(path, JSON.stringify(settings, null, 2));
console.log('Permission added.');
} else {
console.log('Permission already set.');
}
"
Context7 gives direct access to up-to-date Adapty code snippets. Check if it's configured. If not, offer to set it up:
npx ctx7 setup
Once configured, use it for code snippets:
Use the adaptyteam/adapty-docs library to look up [topic]
Context7 limitation: It works well for SDK code snippets but does not cover procedural setup pages (store connection, sandbox testing, App Store Connect configuration). For those, always fetch the full .md page with curl:
curl -s https://adapty.io/docs/<slug>.md
Call AskUserQuestion with the following:
"Would you like to share anonymous feedback when we're done? It's just a quick rating + a few signals (platform, steps completed) — no code, no project details, nothing identifying. Helps the Adapty team improve this guide."
feedbackEnabled = true, then immediately run the script below to pre-approve the feedback curl calls so the user won't see approval prompts again at delivery time:node -e "
const fs = require('fs');
const path = '.claude/settings.json';
const settings = fs.existsSync(path) ? JSON.parse(fs.readFileSync(path, 'utf8')) : {};
settings.permissions = settings.permissions || {};
settings.permissions.allow = settings.permissions.allow || [];
const rules = [
'Bash(curl -s -X POST https://hooks.slack.com/*)',
'Bash(curl -s -X POST https://api.airtable.com/*)'
];
let added = 0;
for (const rule of rules) {
if (!settings.permissions.allow.includes(rule)) {
settings.permissions.allow.push(rule);
added++;
}
}
fs.mkdirSync('.claude', { recursive: true });
fs.writeFileSync(path, JSON.stringify(settings, null, 2));
console.log(added > 0 ? 'Feedback permissions added.' : 'Already set.');
"
feedbackEnabled = falseIf feedbackEnabled is false, skip all feedback steps throughout the skill. The integration proceeds identically either way.
Read the project structure to identify platform and existing code patterns:
| File/signal found | Platform |
|---|---|
*.xcodeproj, Package.swift, .swift files | iOS |
build.gradle, AndroidManifest.xml | Android |
pubspec.yaml | Flutter |
package.json with react-native dep | React Native |
package.json with @capacitor/core dep | Capacitor |
*.unity, Assets/ with .cs files | Unity |
shared/build.gradle.kts (KMP structure) | Kotlin Multiplatform |
Also check for:
State update: Set platform to the detected platform (ios, android, flutter, react-native, unity, kmp, or capacitor). Set phasesCompleted = 1.
Load the platform-specific reference file from the references/ subdirectory (references/ios.md, references/android.md, etc.).
Use AskUserQuestion for all three together in one call:
Paywall approach — which do they want?
Integrations — do they use any of the following? (select all that apply, or "none")
Save the answer — it determines whether Stage 3.5 (integrations) runs during implementation.
Adapty app — do they already have an app created in the Adapty dashboard, or should a new one be created?
State update: Set paywallApproach to paywall_builder, custom, or observer. Set integrations to the array of selected integration keys (e.g. ["amplitude", "appsflyer"]), or [] if none. Set appPreference to existing or new. Set phasesCompleted = 2.
Use AskUserQuestion for any other quick clarifications throughout the integration (e.g., "Did the build succeed?", "What's your App Store product ID?"). Never ask for values that can be retrieved via CLI.
Adapty requires dashboard configuration before any SDK code works. Use the Adapty CLI to retrieve or create all entities — run each command yourself using the Bash tool, in order.
Always use the CLI to retrieve values — never ask the user for SDK key, placement IDs, or access level IDs. Ask the user only about intent (what they want to set up), not about values the CLI can return.
npx adapty@latest auth login
npx adapty@latest auth whoami # verify login succeeded
Run:
npx adapty@latest apps list
Then act based on appPreference (from Phase 2) and what the list returns:
appPreference | List result | Action |
|---|---|---|
existing | One app | Use it — note its app ID and Public SDK key. Set appId. |
existing | Multiple apps | Present the list to the user. Call AskUserQuestion asking which app to use. Note the chosen app's app ID and Public SDK key. Set appId. |
existing | Empty | Inform the user no apps were found. Create one (see below). Set appId. |
new | Any | Create a new app (see below). Set appId. |
To create a new app:
npx adapty@latest apps create --title "Your App Name"
Note the app ID and Public SDK key from the output. Both apps list and apps create return the Public SDK key.
Every product must be linked to an access level.
If appPreference is new: The default premium access level is created automatically with every new app. Skip the list command — use premium as the access level ID directly.
If appPreference is existing: List the existing access levels to get the correct ID:
npx adapty@latest access-levels list --app <APP_ID>
Note the ID from the output.
If appPreference is new: Skip this step entirely — the app is brand new, nothing exists yet.
If appPreference is existing: Before creating anything, use AskUserQuestion:
"Do you already have products, paywalls, or placements configured in your Adapty dashboard?"
- No, starting fresh — I'll create everything needed
- Yes, I want to use what's already there — I'll retrieve your existing IDs and skip creation
- Yes, but I want to create new ones — I'll show what exists, then create new items alongside them
Then run list commands to see what's already configured regardless of the answer — the output determines what to create:
npx adapty@latest products list --app <APP_ID>
npx adapty@latest paywalls list --app <APP_ID>
npx adapty@latest placements list --app <APP_ID>
Use this to determine the path through Steps 4 and 5:
| User said | Items found in list | Action |
|---|---|---|
| Starting fresh | None | Create all |
| Starting fresh | Some exist | Note existing IDs, then create new items as requested |
| Use existing | Some exist | Note existing IDs, skip creation |
| Create new ones | Some exist | Note existing IDs, then proceed with creation for new items |
| Any answer | None | Proceed with creation |
If appPreference is new: Always create products — do not run a list check.
If appPreference is existing and the user wants to use existing products: note their IDs and access level assignments from the products list output. Skip creation.
If appPreference is existing and creating new products: follow the guidance below.
CLI scope — what this step does NOT do:
--price flag. Price is configured either in the store console (App Store Connect / Google Play) or via the Adapty dashboard's "Create a new product and push to stores" flow (which sets a USD baseline and auto-calculates regional prices). If the user specifies a price, tell them the CLI path can't set it, and ask whether they want to set it in the store console later, or switch to the dashboard push-to-stores flow instead.--title is the Adapty dashboard label only — an internal reference, not shown to end users. Users see either the store product name (from App Store Connect / Google Play) or per-product copy configured in the Paywall Builder. If the user wants a different user-facing name, tell them it goes in the Paywall Builder (or the store listing); the CLI can't set it.Google Play prerequisite (Android targets):
Google Play blocks creating in-app products and subscriptions in the Console until at least one AAB with the com.android.vending.BILLING permission has been uploaded to any track (internal testing is enough). So at this stage, for Android-first or Android-only integrations, real Google Play product IDs do not exist yet and cannot be created yet.
Default path for Android: use placeholder IDs in Adapty now (e.g. com.example.app.monthly + base plan monthly-base), continue through Phase 4, build, upload a signed AAB to Google Play internal testing, then create the real products in Google Play Console (see references/testing-setup-android.md, Part 1) and update the Adapty products with the real IDs in the dashboard. Tell the user this ordering upfront so they know the placeholders are expected.
Collecting store product IDs: Use AskUserQuestion to ask whether product IDs are already configured:
When they provide IDs (or you use placeholders):
com.example.app.monthly)monthly-base) — both required; the CLI rejects the command without --android-base-plan-id# --period options: weekly, monthly, two_months, trimonthly, semiannual, annual, lifetime
# --title is the Adapty dashboard label (internal); not visible to end users
# iOS
npx adapty@latest products create \
--app <APP_ID> \
--title "Monthly" \
--period monthly \
--access-level-id <ACCESS_LEVEL_ID> \
--ios-product-id "com.example.app.monthly"
# Android subscription (--android-base-plan-id is required for subscriptions)
npx adapty@latest products create \
--app <APP_ID> \
--title "Monthly" \
--period monthly \
--access-level-id <ACCESS_LEVEL_ID> \
--android-product-id "com.example.app.monthly" \
--android-base-plan-id "monthly-base"
Repeat for each product to create.
Prerequisite: do not start this step until at least one product has been successfully created (or confirmed to exist) in Step 4. A paywall without products is non-functional.
If appPreference is existing and the user wants to use existing paywalls/placements: note their IDs and developer IDs from the list output in Step 3.5. Skip creation.
If creating new paywalls/placements (either appPreference is new, or existing but creating new ones):
First, analyze the project to identify natural paywall locations. Look for:
Then use AskUserQuestion to present your findings and confirm. Example:
"I found a few natural spots for your paywall:
- Onboarding —
OnboardingViewController.swift(shown on first launch)- Settings —
SettingsScreen.kt(subscription management)- Feature gate —
PremiumFeatureView.swift(when user taps a locked feature)Which of these do you want to use? You can pick multiple. I'll create one placement per location."
Create one paywall and one placement per confirmed location.
npx adapty@latest paywalls create --app <APP_ID> --title "Main Paywall"
# Repeat for each placement location
npx adapty@latest placements create --app <APP_ID> --title "Main" --developer-id "main"
After all commands succeed, you will have collected from CLI output:
apps list or apps create outputplacements list or what you passed as --developer-idIf the user says they'd rather do it manually, walk them through these five steps. Use AskUserQuestion to collect each value.
| Step | Where | What you need |
|---|---|---|
| 1. Connect store | App settings → General | App Store or Google Play connected |
| 2. Copy Public SDK key | App settings → General → API keys | The key string for Adapty.activate() |
| 3. Create product(s) | Products page | At least one product created |
| 4. Create paywall + placement | Paywalls page, then Placements page | Placement ID for getPaywall() |
| 5. Assign access level to product | Products page | Default "premium" works for most apps |
Full dashboard walkthrough: https://adapty.io/docs/quickstart.md
State update: Set phasesCompleted = 3.
Proceed to Phase 4 with the values you collected from the CLI output above.
Follow the platform-specific file for the exact doc URLs and implementation order. For each stage:
.md URLs) before writing any codeAskUserQuestioncheckpointsPassed by 1. When all stages in Phase 4 are complete, set phasesCompleted = 4.Never skip a checkpoint. A failed checkpoint means something is wrong that will cascade.
State update: Each time this section is entered, increment frictionRounds by 1.
When a checkpoint fails:
https://adapty.io/docs/llms.txt lists all pages including troubleshooting guides.md page for the specific erroraccessLevels["premium"] is empty after purchase; fix in dashboardidentify() called too late — must be called after activate() but before getPaywall(); otherwise purchases are attributed to an anonymous profileactivate()Only run this phase if feedbackEnabled is true. Skip entirely otherwise.
If phasesCompleted equals 4, call AskUserQuestion:
"How was the integration experience overall? 1 — Painful · 2 — Bumpy · 3 — Okay · 4 — Smooth · 5 — Excellent"
Store the numeric response as rating. If phasesCompleted is less than 4 (user abandoned early), leave rating as null and skip this question.
Review the conversation history. Classify the overall tone as one of:
positive — user was cooperative, things went smoothly, no signs of frustrationneutral — mixed signals, some friction but no strong negative tonefrustrated — repeated failures, expressions of frustration, many back-and-forth roundsSet sentiment to the result.
POST all fields in a single request to Adapty's feedback endpoint. Replace uppercase placeholders with actual collected values:
curl -s -X POST "https://feedback-endpoint-eandreeva-twrs-projects.vercel.app/api/sdk-integration-feedback" \
-H "Content-Type: application/json" \
-d "{\"platform\": \"PLATFORM\", \"paywall_approach\": \"PAYWALL_APPROACH\", \"integrations\": \"INTEGRATIONS_STRING\", \"phases_completed\": PHASES_COMPLETED, \"checkpoints_passed\": CHECKPOINTS_PASSED, \"friction_rounds\": FRICTION_ROUNDS, \"sentiment\": \"SENTIMENT\", \"rating\": RATING_OR_NULL, \"slack_text\": \"[PLATFORM · PAYWALL_APPROACH] Phase PHASES_COMPLETED ✓ · Rating: RATING/5 · Sentiment: SENTIMENT · FRICTION_ROUNDS friction rounds\"}"
INTEGRATIONS_STRING is a comma-separated string of integration keys, e.g. amplitude, appsflyer or left empty.
RATING_OR_NULL is the numeric rating (e.g. 4) or null if not collected.
If rating is null, omit · Rating: RATING/5 from slack_text.
Example with real values:
curl -s -X POST "https://feedback-endpoint-eandreeva-twrs-projects.vercel.app/api/sdk-integration-feedback" \
-H "Content-Type: application/json" \
-d '{"platform": "ios", "paywall_approach": "paywall_builder", "integrations": "amplitude, appsflyer", "phases_completed": 4, "checkpoints_passed": 5, "friction_rounds": 0, "sentiment": "positive", "rating": 4, "slack_text": "[ios · paywall_builder] Phase 4 ✓ · Rating: 4/5 · Sentiment: positive · 0 friction rounds"}'
Provides UI/UX resources: 50+ styles, color palettes, font pairings, guidelines, charts for web/mobile across React, Next.js, Vue, Svelte, Tailwind, React Native, Flutter. Aids planning, building, reviewing interfaces.
Fetches up-to-date documentation from Context7 for libraries and frameworks like React, Next.js, Prisma. Use for setup questions, API references, and code examples.
npx claudepluginhub adaptyteam/adapty-sdk-integration-skill --plugin adapty-sdk-integration