> ## 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.

# Triggers Provider

> React to real-time cohort membership changes

The `TriggersProvider` enables real-time reactive programming patterns by allowing you to observe cohort membership changes and trigger actions when users enter or exit specific cohorts. This is powerful for personalizing user experiences, A/B testing, and dynamic content delivery.

<CardGroup cols={4}>
  <Card title="Creating Provider" href="#creating-a-triggersprovider" icon="plus" />

  <Card title="Use Cases" href="#use-cases" icon="layer-group" />

  <Card title="Lifecycle" href="#triggeraction-lifecycle" icon="arrows-rotate" />

  <Card title="Advanced" href="#advanced-patterns" icon="wand-magic-sparkles" />
</CardGroup>

## Overview

The Triggers Provider allows you to:

* **React to cohort changes in real-time** - Execute code when users enter or exit cohorts
* **Observe activations** - Monitor when users qualify for specific ad platform activations
* **Build personalized experiences** - Show/hide content based on cohort membership
* **Implement A/B tests** - Dynamically segment users and track their behavior

## Creating a TriggersProvider

Create a `TriggersProvider` instance from your Permutive SDK instance:

<CodeGroup>
  ```kotlin Kotlin theme={"dark"}
  import com.permutive.android.TriggersProvider

  class MyActivity : AppCompatActivity() {

      private val permutive by lazy {
          (application as MyApplication).permutive
      }

      private val triggersProvider: TriggersProvider by lazy {
          permutive.triggersProvider()
      }

      // Use the triggers provider...
  }
  ```

  ```java Java theme={"dark"}
  import com.permutive.android.TriggersProvider;

  public class MyActivity extends AppCompatActivity {

      private TriggersProvider triggersProvider;

      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);

          Permutive permutive = ((MyApplication) getApplication()).getPermutive();
          triggersProvider = permutive.triggersProvider();
      }
  }
  ```
</CodeGroup>

> 💡 Lifecycle Management
>
> You can create any number of `TriggersProvider` instances. They're lightweight and don't maintain heavy state.

***

## Use Cases

### 1. Observing Cohort Membership

Monitor when a user is in a specific cohort:

<CodeGroup>
  ```kotlin Kotlin theme={"dark"}
  import com.permutive.android.TriggerAction

  class PersonalizedActivity : AppCompatActivity() {

      private var premiumContentTrigger: TriggerAction? = null

      override fun onCreate(savedInstanceState: Bundle?) {
          super.onCreate(savedInstanceState)
          setContentView(R.layout.activity_personalized)

          val triggersProvider = permutive.triggersProvider()

          // Monitor if user is in the "premium_readers" cohort
          premiumContentTrigger = triggersProvider.triggerAction("premium_readers") { isInCohort ->
              if (isInCohort) {
                  showPremiumContent()
              } else {
                  showStandardContent()
              }
          }
      }

      override fun onDestroy() {
          super.onDestroy()
          // Clean up the trigger when the activity is destroyed
          premiumContentTrigger?.close()
      }

      private fun showPremiumContent() {
          // Update UI to show premium features
          binding.premiumBanner.visibility = View.VISIBLE
          binding.subscriptionPrompt.visibility = View.GONE
      }

      private fun showStandardContent() {
          // Update UI for standard users
          binding.premiumBanner.visibility = View.GONE
          binding.subscriptionPrompt.visibility = View.VISIBLE
      }
  }
  ```

  ```java Java theme={"dark"}
  import com.permutive.android.TriggerAction;
  import com.permutive.android.internal.Method;

  public class PersonalizedActivity extends AppCompatActivity {

      private TriggerAction premiumContentTrigger;

      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_personalized);

          TriggersProvider triggersProvider = permutive.triggersProvider();

          // Monitor if user is in the "premium_readers" cohort
          premiumContentTrigger = triggersProvider.triggerAction(
              "premium_readers",
              new Method<Boolean>() {
                  @Override
                  public void invoke(Boolean isInCohort) {
                      if (isInCohort) {
                          showPremiumContent();
                      } else {
                          showStandardContent();
                      }
                  }
              }
          );
      }

      @Override
      protected void onDestroy() {
          super.onDestroy();
          if (premiumContentTrigger != null) {
              premiumContentTrigger.close();
          }
      }

      private void showPremiumContent() {
          // Update UI to show premium features
      }

      private void showStandardContent() {
          // Update UI for standard users
      }
  }
  ```
</CodeGroup>

***

### 2. Observing Multiple Cohorts

React to multiple cohort memberships:

#### Kotlin

```kotlin theme={"dark"}
class ContentRecommendationActivity : AppCompatActivity() {
    
    private val triggers = mutableListOf<TriggerAction>()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        val triggersProvider = permutive.triggersProvider()
        
        // Sports enthusiasts
        triggers.add(
            triggersProvider.triggerAction("sports_enthusiast") { isInCohort ->
                if (isInCohort) addRecommendation("Sports")
            }
        )
        
        // Tech readers
        triggers.add(
            triggersProvider.triggerAction("tech_reader") { isInCohort ->
                if (isInCohort) addRecommendation("Technology")
            }
        )
        
        // Business professionals
        triggers.add(
            triggersProvider.triggerAction("business_professional") { isInCohort ->
                if (isInCohort) addRecommendation("Business")
            }
        )
    }
    
    override fun onDestroy() {
        super.onDestroy()
        triggers.forEach { it.close() }
        triggers.clear()
    }
    
    private fun addRecommendation(category: String) {
        // Update UI with personalized recommendations
    }
}
```

***

### 3. Observing Activations for Ad Platforms

Monitor cohorts activated for specific ad platforms:

#### Kotlin

```kotlin theme={"dark"}
class AdTargetingActivity : AppCompatActivity() {
    
    private var gamActivationTrigger: TriggerAction? = null
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        val triggersProvider = permutive.triggersProvider()
        
        // Monitor Google Ad Manager activations
        gamActivationTrigger = triggersProvider.cohortActivations("dfp") { cohorts ->
            Log.d("Permutive", "User has ${cohorts.size} active GAM cohorts: $cohorts")
            updateAdTargeting(cohorts)
        }
    }
    
    override fun onDestroy() {
        super.onDestroy()
        gamActivationTrigger?.close()
    }
    
    private fun updateAdTargeting(cohorts: List<String>) {
        // Use cohorts for ad targeting
    }
}
```

#### Available Activation Types

| Activation Type                  | Description                                                         |
| -------------------------------- | ------------------------------------------------------------------- |
| `"dfp"`                          | Google Ad Manager (formerly DoubleClick for Publishers) activations |
| `"appnexus_adserver"`            | Xandr/AppNexus ad server activations                                |
| `"freewheel"`                    | Freewheel activations                                               |
| `"dfp_contextual"`               | Google Ad Manager contextual cohorts                                |
| `"appnexus_adserver_contextual"` | Xandr/AppNexus contextual cohorts                                   |

***

### 4. A/B Testing Based on Cohorts

Implement feature flags or A/B tests using cohort membership:

#### Kotlin

```kotlin theme={"dark"}
class ExperimentActivity : AppCompatActivity() {
    
    private var experimentTrigger: TriggerAction? = null
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        val triggersProvider = permutive.triggersProvider()
        
        // A/B test: Show new checkout flow to test cohort
        experimentTrigger = triggersProvider.triggerAction("checkout_experiment_v2") { isInTestGroup ->
            if (isInTestGroup) {
                showNewCheckoutFlow()
            } else {
                showStandardCheckoutFlow()
            }
        }
    }
    
    override fun onDestroy() {
        super.onDestroy()
        experimentTrigger?.close()
    }
}
```

***

## TriggerAction Lifecycle

The `TriggerAction` interface represents an active trigger subscription. It's crucial to manage its lifecycle properly to prevent memory leaks.

### Key Points

1. **Create** triggers when you need to start observing
2. **Close** triggers when you're done (typically in `onDestroy()`)
3. **Store** references if you need to close them later
4. **Don't recreate** unnecessarily - triggers survive configuration changes if managed properly

### Best Practices

#### ✅ Good: Proper Lifecycle Management

```kotlin theme={"dark"}
class MyActivity : AppCompatActivity() {
    private var trigger: TriggerAction? = null
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        trigger = triggersProvider.triggerAction("cohort_id") { /* ... */ }
    }
    
    override fun onDestroy() {
        super.onDestroy()
        trigger?.close()
    }
}
```

#### ✅ Good: Using ViewModel for Configuration Changes

```kotlin theme={"dark"}
class MyViewModel : ViewModel() {
    private var trigger: TriggerAction? = null
    
    fun observeCohort(triggersProvider: TriggersProvider) {
        if (trigger == null) {
            trigger = triggersProvider.triggerAction("cohort_id") { /* ... */ }
        }
    }
    
    override fun onCleared() {
        super.onCleared()
        trigger?.close()
    }
}
```

#### ❌ Bad: Not Closing Triggers

```kotlin theme={"dark"}
class MyActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // Creates a new trigger every time, never closes the old ones
        triggersProvider.triggerAction("cohort_id") { /* ... */ }
    }
    // Memory leak! Triggers never closed
}
```

***

## Thread Safety

The `TriggersProvider` and `TriggerAction` are thread-safe. Callbacks are delivered on a background thread, so if you need to update UI, use appropriate threading mechanisms:

<CodeGroup>
  ```kotlin Kotlin theme={"dark"}
  private var trigger: TriggerAction? = null

  override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)

      trigger = triggersProvider.triggerAction("cohort_id") { isInCohort ->
          // Callback is on background thread
          lifecycleScope.launch(Dispatchers.Main) {
              // Update UI on main thread
              if (isInCohort) {
                  textView.text = "User is in cohort"
              }
          }
      }
  }
  ```

  ```java Java theme={"dark"}
  private final Handler mainHandler = new Handler(Looper.getMainLooper());
  private TriggerAction trigger;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);

      trigger = triggersProvider.triggerAction("cohort_id", new Method<Boolean>() {
          @Override
          public void invoke(Boolean isInCohort) {
              // Callback is on background thread
              mainHandler.post(() -> {
                  // Update UI on main thread
                  if (isInCohort) {
                      textView.setText("User is in cohort");
                  }
              });
          }
      });
  }
  ```
</CodeGroup>

***

## Advanced Patterns

### Combining Multiple Cohorts

Trigger actions only when user is in multiple cohorts:

```kotlin theme={"dark"}
class AdvancedTargetingActivity : AppCompatActivity() {
    
    private var isPremium = false
    private var isSportsReader = false
    
    private val triggers = mutableListOf<TriggerAction>()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        val triggersProvider = permutive.triggersProvider()
        
        triggers.add(
            triggersProvider.triggerAction("premium_subscriber") { inCohort ->
                isPremium = inCohort
                updateContent()
            }
        )
        
        triggers.add(
            triggersProvider.triggerAction("sports_enthusiast") { inCohort ->
                isSportsReader = inCohort
                updateContent()
            }
        )
    }
    
    private fun updateContent() {
        when {
            isPremium && isSportsReader -> showPremiumSportsContent()
            isPremium -> showPremiumGeneralContent()
            isSportsReader -> showFreeSportsContent()
            else -> showGeneralContent()
        }
    }
    
    override fun onDestroy() {
        super.onDestroy()
        triggers.forEach { it.close() }
        triggers.clear()
    }
}
```

***

## Deprecated APIs

### Legacy Segment-Based Triggers

The following methods are deprecated as they only support integer-based segment IDs:

```kotlin theme={"dark"}
@Deprecated("Use triggerAction(cohortId: String, callback: Method<Boolean>)")
fun <T : Any> triggerAction(queryId: Int, callback: Method<T>): TriggerAction

@Deprecated("Use cohortActivations")
fun querySegments(callback: Method<List<Int>>): TriggerAction

@Deprecated("Use cohortActivations") 
fun queryReactions(reaction: String, callback: Method<List<Int>>): TriggerAction
```

**Migration Guide:**

Old (Deprecated):

```kotlin theme={"dark"}
triggersProvider.triggerAction(12345) { result: Boolean ->
    // Handle result
}
```

New:

```kotlin theme={"dark"}
triggersProvider.triggerAction("cohort_id_string") { isInCohort ->
    // Handle result
}
```

> 📘 Why the Change?
>
> The SDK now supports Classification Model cohorts which use string IDs. The new APIs support both traditional integer-based cohorts and newer string-based cohorts seamlessly.

***

## Troubleshooting

<AccordionGroup>
  <Accordion title="Callbacks Not Firing">
    **Problem:** Your trigger callback is never invoked.

    **Possible Causes:**

    1. SDK hasn't finished initializing
    2. Cohort ID is incorrect
    3. User hasn't generated enough events to be segmented

    **Solutions:**

    * Enable debug logging: `permutive.setDeveloperMode(true)`
    * Check logs for cohort updates
    * Verify cohort ID matches your dashboard configuration
    * Ensure events are being tracked (see [Verification Guide](/sdks/mobile/android/getting-started/verification))
  </Accordion>

  <Accordion title="Memory Leaks">
    **Problem:** App memory usage grows over time.

    **Cause:** `TriggerAction` instances not being closed.

    **Solution:** Always call `close()` on triggers in appropriate lifecycle methods (usually `onDestroy()` or `onCleared()`).
  </Accordion>

  <Accordion title="Callbacks on Wrong Thread">
    **Problem:** Crash when trying to update UI from callback.

    **Cause:** Callbacks execute on background threads.

    **Solution:** Use `Handler`, coroutines, or `runOnUiThread()` to update UI (see Thread Safety section above).
  </Accordion>
</AccordionGroup>

***

## Best Practices

<Tabs>
  <Tab title="Do">
    * Close all triggers when done to prevent memory leaks
    * Handle threading appropriately when updating UI
    * Use descriptive cohort IDs that match your dashboard
    * Store trigger references if you need to close them later
    * Test with debug logging enabled
  </Tab>

  <Tab title="Don't">
    * Create triggers and never close them
    * Update UI directly from callbacks without switching threads
    * Create multiple triggers for the same cohort unnecessarily
    * Assume callbacks will fire immediately (SDK needs time to initialize)
  </Tab>
</Tabs>

***

## Example: Complete Implementation

Here's a complete example showing proper implementation:

```kotlin theme={"dark"}
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import com.permutive.android.TriggerAction
import com.permutive.android.TriggersProvider
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

class PersonalizedHomeActivity : AppCompatActivity() {
    
    private val permutive by lazy {
        (application as MyApplication).permutive
    }
    
    private val triggersProvider by lazy {
        permutive.triggersProvider()
    }
    
    private val activeTriggers = mutableListOf<TriggerAction>()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_personalized_home)
        
        setupCohortTriggers()
    }
    
    private fun setupCohortTriggers() {
        // Premium content trigger
        activeTriggers.add(
            triggersProvider.triggerAction("premium_subscriber") { isSubscriber ->
                lifecycleScope.launch(Dispatchers.Main) {
                    updatePremiumFeatures(isSubscriber)
                }
            }
        )
        
        // Sports content trigger
        activeTriggers.add(
            triggersProvider.triggerAction("sports_enthusiast") { isSportsReader ->
                lifecycleScope.launch(Dispatchers.Main) {
                    updateSportsRecommendations(isSportsReader)
                }
            }
        )
        
        // Ad activations trigger
        activeTriggers.add(
            triggersProvider.cohortActivations("dfp") { cohorts ->
                lifecycleScope.launch(Dispatchers.Main) {
                    updateAdTargeting(cohorts)
                }
            }
        )
    }
    
    private fun updatePremiumFeatures(isPremium: Boolean) {
        binding.premiumBadge.visibility = if (isPremium) View.VISIBLE else View.GONE
        binding.upgradePrompt.visibility = if (isPremium) View.GONE else View.VISIBLE
    }
    
    private fun updateSportsRecommendations(showSports: Boolean) {
        if (showSports) {
            binding.sportsSection.visibility = View.VISIBLE
            loadSportsContent()
        } else {
            binding.sportsSection.visibility = View.GONE
        }
    }
    
    private fun updateAdTargeting(cohorts: List<String>) {
        Log.d("Permutive", "Updated ad targeting with ${cohorts.size} cohorts")
        // Ad targeting logic here
    }
    
    private fun loadSportsContent() {
        // Load sports-specific content
    }
    
    override fun onDestroy() {
        super.onDestroy()
        // Clean up all triggers
        activeTriggers.forEach { it.close() }
        activeTriggers.clear()
    }
}
```

***

## Related Documentation

<CardGroup cols={2}>
  <Card title="Cohorts and Activations" icon="users" href="/sdks/mobile/android/core-concepts/cohorts-and-activations">
    Understanding how cohorts work
  </Card>

  <Card title="Event Tracking" icon="bolt" href="/sdks/mobile/android/features/event-tracking">
    How events feed into segmentation
  </Card>

  <Card title="Identity Management" icon="fingerprint" href="/sdks/mobile/android/core-concepts/identity-management">
    Tracking users across sessions
  </Card>

  <Card title="Contextual Data" icon="bullseye" href="/sdks/mobile/android/core-concepts/contextual-data">
    Content-based segmentation
  </Card>
</CardGroup>

***

## API Reference

For complete API documentation, see the [Javadocs](https://sdk-docs.permutive.com/index.html).

### Key Interfaces

* `TriggersProvider` - Factory for creating trigger subscriptions
* `TriggerAction` - Represents an active trigger subscription
* `Method<T>` - Callback interface for Java compatibility
