Superwall

The shared instance of Superwall that provides access to all SDK features.

You must call configure() before accessing Superwall.shared, otherwise your app will crash.

Purpose

Provides access to the configured Superwall instance after calling configure().

Signature

public static var shared: Superwall { get }
public var eventTrackingBehavior: EventTrackingBehavior { get set }

@Published public var configurationStatus: ConfigurationStatus { get }
public var isPaywallPresented: Bool { get }
public var latestPaywallInfo: PaywallInfo? { get }

public func getAssignments() -> [Assignment]
public func togglePaywallSpinner(isHidden: Bool)

Parameters

This is a computed property with no parameters.

Returns / State

Returns the shared Superwall instance that was configured via configure().

Usage

Configure first (typically in AppDelegate or SceneDelegate):

Superwall.configure(apiKey: "pk_your_api_key")

Then access throughout your app:

Superwall.shared.register(placement: "feature_access") {
  // Feature code here
}

Set user identity and attributes:

Superwall.shared.identify(userId: "user123")

Superwall.shared.setUserAttributes([
  "plan": "premium",
  "signUpDate": Date()
])

Change event collection at runtime:

// Stop SDK event collection after the user opts out.
Superwall.shared.eventTrackingBehavior = .none

// Keep Superwall's internal events, but suppress app-sent events and user attributes.
Superwall.shared.eventTrackingBehavior = .superwallOnly

// Restore the default behavior.
Superwall.shared.eventTrackingBehavior = .all

This property is available in iOS SDK 4.16.0 and later. It updates the SDK's event queue and the currently displayed paywall, so your app can respond to consent changes without reconfiguring Superwall. If you need an initial value before the SDK is configured, set SuperwallOptions.eventTrackingBehavior before calling configure().

Reset the user:

Superwall.shared.reset()

Avoid calling Superwall.shared.reset() repeatedly. Resetting rotates the anonymous user ID, clears local paywall assignments, and requires the SDK to re-download configuration state. Only trigger a reset when a user explicitly logs out or you intentionally need to forget their identity. See User Management for more guidance.

Set delegate:

Superwall.shared.delegate = self

Override products:

Superwall.shared.overrideProductsByName = [
  "primary": "produceID_to_replace_primary_product"
]

Access customer info:

// Get current customer info
let customerInfo = Superwall.shared.customerInfo

// Get customer info asynchronously
let customerInfo = await Superwall.shared.getCustomerInfo()

// Observe customer info changes
Superwall.shared.$customerInfo
  .sink { customerInfo in
    print("Customer has \(customerInfo.subscriptions.count) subscriptions")
  }
  .store(in: &cancellables)

Set integration attributes:

Superwall.shared.setIntegrationAttributes([
  .amplitudeUserId: "user123",
  .mixpanelDistinctId: "distinct456",
  .firebaseInstallationId: "abc123"
])

Get device attributes:

let deviceAttributes = await Superwall.shared.getDeviceAttributes()
// Use in audience filters or for debugging
print("Device attributes: \(deviceAttributes)")

Observe configuration status:

// .pending until configuration finishes, then .configured or .failed
switch Superwall.shared.configurationStatus {
case .pending:
  showLoadingState()
case .configured:
  showPaywallEntryPoints()
case .failed:
  showFallbackUI()
}

// It's a @Published property, so you can bind to it in SwiftUI or Combine
Superwall.shared.$configurationStatus
  .sink { status in
    print("Superwall configuration is now \(status)")
  }
  .store(in: &cancellables)

Check whether a paywall is on screen:

if Superwall.shared.isPaywallPresented {
  // Don't push another screen on top of the paywall
  return
}

// Inspect the most recently presented paywall
if let info = Superwall.shared.latestPaywallInfo {
  print("Last paywall: \(info.identifier), experiment: \(info.experiment?.id ?? "none")")
}

Confirm all experiment assignments:

// Get all experiment assignments
let assignments = await Superwall.shared.confirmAllAssignments()
print("Confirmed \(assignments.count) assignments")

Read already-confirmed assignments:

// Synchronous, and does not confirm anything new — returns the assignments
// already stored on device. Use confirmAllAssignments() to confirm them first.
let assignments = Superwall.shared.getAssignments()

Show a spinner while doing async work from a custom paywall action:

func handleCustomPaywallAction(withName name: String) {
  guard name == "restore_from_backend" else { return }

  Superwall.shared.togglePaywallSpinner(isHidden: false)
  Task {
    await syncEntitlementsFromServer()
    Superwall.shared.togglePaywallSpinner(isHidden: true)
  }
}

Manually refresh configuration (development-only):

// Useful when hot-reloading paywalls during development
await Superwall.shared.refreshConfiguration()

How is this guide?

On this page