Displaying Paywalls
These docs refer to our beta of Paywalls v2. For our original Paywalls which already support iOS, Android, React Native, Flutter, and KMP, click here.
iOSโ
How to display a Paywall in your appโ
RevenueCat Paywalls v2 will show paywalls fullscreen, and there are multiple ways to do this with SwiftUI and UIKit.
- Depending on an entitlement with
presentPaywallIfNeeded
- Custom logic with
presentPaywallIfNeeded
- Manually with
PaywallView
orPaywallViewController
- Entitlement
- Custom Logic
- Manually
- Manually (UIKit)
- Manually (UIKit and Objective-C)
import SwiftUI
import RevenueCat
import RevenueCatUI
struct App: View {
var body: some View {
ContentView()
.presentPaywallIfNeeded(
requiredEntitlementIdentifier: "pro",
purchaseCompleted: { customerInfo in
print("Purchase completed: \(customerInfo.entitlements)")
},
restoreCompleted: { customerInfo in
// Paywall will be dismissed automatically if "pro" is now active.
print("Purchases restored: \(customerInfo.entitlements)")
}
)
}
}
import SwiftUI
import RevenueCat
import RevenueCatUI
struct App: View {
var body: some View {
ContentView()
.presentPaywallIfNeeded { customerInfo in
// Returning `true` will present the paywall
return customerInfo.entitlements.active.keys.contains("pro")
} purchaseCompleted: { customerInfo in
print("Purchase completed: \(customerInfo.entitlements)")
} restoreCompleted: {
// Paywall will be dismissed automatically if "pro" is now active.
print("Purchases restored: \(customerInfo.entitlements)")
}
}
}
import SwiftUI
import RevenueCat
import RevenueCatUI
struct App: View {
@State
var displayPaywall = false
var body: some View {
ContentView()
.sheet(isPresented: self.$displayPaywall) {
PaywallView(displayCloseButton: true)
}
}
}
import UIKit
import RevenueCat
import RevenueCatUI
class ViewController: UIViewController {
@IBAction func presentPaywall() {
let controller = PaywallViewController()
controller.delegate = self
present(controller, animated: true, completion: nil)
}
}
extension ViewController: PaywallViewControllerDelegate {
func paywallViewController(_ controller: PaywallViewController,
didFinishPurchasingWith customerInfo: CustomerInfo) {
}
}
#import "ViewController.h"
@import RevenueCat;
@import RevenueCatUI;
@interface ViewController () <RCPaywallViewControllerDelegate>
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (IBAction)showPaywallTapped:(id)sender {
[RCPurchases.sharedPurchases offeringsWithCompletionHandler:^(RCOfferings * _Nullable offerings, NSError * _Nullable error) {
if (error) {
NSLog(@"Error fetching offerings: %@", error.localizedDescription);
return;
}
RCOffering *offering = offerings.current;
if (offering) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"Current offering identifier: %@", offering.identifier);
RCPaywallViewController *controller = [[RCPaywallViewController alloc] initWithOffering:offering
displayCloseButton:YES
shouldBlockTouchEvents:NO
dismissRequestedHandler:^(RCPaywallViewController * _Nonnull controller) {
NSLog(@"dismiss request!");
[controller dismissViewControllerAnimated:YES completion:nil];
}];
controller.delegate = self;
[self presentViewController:controller animated:YES completion:nil];
});
} else {
NSLog(@"No current offering available");
}
}];
}
#pragma mark - PaywallViewControllerDelegate
- (void)paywallViewController:(RCPaywallViewController *)controller
didFinishPurchasingWithCustomerInfo:(RCCustomerInfo *)customerInfo {
// Handle purchase completion here
}
@end
Handling paywall navigationโ
When creating a paywall, consider whether it will be presented in a sheet, or as a full screen view. Sheets won't require a dedicated close button. Full screen views should have either a close button (if presented) or a back button (if pushed in a navigation stack) unless you intend to provide a hard paywall to your customers that cannot be bypassed.
Additional changes from original Paywallsโ
Footer Paywallsโ
Paywalls v2 does not support footer Paywalls. If your app requests the Paywall for an Offering to display that has a v2 Paywall, it will display a default version of that paywall instead (see below). Footer mode can still be used on original Paywalls templates using the existing method, or the new .originalTemplatePaywallFooter()
method on iOS SDK versions 5.16.0+.
Close buttonsโ
Paywalls v2 does not require the displayCloseButton
parameter, and it will have no effect if used, since close buttons can be optionally added directly to your paywall as a component if desired.
Font providerโ
Paywalls v2 does not support passing in a custom font provider via the PaywallFontProvider
handler that original Paywalls used. Instead, in the near future you'll be able to configure Paywalls to use the font providers you've already installed in your app directly from the Dashboard. Using this handler will have no effect on Paywalls v2.
Default Paywallโ
If you attempt to display a Paywall for an Offering that doesn't have one configured, or that has a Paywall configured which is not supported on the installed SDK version, the RevenueCatUI SDK will display a default Paywall.
The default paywall displays all packages in the Offering.
On iOS it uses the app's accentColor
for styling.
On Android, it uses the app's Material3
's ColorScheme
.
If your app supports our original Paywall templates, consider using Targeting to create an audience that only receives your v2 Paywall if they're using RC iOS SDK version 5.16.0+. 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 iOS SDK version receive your new v2 Paywall. Learn more about Targeting.