Skip to main content
TriggerProvider enables reactive updates when users enter or exit cohorts, allowing your app to respond to segment changes in real-time.

Overview

TriggerProvider provides:
  • Real-time cohort change notifications
  • Immediate callback when users enter/exit cohorts
  • Query-based triggers for complex conditions
  • User identity change monitoring
Use TriggerProvider instead of polling cohorts or activations for reactive behavior.

Accessing TriggerProvider

let triggerProvider = Permutive.shared.triggerProvider

Cohort Membership Triggers

Watch for changes in cohort membership:
import Permutive_iOS

class FeatureController {
    private var premiumTrigger: TriggerAction?

    func watchPremiumStatus() {
        premiumTrigger = Permutive.shared.triggerProvider?.action(
            boolFor: ["premium_subscriber"],
            action: { cohortId, isInCohort in
                print("Cohort '\(cohortId)' membership: \(isInCohort)")

                if isInCohort {
                    self.enablePremiumFeatures()
                } else {
                    self.disablePremiumFeatures()
                }
            }
        )
    }

    private func enablePremiumFeatures() {
        // Show premium content
    }

    private func disablePremiumFeatures() {
        // Hide premium content
    }

    deinit {
        // Release trigger to stop watching
        premiumTrigger = nil
    }
}

Watching Multiple Cohorts

class ContentPersonalizer {
    private var contentTrigger: TriggerAction?

    func watchUserInterests() {
        contentTrigger = Permutive.shared.triggerProvider?.action(
            boolFor: ["sports_enthusiast", "tech_reader", "news_follower"],
            action: { cohortId, isInCohort in
                if isInCohort {
                    switch cohortId {
                    case "sports_enthusiast":
                        self.boostSportsContent()
                    case "tech_reader":
                        self.boostTechContent()
                    case "news_follower":
                        self.boostNewsContent()
                    default:
                        break
                    }
                }
            }
        )
    }
}

Query Triggers

For more complex data, use query triggers that return dictionaries or integers:

Dictionary Queries

class AnalyticsController {
    private var queryTrigger: TriggerAction?

    func watchComplexQueries() {
        queryTrigger = Permutive.shared.triggerProvider?.action(
            dictionaryFor: ["user_profile_query", "engagement_metrics"],
            action: { queryId, result in
                print("Query '\(queryId)' returned: \(result)")

                if queryId == "user_profile_query",
                   let preferences = result["preferences"] as? [String: Any] {
                    self.applyUserPreferences(preferences)
                }
            }
        )
    }
}

Integer Queries

class ScoreController {
    private var scoreTrigger: TriggerAction?

    func watchEngagementScore() {
        scoreTrigger = Permutive.shared.triggerProvider?.action(
            intFor: ["engagement_score"],
            action: { queryId, score in
                print("Engagement score: \(score)")

                self.updateUIForScore(score)
            }
        )
    }

    private func updateUIForScore(_ score: Int) {
        // Adjust UI based on engagement level
    }
}

User ID Triggers

Monitor changes to the user identity:
class SessionController {
    private var userIdTrigger: TriggerAction?

    func watchUserIdentityChanges() {
        userIdTrigger = Permutive.shared.triggerProvider?.actionUpdateForUserIdentity { userId in
            print("User identity changed to: \(userId)")

            // Update analytics with new user ID
            Analytics.setUserId(userId)

            // Refresh user-specific data
            self.refreshUserData()
        }
    }

    deinit {
        userIdTrigger = nil
    }
}

TriggerAction Lifecycle

You must maintain a strong reference to TriggerAction objects. Releasing the reference stops the trigger.

Keeping Triggers Active

class TriggerManager {
    // Store triggers as instance properties
    private var cohortTrigger: TriggerAction?
    private var userIdTrigger: TriggerAction?

    func setupTriggers() {
        cohortTrigger = Permutive.shared.triggerProvider?.action(
            boolFor: ["cohort"],
            action: { _, _ in }
        )

        userIdTrigger = Permutive.shared.triggerProvider?.actionUpdateForUserIdentity { _ in }
    }

    func stopWatching() {
        // Explicitly release triggers
        cohortTrigger = nil
        userIdTrigger = nil
    }

    deinit {
        // Automatically released when controller is deallocated
    }
}

UIViewController Integration

class PersonalizedViewController: UIViewController {
    private var cohortTrigger: TriggerAction?

    override func viewDidLoad() {
        super.viewDidLoad()

        // Start watching cohorts
        cohortTrigger = Permutive.shared.triggerProvider?.action(
            boolFor: ["premium_user", "new_user"],
            action: { [weak self] cohortId, isInCohort in
                DispatchQueue.main.async {
                    self?.handleCohortChange(cohortId: cohortId, isInCohort: isInCohort)
                }
            }
        )
    }

    private func handleCohortChange(cohortId: String, isInCohort: Bool) {
        switch cohortId {
        case "premium_user":
            updatePremiumUI(enabled: isInCohort)
        case "new_user":
            showOnboarding(isNew: isInCohort)
        default:
            break
        }
    }

    deinit {
        cohortTrigger = nil
    }
}

SwiftUI Integration

import SwiftUI
import Permutive_iOS

struct PersonalizedView: View {
    @StateObject private var triggerManager = TriggerManager()

    var body: some View {
        VStack {
            if triggerManager.isPremium {
                PremiumContentView()
            } else {
                StandardContentView()
            }
        }
        .onAppear {
            triggerManager.startWatching()
        }
        .onDisappear {
            triggerManager.stopWatching()
        }
    }
}

class TriggerManager: ObservableObject {
    @Published var isPremium = false

    private var trigger: TriggerAction?

    func startWatching() {
        trigger = Permutive.shared.triggerProvider?.action(
            boolFor: ["premium_subscriber"],
            action: { [weak self] _, isInCohort in
                DispatchQueue.main.async {
                    self?.isPremium = isInCohort
                }
            }
        )
    }

    func stopWatching() {
        trigger = nil
    }
}

tvOS Considerations

tvOS Note: TriggerProvider works identically on tvOS. Use it to update UI elements based on cohort membership in your focus-based navigation.

Best Practices

  • Store TriggerAction references as instance properties
  • Use [weak self] in closures to avoid retain cycles
  • Dispatch UI updates to main thread
  • Release triggers when no longer needed
  • Group related cohorts in a single trigger

Troubleshooting

Problem: No callbacks when cohort membership changes.Solutions:
  • Verify you’re storing a strong reference to TriggerAction
  • Check that cohort IDs match your dashboard
  • Enable debug logging to see cohort updates
  • Ensure SDK is initialized before creating triggers
Problem: Trigger worked initially but stopped.Cause: TriggerAction reference was released.Solution: Store TriggerAction as an instance property, not a local variable.
Problem: Callback fires but UI doesn’t change.Solution: Dispatch UI updates to main thread:
DispatchQueue.main.async {
    self.updateUI()
}