diff --git a/code_blocks/tools/paywalls_custom_variables_1.kt b/code_blocks/tools/paywalls_custom_variables_1.kt new file mode 100644 index 000000000..50dcf4281 --- /dev/null +++ b/code_blocks/tools/paywalls_custom_variables_1.kt @@ -0,0 +1,25 @@ +import androidx.compose.runtime.Composable +import com.revenuecat.purchases.CustomerInfo +import com.revenuecat.purchases.ui.revenuecatui.PaywallDialog +import com.revenuecat.purchases.ui.revenuecatui.PaywallOptions +import com.revenuecat.purchases.ui.revenuecatui.data.processed.CustomVariableValue + +@Composable +fun PaywallWithCustomVariables( + customerInfo: CustomerInfo, + onDismiss: () -> Unit +) { + val options = PaywallOptions.Builder { /* dismiss */ } + .setCustomVariables( + mapOf( + "player_name" to CustomVariableValue.String("John"), + "level" to CustomVariableValue.String("42") + ) + ) + .build() + + PaywallDialog( + options = options, + shouldDisplayBlock = { !customerInfo.entitlements.active.containsKey("pro") } + ) +} diff --git a/code_blocks/tools/paywalls_custom_variables_1.swift b/code_blocks/tools/paywalls_custom_variables_1.swift new file mode 100644 index 000000000..76b136d21 --- /dev/null +++ b/code_blocks/tools/paywalls_custom_variables_1.swift @@ -0,0 +1,19 @@ +import SwiftUI +import RevenueCat +import RevenueCatUI + +struct App: View { + @State + var displayPaywall = false + + var body: some View { + ContentView() + .sheet(isPresented: self.$displayPaywall) { + PaywallView() + .customPaywallVariables([ + "player_name": .string("John"), + "level": .string("42") + ]) + } + } +} diff --git a/code_blocks/tools/paywalls_custom_variables_2.kt b/code_blocks/tools/paywalls_custom_variables_2.kt new file mode 100644 index 000000000..aee494d4f --- /dev/null +++ b/code_blocks/tools/paywalls_custom_variables_2.kt @@ -0,0 +1,18 @@ +import com.revenuecat.purchases.CustomerInfo +import com.revenuecat.purchases.Offering +import com.revenuecat.purchases.ui.revenuecatui.activity.PaywallActivityLauncher +import com.revenuecat.purchases.ui.revenuecatui.data.processed.CustomVariableValue + +class MyActivity : ComponentActivity() { + private val paywallActivityLauncher = PaywallActivityLauncher(this) + + fun showPaywall(offering: Offering) { + paywallActivityLauncher.launch( + offering = offering, + customVariables = mapOf( + "player_name" to CustomVariableValue.String("John"), + "level" to CustomVariableValue.String("42") + ) + ) + } +} diff --git a/code_blocks/tools/paywalls_custom_variables_2.swift b/code_blocks/tools/paywalls_custom_variables_2.swift new file mode 100644 index 000000000..241f1f666 --- /dev/null +++ b/code_blocks/tools/paywalls_custom_variables_2.swift @@ -0,0 +1,15 @@ +import UIKit +import RevenueCat +import RevenueCatUI + +class MyViewController: UIViewController { + func showPaywall() { + let controller = PaywallViewController() + + // Set custom variables + controller.setCustomVariable(.string("John"), forKey: "player_name") + controller.setCustomVariable(.string("42"), forKey: "level") + + self.present(controller, animated: true) + } +} diff --git a/code_blocks/tools/paywalls_custom_variables_flutter.dart b/code_blocks/tools/paywalls_custom_variables_flutter.dart new file mode 100644 index 000000000..8e32781f3 --- /dev/null +++ b/code_blocks/tools/paywalls_custom_variables_flutter.dart @@ -0,0 +1,22 @@ +import 'package:purchases_ui_flutter/purchases_ui_flutter.dart'; + +@override +Widget build(BuildContext context) { + return Scaffold( + body: SafeArea( + child: Center( + child: PaywallView( + offering: offering, // Optional Offering object obtained through getOfferings + customVariables: { + "player_name": "John", + "level": "42" + }, + onDismiss: () { + // Dismiss the paywall, i.e. remove the view, navigate to another screen, etc. + // Will be called when the close button is pressed (if enabled) or when a purchase succeeds. + }, + ), + ), + ), + ); +} diff --git a/code_blocks/tools/paywalls_custom_variables_rn.ts.txt b/code_blocks/tools/paywalls_custom_variables_rn.ts.txt new file mode 100644 index 000000000..e92eed78f --- /dev/null +++ b/code_blocks/tools/paywalls_custom_variables_rn.ts.txt @@ -0,0 +1,22 @@ +import React from 'react'; +import { View } from 'react-native'; + +import RevenueCatUI from 'react-native-purchases-ui'; + +return ( + + { + // Dismiss the paywall, i.e. remove the view, navigate to another screen, etc. + // Will be called when the close button is pressed (if enabled) or when a purchase succeeds. + }} + /> + +); diff --git a/docs/tools/paywalls/creating-paywalls/variables.mdx b/docs/tools/paywalls/creating-paywalls/variables.mdx index 0feefa968..09088945e 100644 --- a/docs/tools/paywalls/creating-paywalls/variables.mdx +++ b/docs/tools/paywalls/creating-paywalls/variables.mdx @@ -50,6 +50,27 @@ We support the following variables: | product.relative_discount | 19% | 19% | 19% | 19% | 19% | 19% | 19% | | product.store_product_name | Pro Access | Pro Access | Pro Access | Pro Access | Pro Access | Pro Access | Pro Access | +## Custom variables + +In addition to the product variables listed above, you can create **Custom variables** to insert dynamic content that isn't tied to a specific product. This is useful for displaying values like user-specific information, app state, or promotional messaging that changes based on your app's context. + +### Creating and using custom variables in the editor + +To create a custom variable: + +1. In the paywall editor, select the **Variables** tab from the left-hand sidebar +2. Click "Create variable" +3. Set the name of the variable - this will be how you reference it in your paywall +4. Give it a default value - this is what will be displayed in the preview and used as a fallback if no value is provided + +The default value you set applies across your entire project, ensuring consistency wherever the variable is used. Once created, you can insert the custom variable into any text field using the same `{{ custom.variable_name }}` syntax. + +### Passing custom variable values from your app + +When displaying a paywall in your app, you'll need to pass actual values for any custom variables you've created. This allows you to provide dynamic, context-specific content based on the user's session or app state. + +For details on how to pass custom variable values when presenting a paywall, see [Displaying Paywalls](/documentation/displaying-paywalls#custom-variables). + ## Countdown variables When using a [Countdown component](/tools/paywalls/creating-paywalls/components#countdown) on your paywall, you can use countdown-specific variables within any text component inside that countdown. These variables display the time remaining until the countdown's target date. @@ -95,4 +116,4 @@ These modifiers can be used with the `|` operator after the variable name, for e | Question | Answer | | ------------------ | ------------------| -| How is the `product.relative_discount` variable calculated? | `relative_discount` returns the localized discount percentage of a given package compared to the most expensive package per period that's offered on your paywall. For example, if you're displaying a monthly package that is $10/month, and a yearly package that is $80/year (or $6.67/month), the relative discount for the annual package is 67%. Because of this, we recommend only using this variable within packages that are NOT the most expensive package per period, as the most expensive package will have a null value returned, since its relative discount is null. | \ No newline at end of file +| How is the `product.relative_discount` variable calculated? | `relative_discount` returns the localized discount percentage of a given package compared to the most expensive package per period that's offered on your paywall. For example, if you're displaying a monthly package that is $10/month, and a yearly package that is $80/year (or $6.67/month), the relative discount for the annual package is 67%. Because of this, we recommend only using this variable within packages that are NOT the most expensive package per period, as the most expensive package will have a null value returned, since its relative discount is null. | diff --git a/docs/tools/paywalls/displaying-paywalls.mdx b/docs/tools/paywalls/displaying-paywalls.mdx index f0391696e..71db95ecb 100644 --- a/docs/tools/paywalls/displaying-paywalls.mdx +++ b/docs/tools/paywalls/displaying-paywalls.mdx @@ -347,6 +347,60 @@ import preferredLocaleReactNative from '@site/code_blocks/tools/paywalls_preferr /> +## Custom variables {#custom-variables} + +Custom variables allow you to pass dynamic values from your app to display in your paywall text. This is useful for displaying values like user-specific information, app state, or promotional messaging that changes based on your app's context. + +When you create custom variables in the [paywall editor](/tools/paywalls/creating-paywalls/variables#custom-variables), you set default values that will be used as fallbacks. When displaying the paywall in your app, you can override these defaults with actual runtime values specific to the user's session. + +### iOS + +import customVarsSwift from '@site/code_blocks/tools/paywalls_custom_variables_1.swift?raw'; +import customVarsUIKit from '@site/code_blocks/tools/paywalls_custom_variables_2.swift?raw'; + + + +### Android + +import customVarsKotlin from '@site/code_blocks/tools/paywalls_custom_variables_1.kt?raw'; +import customVarsActivity from '@site/code_blocks/tools/paywalls_custom_variables_2.kt?raw'; + + + +### React Native + +import customVarsRN from '@site/code_blocks/tools/paywalls_custom_variables_rn.ts.txt?raw'; + + + +### Flutter + +import customVarsFlutter from '@site/code_blocks/tools/paywalls_custom_variables_flutter.dart?raw'; + + + +:::info Variable naming +Custom variable keys must start with a letter and can only contain letters, numbers, and underscores. In your paywall text, reference them using the template syntax: `{{ custom.variable_name }}` +::: + ## Custom fonts Using custom fonts in your paywall can now be done by uploading font files directly to RevenueCat. See the [Custom fonts](/tools/paywalls/creating-paywalls/components#custom-fonts) section for more information. @@ -451,4 +505,4 @@ On Android, it uses the app's `Material3`'s `ColorScheme`. :::tip Targeting If your app supports our legacy Paywall templates, consider using Targeting to create an audience that only receives your new Paywall if they're using an SDK version that does not support our current Paywalls. This will ensure that older app versions continue to receive the Offering and Paywall that they support, while any app versions running a supported RC SDK version receive your new Paywall. [Learn more about Targeting.](/tools/targeting) -::: \ No newline at end of file +:::