Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.permutive.com/llms.txt

Use this file to discover all available pages before exploring further.

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

Cohort Triggers

Query Triggers

User ID

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()
}

Cohorts & Activations

Understanding user segments

Identity Management

User identity tracking

Page Tracking

Trigger cohort qualification

Issues

Common problems and solutions