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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.contextsdk.com/context-decision/advanced/custom-signals.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
