API Reference

Embedding Quizzes and Paywalls into Mobile Apps

This guide provides step-by-step instructions for integrating Web2Wave quizzes and paywalls into your mobile applications using our native SDKs. Web2Wave offers SDKs for iOS (Swift), Android (Kotlin), Android (Java), and Flutter.

Overview

Web2Wave allows you to embed quizzes and paywalls directly into your mobile app using WebView components. The SDKs handle all communication between your app and the Web2Wave web content, including event handling, navigation, and user interactions.

What You'll Need

  • A Web2Wave project with at least one quiz or paywall
  • Your quiz/paywall URL (format: https://yourdomain.com/quiz-slug or https://yourdomain.com/paywall/paywall-slug)
  • A mobile development environment set up for your target platform

Getting Your Quiz/Paywall URL

  1. Navigate to your quiz or paywall editor in the Web2Wave dashboard
  2. Click on the Publish button dropdown menu
  3. Select Embed into mobile app
  4. Copy the URL displayed in the modal (e.g., https://yourdomain.com/quiz-slug)


Quick Links to SDKs

Payment Synchronization with Third-Party Systems

Web2Wave supports synchronizing user payments with third-party subscription management platforms (RevenueCat, Adapty, Qonversion). This ensures that all purchases made through Web2Wave are automatically reflected in your chosen subscription management system.

How It Works

You can pass profile IDs as URL parameters when opening a quiz or paywall. When these parameters are present, Web2Wave will automatically sync all payment transactions for that user to the corresponding third-party system.

Supported Parameters

  • revenuecat_profile_id - RevenueCat user profile ID
  • adapty_profile_id - Adapty user profile ID
  • qonversion_profile_id - Qonversion user profile ID

Prerequisites

  • The corresponding third-party system must be configured in your Project settings in the Web2Wave dashboard
  • You need to obtain the profile ID from the third-party SDK before opening the WebView

URL Format

Append the profile ID parameter to your quiz or paywall URL:

https://yourdomain.com/quiz-slug?adapty_profile_id=USER_PROFILE_ID
https://yourdomain.com/paywall-slug?revenuecat_profile_id=USER_PROFILE_ID
https://yourdomain.com/quiz-slug?qonversion_profile_id=USER_PROFILE_ID

You can also combine multiple parameters if needed:

https://yourdomain.com/quiz-slug?adapty_profile_id=USER_ID&revenuecat_profile_id=USER_ID

Important Notes:

  • If a user completes a purchase in the WebView, the subscription will be automatically synchronized to the third-party system specified by the profile ID parameter(s).
  • Make sure to URL-encode the profile ID if it contains special characters. Most SDKs and URL construction libraries handle this automatically.
  • The profile ID must be obtained from the third-party SDK (Adapty, RevenueCat, or Qonversion) before opening the WebView.

iOS (Swift)

Installation

Using Swift Package Manager

  1. In Xcode, go to File > Add Packages...
  2. Enter the repository URL: https://github.com/web2wave/web2wave_swift.git
  3. Select the version (recommended: latest)
  4. Add the package to your target

Using CocoaPods

Add to your Podfile:

pod 'Web2Wave'

Then run:

pod install

Setup

  1. Import the SDK in your Swift file:
import Web2Wave

Basic Usage - Opening a Quiz or Paywall

To open a quiz or paywall, you need to:

  1. Make your view controller conform to the Web2WaveWebListener protocol
  2. Implement the required protocol methods to handle events
  3. Pass self as the delegate parameter when opening the WebView

Here's a complete example:

import UIKit
import Web2Wave

// 1. Make your view controller conform to Web2WaveWebListener
class ViewController: UIViewController, Web2WaveWebListener {
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    @IBAction func openQuizButtonTapped(_ sender: UIButton) {
        // Your quiz or paywall URL
        var quizURL = "https://yourdomain.com/quiz-slug"
        
        // Optional: Add profile ID for payment synchronization with third-party systems
        // Replace getAdaptyProfileID() with actual method to get profile ID from Adapty SDK
        if let adaptyProfileID = getAdaptyProfileID() {
            // Use URLComponents for proper URL encoding
            var components = URLComponents(string: quizURL)
            components?.queryItems = [URLQueryItem(name: "adapty_profile_id", value: adaptyProfileID)]
            quizURL = components?.url?.absoluteString ?? quizURL
        }
        // Similarly for RevenueCat:
        // if let revenueCatProfileID = getRevenueCatProfileID() {
        //     var components = URLComponents(string: quizURL)
        //     components?.queryItems?.append(URLQueryItem(name: "revenuecat_profile_id", value: revenueCatProfileID))
        //     quizURL = components?.url?.absoluteString ?? quizURL
        // }
        // Or Qonversion:
        // if let qonversionProfileID = getQonversionProfileID() {
        //     var components = URLComponents(string: quizURL)
        //     components?.queryItems?.append(URLQueryItem(name: "qonversion_profile_id", value: qonversionProfileID))
        //     quizURL = components?.url?.absoluteString ?? quizURL
        // }
        
        // 2. Open the WebView and pass self as delegate
        // The SDK will automatically call your protocol methods when events occur
        Web2Wave.shared.showWebView(
            currentVC: self,
            urlString: quizURL,
            topOffset: 0,           // Optional: Adjust for status bar/navigation bar
            bottomOffset: 0,         // Optional: Adjust for tab bar
            delegate: self,          // Pass self - your view controller implements Web2WaveWebListener
            backgroundColor: UIColor.white  // Optional: Background color (defaults to white if not provided)
        )
    }
    
    // MARK: - Web2WaveWebListener Protocol Methods
    
    // Called when any event occurs in the quiz/paywall
    func onEvent(event: String, data: [String : Any]?) {
        print("Event received: \(event)")
        print("Data: \(data ?? [:])")
        
        // Handle specific events
        switch event {
        case "Quiz finished":
            // User completed the quiz
            print("User finished the quiz")
        case "Subscribe":
            // User started a subscription or trial
            if let currency = data?["currency"] as? String,
               let value = data?["value"] as? String {
                print("Subscription started: \(value) \(currency)")
            }
        case "Purchase":
            // User completed a purchase
            if let currency = data?["currency"] as? String,
               let value = data?["value"] as? String {
                print("Purchase completed: \(value) \(currency)")
            }
        case "InitiateCheckout":
            // User initiated checkout process
            print("Checkout initiated")
        case "CompleteRegistration":
            // User reached the paywall page
            print("User reached paywall")
        case "AddPaymentInfo":
            // User submitted payment information
            print("Payment info added")
        default:
            // Handle other events (e.g., "Step 0 Welcome", "Answer Question 1", "Paywall click", etc.)
            print("Other event: \(event)")
            break
        }
    }
    
    // Called when the quiz is completed
    func onQuizFinished(data: [String : Any]?) {
        print("Quiz finished!")
        print("Result data: \(data ?? [:])")
        
        // Close the WebView
        Web2Wave.shared.closeWebView(currentVC: self)
        
        // Handle quiz completion (e.g., navigate to results screen)
        handleQuizCompletion(data: data)
    }
    
    // Called when the WebView should be closed
    func onClose(data: [String : Any]?) {
        print("WebView closed")
        print("Data: \(data ?? [:])")
        
        // Close the WebView
        Web2Wave.shared.closeWebView(currentVC: self)
        
        // Return to previous screen or handle navigation
    }
    
    func handleQuizCompletion(data: [String : Any]?) {
        // Your custom logic here
        // e.g., navigate to results screen, update user properties, etc.
    }
}

How it works:

  1. When you pass delegate: self in showWebView, the SDK stores a reference to your view controller
  2. When events occur in the WebView (quiz finished, screen changed, etc.), the SDK automatically calls the corresponding protocol methods (onQuizFinished, onEvent, onClose) on your delegate
  3. You don't need to manually connect or register the listener—it's all handled automatically when you pass self as the delegate

Alternative: Using an Extension

You can also implement the protocol methods in an extension to keep your code organized:

class ViewController: UIViewController {
    // ... your view controller code ...
    
    @IBAction func openQuizButtonTapped(_ sender: UIButton) {
        var quizURL = "https://yourdomain.com/quiz-slug"
        
        // Optional: Add profile ID for payment synchronization
        if let adaptyProfileID = getAdaptyProfileID() {
            var components = URLComponents(string: quizURL)
            components?.queryItems = [URLQueryItem(name: "adapty_profile_id", value: adaptyProfileID)]
            quizURL = components?.url?.absoluteString ?? quizURL
        }
        
        Web2Wave.shared.showWebView(
            currentVC: self,
            urlString: quizURL,
            topOffset: 0,
            bottomOffset: 0,
            delegate: self,
            backgroundColor: UIColor.white  // Optional: Background color
        )
    }
}

// Extension to implement Web2WaveWebListener protocol
extension ViewController: Web2WaveWebListener {
    func onEvent(event: String, data: [String : Any]?) {
        // Handle events
    }
    
    func onQuizFinished(data: [String : Any]?) {
        // Handle quiz completion
        Web2Wave.shared.closeWebView(currentVC: self)
    }
    
    func onClose(data: [String : Any]?) {
        // Handle close event
        Web2Wave.shared.closeWebView(currentVC: self)
    }
}

Closing the WebView Programmatically

// Close the WebView at any time
Web2Wave.shared.closeWebView(currentVC: self)

Android (Kotlin)

Installation

  1. Add JitPack repository to your project's settings.gradle.kts:
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven { url = uri("https://jitpack.io") }
    }
}
  1. Add the dependency to your app-level build.gradle.kts:
dependencies {
    implementation("com.github.web2wave:web2wave_kotlin:1.0.1")
}

Setup

The SDK is ready to use after adding the dependency. No initialization required for basic WebView functionality.

Basic Usage - Opening a Quiz or Paywall

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.web2wave.Web2Wave
import android.graphics.Color

class MainActivity : AppCompatActivity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        // Your quiz or paywall URL
        var quizURL = "https://yourdomain.com/quiz-slug"
        
        // Optional: Add profile ID for payment synchronization with third-party systems
        // Replace getAdaptyProfileID() with actual method to get profile ID from Adapty SDK
        val adaptyProfileID = getAdaptyProfileID() // Get from Adapty SDK
        if (adaptyProfileID != null) {
            // Use Uri.Builder for proper URL encoding
            val uri = android.net.Uri.parse(quizURL).buildUpon()
            uri.appendQueryParameter("adapty_profile_id", adaptyProfileID)
            quizURL = uri.build().toString()
        }
        // Similarly for RevenueCat:
        // val revenueCatProfileID = getRevenueCatProfileID()
        // if (revenueCatProfileID != null) {
        //     val uri = android.net.Uri.parse(quizURL).buildUpon()
        //     uri.appendQueryParameter("revenuecat_profile_id", revenueCatProfileID)
        //     quizURL = uri.build().toString()
        // }
        // Or Qonversion:
        // val qonversionProfileID = getQonversionProfileID()
        // if (qonversionProfileID != null) {
        //     val uri = android.net.Uri.parse(quizURL).buildUpon()
        //     uri.appendQueryParameter("qonversion_profile_id", qonversionProfileID)
        //     quizURL = uri.build().toString()
        // }
        
        // Create event listener
        val listener = object : Web2WaveWebListener {
            override fun onEvent(event: String, data: Map<String, Any>?) {
                println("onEvent: $event, data: $data")
                
                // Handle specific events
                when (event) {
                    "Quiz finished" -> {
                        // User completed the quiz
                        println("User finished the quiz")
                    }
                    "Subscribe" -> {
                        // User started a subscription or trial
                        val currency = data?.get("currency") as? String
                        val value = data?.get("value") as? String
                        println("Subscription started: $value $currency")
                    }
                    "Purchase" -> {
                        // User completed a purchase
                        val currency = data?.get("currency") as? String
                        val value = data?.get("value") as? String
                        println("Purchase completed: $value $currency")
                    }
                    "InitiateCheckout" -> {
                        // User initiated checkout process
                        println("Checkout initiated")
                    }
                    "CompleteRegistration" -> {
                        // User reached the paywall page
                        println("User reached paywall")
                    }
                    "AddPaymentInfo" -> {
                        // User submitted payment information
                        println("Payment info added")
                    }
                    else -> {
                        // Handle other events (e.g., "Step 0 Welcome", "Answer Question 1", "Paywall click", etc.)
                        println("Other event: $event")
                    }
                }
            }
            
            override fun onClose(data: Map<String, Any>?) {
                println("onClose: data: $data")
                // Close the WebView
                Web2Wave.closeWebView(supportFragmentManager)
            }
            
            override fun onQuizFinished(data: Map<String, Any>?) {
                println("onQuizFinished: data: $data")
                // Close the WebView
                Web2Wave.closeWebView(supportFragmentManager)
                
                // Handle quiz completion
                handleQuizCompletion(data)
            }
        }
        
        // Open the WebView
        Web2Wave.showWebView(
            fragmentManager = supportFragmentManager,
            url = quizURL,
            listener = listener,
            topOffset = 0,                      // Optional: Adjust for status bar/toolbar
            bottomOffset = 0,                    // Optional: Adjust for navigation bar
            backgroundColor = Color.WHITE  // Optional: Background color (defaults to white if not provided)
        )
    }
    
    private fun handleQuizCompletion(data: Map<String, Any>?) {
        // Your custom logic here
    }
}

Event Handling Interface

The SDK requires implementing Web2WaveWebListener:

val listener = object : Web2WaveWebListener {
    override fun onEvent(event: String, data: Map<String, Any>?) {
        // Handle events from the quiz/paywall
    }
    
    override fun onClose(data: Map<String, Any>?) {
        // Called when WebView should be closed
        Web2Wave.closeWebView(supportFragmentManager)
    }
    
    override fun onQuizFinished(data: Map<String, Any>?) {
        // Called when quiz is completed
        Web2Wave.closeWebView(supportFragmentManager)
    }
}

Closing the WebView Programmatically

// Close the WebView at any time
Web2Wave.closeWebView(supportFragmentManager)

Android (Java)

Installation

  1. Add JitPack repository to your project's build.gradle:
allprojects {
    repositories {
        google()
        mavenCentral()
        maven { url 'https://jitpack.io' }
    }
}
  1. Add the dependency to your app-level build.gradle:
dependencies {
    implementation 'com.github.web2wave:web2wave_java:1.0.0'
}

Setup

The SDK is ready to use after adding the dependency. No initialization required for basic WebView functionality.

Basic Usage - Opening a Quiz or Paywall

import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import com.web2wave.sdk.Web2Wave;
import com.web2wave.sdk.Web2WaveWebListener;
import java.util.Map;
import android.graphics.Color;

public class MainActivity extends AppCompatActivity {
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        // Your quiz or paywall URL
        String quizURL = "https://yourdomain.com/quiz-slug";
        
        // Optional: Add profile ID for payment synchronization with third-party systems
        // Replace getAdaptyProfileID() with actual method to get profile ID from Adapty SDK
        String adaptyProfileID = getAdaptyProfileID(); // Get from Adapty SDK
        if (adaptyProfileID != null) {
            // Use Uri.Builder for proper URL encoding
            android.net.Uri.Builder uriBuilder = android.net.Uri.parse(quizURL).buildUpon();
            uriBuilder.appendQueryParameter("adapty_profile_id", adaptyProfileID);
            quizURL = uriBuilder.build().toString();
        }
        // Similarly for RevenueCat:
        // String revenueCatProfileID = getRevenueCatProfileID();
        // if (revenueCatProfileID != null) {
        //     android.net.Uri.Builder uriBuilder = android.net.Uri.parse(quizURL).buildUpon();
        //     uriBuilder.appendQueryParameter("revenuecat_profile_id", revenueCatProfileID);
        //     quizURL = uriBuilder.build().toString();
        // }
        // Or Qonversion:
        // String qonversionProfileID = getQonversionProfileID();
        // if (qonversionProfileID != null) {
        //     android.net.Uri.Builder uriBuilder = android.net.Uri.parse(quizURL).buildUpon();
        //     uriBuilder.appendQueryParameter("qonversion_profile_id", qonversionProfileID);
        //     quizURL = uriBuilder.build().toString();
        // }
        
        // Create event listener
        Web2WaveWebListener listener = new Web2WaveWebListener() {
            @Override
            public void onEvent(String event, Map<String, Object> data) {
                System.out.println("onEvent: " + event + ", data: " + data);
                
                // Handle specific events
                switch (event) {
                    case "Quiz finished":
                        // User completed the quiz
                        System.out.println("User finished the quiz");
                        break;
                    case "Subscribe":
                        // User started a subscription or trial
                        String currency = (String) data.get("currency");
                        String value = (String) data.get("value");
                        System.out.println("Subscription started: " + value + " " + currency);
                        break;
                    case "Purchase":
                        // User completed a purchase
                        String purchaseCurrency = (String) data.get("currency");
                        String purchaseValue = (String) data.get("value");
                        System.out.println("Purchase completed: " + purchaseValue + " " + purchaseCurrency);
                        break;
                    case "InitiateCheckout":
                        // User initiated checkout process
                        System.out.println("Checkout initiated");
                        break;
                    case "CompleteRegistration":
                        // User reached the paywall page
                        System.out.println("User reached paywall");
                        break;
                    case "AddPaymentInfo":
                        // User submitted payment information
                        System.out.println("Payment info added");
                        break;
                    default:
                        // Handle other events (e.g., "Step 0 Welcome", "Answer Question 1", "Paywall click", etc.)
                        System.out.println("Other event: " + event);
                        break;
                }
            }
            
            @Override
            public void onClose(Map<String, Object> data) {
                System.out.println("onClose: data: " + data);
                // Close the WebView
                Web2Wave.closeWebView(getSupportFragmentManager());
            }
            
            @Override
            public void onQuizFinished(Map<String, Object> data) {
                System.out.println("onQuizFinished: data: " + data);
                // Close the WebView
                Web2Wave.closeWebView(getSupportFragmentManager());
                
                // Handle quiz completion
                handleQuizCompletion(data);
            }
        };
        
        // Open the WebView
        Web2Wave.showWebView(
            getSupportFragmentManager(),
            quizURL,
            listener,
            0,                              // topOffset - adjust for status bar/toolbar
            0,                              // bottomOffset - adjust for navigation bar
            Color.WHITE     // backgroundColor - optional (defaults to white if not provided)
        );
    }
    
    private void handleQuizCompletion(Map<String, Object> data) {
        // Your custom logic here
    }
}

Event Handling

Implement the Web2WaveWebListener interface:

Web2WaveWebListener listener = new Web2WaveWebListener() {
    @Override
    public void onEvent(String event, Map<String, Object> data) {
        // Handle events from the quiz/paywall
    }
    
    @Override
    public void onClose(Map<String, Object> data) {
        // Called when WebView should be closed
        Web2Wave.closeWebView(getSupportFragmentManager());
    }
    
    @Override
    public void onQuizFinished(Map<String, Object> data) {
        // Called when quiz is completed
        Web2Wave.closeWebView(getSupportFragmentManager());
    }
};

Closing the WebView Programmatically

// Close the WebView at any time
Web2Wave.closeWebView(getSupportFragmentManager());

Flutter

Installation

  1. Add the Web2Wave package to your pubspec.yaml:
dependencies:
  web2wave:
    git:
      url: https://github.com/web2wave/web2wave_flutter.git
      ref: main
  1. Run:
flutter pub get

Setup

  1. Import the SDK in your Dart file:
import 'package:web2wave/web2wave.dart';

Basic Usage - Opening a Quiz or Paywall

import 'package:flutter/material.dart';
import 'package:web2wave/web2wave.dart';

class QuizScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Quiz'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            _openQuiz(context);
          },
          child: Text('Open Quiz'),
        ),
      ),
    );
  }
  
  void _openQuiz(BuildContext context) async {
    // Your quiz or paywall URL
    var quizURL = 'https://yourdomain.com/quiz-slug';
    
    // Optional: Add profile ID for payment synchronization with third-party systems
    // Replace getAdaptyProfileID() with actual method to get profile ID from Adapty SDK
    final adaptyProfileID = await getAdaptyProfileID(); // Get from Adapty SDK
    if (adaptyProfileID != null) {
      // Use Uri class for proper URL encoding
      final uri = Uri.parse(quizURL);
      quizURL = uri.replace(queryParameters: {
        ...uri.queryParameters,
        'adapty_profile_id': adaptyProfileID,
      }).toString();
    }
    // Similarly for RevenueCat:
    // final revenueCatProfileID = await getRevenueCatProfileID();
    // if (revenueCatProfileID != null) {
    //   final uri = Uri.parse(quizURL);
    //   quizURL = uri.replace(queryParameters: {
    //     ...uri.queryParameters,
    //     'revenuecat_profile_id': revenueCatProfileID,
    //   }).toString();
    // }
    // Or Qonversion:
    // final qonversionProfileID = await getQonversionProfileID();
    // if (qonversionProfileID != null) {
    //   final uri = Uri.parse(quizURL);
    //   quizURL = uri.replace(queryParameters: {
    //     ...uri.queryParameters,
    //     'qonversion_profile_id': qonversionProfileID,
    //   }).toString();
    // }
    
    // Create event listener
    final listener = EventListener();
    
    // Open the WebView
    Web2Wave.shared.openWebPage(
      context: context,
      webPageURL: quizURL,
      allowBackNavigation: true,
      listener: listener,
      backgroundColor: Colors.white,  // Optional: Background color (defaults to white if not provided)
    );
  }
}

// Event listener class
class EventListener extends Web2WaveWebListener {
  @override
  void onEvent({required String event, Map<String, dynamic>? data}) {
    print('onEvent: $event, data: $data');
    
    // Handle specific events
    switch (event) {
      case 'Quiz finished':
        // User completed the quiz
        print('User finished the quiz');
        break;
      case 'Subscribe':
        // User started a subscription or trial
        final currency = data?['currency'];
        final value = data?['value'];
        print('Subscription started: $value $currency');
        break;
      case 'Purchase':
        // User completed a purchase
        final purchaseCurrency = data?['currency'];
        final purchaseValue = data?['value'];
        print('Purchase completed: $purchaseValue $purchaseCurrency');
        break;
      case 'InitiateCheckout':
        // User initiated checkout process
        print('Checkout initiated');
        break;
      case 'CompleteRegistration':
        // User reached the paywall page
        print('User reached paywall');
        break;
      case 'AddPaymentInfo':
        // User submitted payment information
        print('Payment info added');
        break;
      default:
        // Handle other events (e.g., 'Step 0 Welcome', 'Answer Question 1', 'Paywall click', etc.)
        print('Other event: $event');
        break;
    }
  }
  
  @override
  void onClose(Map<String, dynamic>? data) {
    print('onClose: data: $data');
    // Close the WebView
    Web2Wave.shared.closeWebPage();
  }
  
  @override
  void onQuizFinished(Map<String, dynamic>? data) {
    print('onQuizFinished: data: $data');
    // Close the WebView
    Web2Wave.shared.closeWebPage();
    
    // Handle quiz completion
    handleQuizCompletion(data);
  }
  
  void handleQuizCompletion(Map<String, dynamic>? data) {
    // Your custom logic here
  }
}

Event Handling

Extend the Web2WaveWebListener class:

class EventListener extends Web2WaveWebListener {
  @override
  void onEvent({required String event, Map<String, dynamic>? data}) {
    // Handle events from the quiz/paywall
    print('Event: $event');
    print('Data: $data');
  }
  
  @override
  void onClose(Map<String, dynamic>? data) {
    // Called when WebView should be closed
    Web2Wave.shared.closeWebPage();
  }
  
  @override
  void onQuizFinished(Map<String, dynamic>? data) {
    // Called when quiz is completed
    Web2Wave.shared.closeWebPage();
  }
}

Closing the WebView Programmatically

// Close the WebView at any time
Web2Wave.shared.closeWebPage();

Available Events

Web2Wave sends various events during user interactions with quizzes and paywalls. These events are received through the onEvent method of your event listener. Below is a list of common events you can handle:

Quiz Events

  • Quiz finished - Triggered when the user completes the quiz
  • Step {index} {screen_name} - Triggered when a user visits a specific screen (e.g., "Step 0 Welcome", "Step 1 Question")
  • Answer {screen_name} - Triggered when a user answers a question on a specific screen (e.g., "Answer Question 1")

Paywall Events

  • CompleteRegistration - Triggered when the user reaches the paywall page
  • Paywall click - Triggered when a user clicks on the paywall
  • Paywall Prices visible - Triggered when paywall prices are displayed
  • Paywall scroll 1 - Triggered when a user scrolls on the paywall (1% scrolled)
  • Paywall scroll 50 - Triggered when a user scrolls 50% of the paywall

Checkout & Purchase Events

  • InitiateCheckout - Triggered when a user initiates the checkout process
  • AddPaymentInfo - Triggered when a user submits payment information
  • Subscribe - Triggered when a user starts a subscription or trial
    • Properties: currency (e.g., "USD"), value (e.g., "19.99")
  • Purchase - Triggered when a user completes a purchase
    • Properties: currency (e.g., "USD"), value (e.g., "19.99")

Event Data Structure

Events may include additional properties in the data parameter. Common properties include:

{
  "currency": "USD",
  "value": "19.99",
  "price_id": "price_123",
  "subscription_id": "sub_123",
  "quiz_id": "quiz_123",
  "paywall_id": "paywall_123",
  "screen_index": "0",
  "screen_name": "Welcome"
}

For a complete list of all available events and their properties, refer to the Web2Wave Events Documentation.


Best Practices

1. Thread Safety

  • Android: Ensure WebView operations are performed on the main thread
  • iOS: Use completion handlers appropriately for UI updates
  • Flutter: Use async/await for async operations

2. Event Data

The data parameter in event callbacks may be null or empty. Always check before accessing:

// Swift example
func onQuizFinished(data: [String : Any]?) {
    guard let data = data else { return }
    // Use data safely
}

3. Memory Management

  • Close WebViews when they're no longer needed
  • Remove listeners/references when the view is destroyed
  • Use weak references for delegates (iOS) or proper lifecycle management (Android)

4. Offsets

Use topOffset and bottomOffset to account for:

  • Status bars
  • Navigation bars
  • Tab bars
  • Notches/Dynamic Island (iOS)
  • System navigation bars (Android)

Example for iOS with navigation bar:

let topOffset = view.safeAreaInsets.top + navigationController?.navigationBar.frame.height ?? 0
Web2Wave.shared.showWebView(
    currentVC: self,
    urlString: quizURL,
    topOffset: topOffset,
    bottomOffset: 0,
    delegate: self,
    backgroundColor: UIColor.white  // Optional: Background color
)

5. Testing

  • Test with different screen sizes and orientations
  • Test on both iOS and Android devices
  • Test with and without network connectivity
  • Test event callbacks with different quiz/paywall configurations

Troubleshooting

WebView Not Appearing

  1. Check that the URL is correct and accessible
  2. Verify internet connectivity
  3. Check console logs for errors
  4. Ensure you're calling showWebView/openWebPage on the main thread

Events Not Firing

  1. Verify your listener/delegate is properly implemented
  2. Check that all required methods are implemented
  3. Ensure the WebView is not blocked by ad blockers or content blockers

Closing Issues

  1. Ensure you're calling the close method on the correct thread (usually main thread)
  2. Check that the fragment manager/view controller reference is valid
  3. Verify lifecycle is properly managed

API Reference Links


Additional Resources

  • Web2Wave Dashboard: https://app.web2wave.com
  • Support: Contact support through your Web2Wave dashboard
  • Documentation: Check the README files in each SDK repository for platform-specific details

Examples Summary

Quick Reference

PlatformOpen Quiz/PaywallClose WebViewEvent Listener
iOS (Swift)Web2Wave.shared.showWebView(...)Web2Wave.shared.closeWebView(...)Web2WaveWebListener protocol
Android (Kotlin)Web2Wave.showWebView(...)Web2Wave.closeWebView(...)Web2WaveWebListener interface
Android (Java)Web2Wave.showWebView(...)Web2Wave.closeWebView(...)Web2WaveWebListener interface
FlutterWeb2Wave.shared.openWebPage(...)Web2Wave.shared.closeWebPage()Web2WaveWebListener class

Need Help?

If you encounter any issues or have questions:

  1. Check the SDK repository README files for detailed API documentation
  2. Review the console logs for error messages
  3. Contact Web2Wave support through your dashboard
  4. Ensure you're using the latest SDK version