Apphud + web2wave integration

Grant and revoke Apphud access automatically when a web2wave subscription changes.

🤖

Integrate with an AI coding agent — Cursor, Claude Code, Codex, Windsurf and others.

Open your mobile app project in the agent, paste the prompt below, and answer its questions. The agent reads the web2wave mobile integration playbook, detects your subscription provider and attribution tool, and does the integration step by step.

You are integrating web2wave into this mobile app.

1. Read the web2wave mobile integration playbook and follow it end to end:
   https://raw.githubusercontent.com/web2wave/integration-skills/main/docs/web2wave-mobile-integration-playbook.md
   (Docs index for agents: https://docs.web2wave.com/llms.txt)

2. First inspect this project: the platform (iOS, Android, Flutter, React Native, Unity),
   the subscription provider (RevenueCat, Adapty, Qonversion, Apphud, Superwall) and the
   attribution tool (AppsFlyer, Adjust, Branch). Show me what you found and ask me to confirm.

3. Ask me every question the playbook lists, in its order. Do not guess settings or secrets.
   Never hardcode API keys: ask me for my web2wave API key and keep it in config / env.

4. Implement only the branch we agreed on. Use the web2wave SDK for this platform and take
   code samples from the documentation pages the playbook links to.

5. At the end, list the web2wave project settings I still have to fill in, and run or
   describe the acceptance tests from the playbook.

Where to paste it: the chat or agent panel in Cursor and Windsurf, the terminal session in Claude Code and Codex. You can also save the playbook as a project skill or instructions file and keep the prompt short.

web2wave can sync web subscriptions to Apphud. When a user buys, renews, cancels or is refunded on web, web2wave grants or revokes promotional access to the matching Apphud user via the Apphud API. The user then gets premium inside your app through your regular Apphud checks.

How it works

  1. The user pays on web (quiz / paywall).
  2. Your app tells web2wave which Apphud user this is — by sending the apphud_profile_id user property.
  3. web2wave calls Apphud:
    • subscription active, trialing or past due → grant promotional access until the next charge date;
    • subscription canceled, expired, refunded, etc. → revoke promotional access.

Every sync is written to the user's event log (apphud_access_granted, apphud_access_revoked, apphud_access_grant_failed, …), so you can see what happened per user.

Note: web2wave does not create Apphud users. The user must already exist in Apphud (your app has to start the Apphud SDK, or call updateUserID, before the ID is sent to web2wave).

Step 1. Add Apphud settings to your web2wave project

Open Project settings → Deeplinks (the Apphud block), enable Synchronize subscriptions with Apphud and fill in:

  • Apphud API Key — the secret server-to-server key from your Apphud dashboard (App Settings → Authentication center). Keep it private: it is used by web2wave on the server only and must never be shipped in the app.
  • Apphud Product ID — the Apphud product that represents your premium access (for example premium.yearly). If your app has several permission groups, use the product from the group you want to unlock. You can enter several products separated by commas.

Per-price overrides

Different plans can unlock different products. Open a price and fill Custom Apphud Product IDs:

FieldUsed when
Apphud Product ID Androidthe user's platform is Android
Apphud Product ID IOSthe user's platform is iOS
Apphud Product IDany other case

Priority: platform field of the price → price field → project setting. Leave a field empty to fall back to the next level.

Step 2. Send the Apphud user ID to web2wave

web2wave needs to know which Apphud user to unlock. There are two ways; use whichever fits your flow.

Option A. Send it after install

If the user buys on web first and installs the app later, resolve the web2wave user_id from the deeplink (see Pass subscription from web to app or deferred deeplinks) and send the Apphud user ID with the API:

curl -X POST "https://api.web2wave.com/api/user/properties?user=WEB2WAVE_USER_ID" \
  -H "api_key: YOUR_WEB2WAVE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"property": "apphud_profile_id", "value": "APPHUD_USER_ID"}'

As soon as the property is saved, web2wave syncs the user's active subscriptions to Apphud — no extra call is needed.

Or use the web2wave SDK — read the Apphud user ID after the web2wave user_id is resolved from the deeplink, and send it with setApphudProfileID:

import ApphudSDK
import Web2Wave

func sendApphudUserIDToWeb2Wave(web2waveUserId: String) async {
    Web2Wave.shared.apiKey = "your-api-key"

    let apphudUserID = Apphud.userID() // Apphud user ID

    switch await Web2Wave.shared.setApphudProfileID(
        web2waveUserId: web2waveUserId,
        apphudProfileID: apphudUserID
    ) {
    case .success: print("Successfully sent Apphud ID to Web2Wave API")
    case .failure(let error): print("Error sending data to Web2Wave API: \(error)")
    }
}
import com.apphud.sdk.Apphud
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import web2wave.Web2Wave

private val scope = CoroutineScope(Dispatchers.IO)

fun sendApphudUserIDToWeb2Wave(web2waveUserId: String) {
    Web2Wave.initWith("YOUR_API_KEY_TO_WEB2WAVE")

    val apphudUserID = Apphud.userId() // Apphud user ID

    scope.launch {
        Web2Wave.setApphudProfileID(web2waveUserId, apphudUserID)
    }
}
import 'package:apphud/apphud.dart';
import 'package:web2wave/web2wave.dart';

Future<void> sendApphudUserIDToWeb2Wave(String web2waveUserId) async {
  Web2Wave.shared.initialize(apiKey: 'your-api-key');

  final apphudUserID = await Apphud.userID(); // Apphud user ID

  final result = await Web2Wave.shared.setApphudProfileID(
    web2waveUserId: web2waveUserId,
    apphudProfileId: apphudUserID,
  );

  if (result.isSuccess) {
    print('Successfully sent Apphud ID to Web2Wave API');
  } else {
    print('Error sending data to Web2Wave API: ${result.errorMessage}');
  }
}

SDK methods setApphudProfileID (Unity: SetApphudProfileID) are available in: Swift 1.2.0+, Kotlin 1.2.0+, Java 1.2.0+, Flutter 1.1.11+, React Native 1.4.0+, Unity 1.3.0+. See the mobile SDK overview.

Option B. Pass it in the WebView URL

If you open the quiz or paywall inside your app, add the ID as a query parameter:

https://yourdomain.com/quiz-slug?apphud_profile_id=APPHUD_USER_ID

See Embed quizzes and paywalls into mobile apps. URL-encode the value if it contains special characters.

Step 3. Access appears in Apphud

After the sync, the user has a subscription with status promo for your product in the Apphud dashboard, and Apphud's SDK reports the permission group as active. All later changes — renewals, cancellations, refunds — are reflected automatically.

Good to know

  • Expiration date. Apphud requires a future expiration date, so web2wave sends the next charge date. If it is missing, access is granted for 30 days; if it is already in the past (for example a past-due payment), for 3 days. The next renewal extends it.
  • Renewals. Apphud may refuse to extend an existing promo with a new date. In that case web2wave deletes the current promo and creates a new one with the later date.
  • Revoking. If there is nothing to revoke (user or promo not found), the sync is skipped without an error.
  • Retries. Temporary API failures are retried automatically; failed attempts are visible in the user's event log.
  • No apphud_profile_id, no sync. Users without this property are skipped.