# Custom Signals

## What are custom signals?

Custom signals allow you to provide additional context when capturing user interactions. ContextSDK processes more than 300 built-in signals, but you can enhance its predictions by including app-specific data — such as in-game progress, friend count, or prior interactions like ad views or feature usage. Any past event that may influence a user’s decision-making process is valuable to include.

{% hint style="warning" %}
Important: Never send personally identifiable information (PII) to the SDK. See [Privacy Considerations](https://docs.contextsdk.com/context-decision/advanced/custom-signals#privacy-considerations) to learn more.
{% endhint %}

## Why add custom signals?

By adding custom signals, you can:

* Provide additional context when making upsell or engagement decisions to improve the precision of ML models.
* Optimize monetization and user experience based on real-time behavioral data.

Despite that, it's worth noting that adding custom signals is optional. Not all apps and businesses have environment- or user-specific signals that would make a significant difference when deciding whether to show an upsell offer or not.

## How to add custom signals

You can define custom signals at two levels:

### Global Signals

Global signals apply to all context evaluations and persist across different flows. Use them for app-wide metrics, such as total session count or the number of purchases made. Usage example:

{% tabs %}
{% tab title="iOS" %}

```swift
ContextManager.setGlobalCustomSignal(id: "number_of_levels_completed", value: 21)
```

{% endtab %}

{% tab title="Android" %}
{% tabs %}
{% tab title="Kotlin" %}

```kotlin
ContextSDK.globalCustomSignals["number_of_levels_completed"] = 21
```

{% endtab %}

{% tab title="Java" %}

```java
ContextSDK.Companion.getGlobalCustomSignals().set("number_of_levels_completed",
21);
```

{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="Flutter" %}

```dart
_contextSdkPlugin.setGlobalCustomSignals({
  'number_of_levels_completed': 21,
});
```

{% endtab %}

{% tab title="Unity" %}

```csharp
ContextSDKBinding.SetGlobalCustomSignal("number_of_levels_completed", 21);
```

{% endtab %}

{% tab title="React Native" %}

```javascript
setGlobalCustomSignals({ number_of_levels_completed: 21 })
```

{% endtab %}
{% endtabs %}

To update a signal, call `setGlobalCustomSignal(id:value:)` with the same ID and a new value. To remove a global signal, pass a `null-like` value.

### Flow-Specific Signals

Use flow-specific signals when a signal is relevant only to a particular flow. These signals are passed as parameters when capturing a context. Usage example:

{% tabs %}
{% tab title="iOS" %}

```swift
let customSignals: [CustomSignal] = [
    CustomSignalBool(id: "watched_ad", value: true),
    CustomSignalFloat(id: "percentage_onboarding_finished", value: 0.3),
    CustomSignalString(id: "upsell_copy_button_used", value: "Purchase Premium"),
]
ContextManager.fetchContext(flowName: "onboarding_upsell", customSignals: customSignals) { context in
    // Handle context evaluation
}
```

{% endtab %}

{% tab title="Android" %}
{% tabs %}
{% tab title="Kotlin" %}

```kotlin
val customSignals = CustomSignals(
    mapOf(
        "number_of_friends" to SignalValue.IntValue(4),
        "percentage_onboarding_finished" to SignalValue.FloatValue(0.3f),
        "upsell_copy_button_used" to SignalValue.StringValue("Purchase Premium"),
    )
)
ContextSDK.fetchContext("onboarding_upsell", 3, customSignals) { context ->
    // Handle context evaluation
}
```

{% endtab %}

{% tab title="Java" %}

```java
CustomSignals customSignals = new CustomSignals();
customSignals.set("number_of_friends", 4);
customSignals.set("percentage_onboarding_finished", 0.3f);
customSignals.set("upsell_copy_button_used", "Purchase Premium");

ContextSDK.Companion.fetchContext("onboarding_upsell", 3, customSignals, realWorldContext -> {
    // Handle context evaluation
});
```

{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="Flutter" %}

```dart
_contextSdkPlugin.fetchContext("onboarding_upsell", customSignals: {
  'watched_ad': true,
  'percentage_onboarding_finished': 0.3,
  'upsell_copy_button_used': 'Purchase Premium',
}, (context) async {
  // Handle context evaluation
})
```

{% endtab %}

{% tab title="Unity" %}

```csharp
CustomSignals customSignals = new CustomSignals();
customSignals.AppendCustomSignal("watched_ad", true);
customSignals.AppendCustomSignal("percentage_onboarding_finished", 0.3f);
customSignals.AppendCustomSignal("upsell_copy_button_used", "Purchase Premium");

ContextSDKBinding.FetchContext("onboarding_upsell", delegate (Context context) {
    // Handle context evaluation
}, customSignals);
```

{% endtab %}

{% tab title="React Native" %}

```javascript
fetchContext({
  flowName: 'onboarding_upsell',
  onContextReady: async (context) => {
    // Handle context evaluation
  },
  customSignals: {
    watched_ad: true,
    percentage_onboarding_finished: 0.3,
    upsell_copy_button_used: 'Purchase Premium',
  },
});
```

{% endtab %}
{% endtabs %}

Flow-specific signals ensure that only relevant data is included in decision-making for a particular flow.

## Privacy Considerations

When using custom signals, ensure that no personally identifiable information (PII) is included. ContextSDK does not process sensitive data, such as:

* User IDs
* Email addresses or phone numbers
* IP addresses
* Exact locations
* Date of birth or age
* Gender

You are responsible for ensuring that you have the necessary rights to provide data to ContextSDK.

By leveraging custom signals, you can refine ContextSDK’s predictions and optimize monetization strategies — all while maintaining user privacy and security.
