Custom Signals

By default, Castle exposes a number of Signals that each represent a unique risk behavior. If the tracked event matches, these signals show up as tags on each event record in the Caste Dashboard, so you can easily filter out the ones you're interested in. In addition to these tags, the signals are also returned in the Risk and Filter API calls, so you can implement conditional logic on the backend (however, we recommend using Policies to keep all logic within Castle instead).

In order to model and catch more business specific fraud and abuse signals, Castle allows you to create your own custom ones. For example:

  • Content spamming: By monitoring the frequency and patterns of content submissions, such as comments, reviews, or posts, Signals + Aggregations can flag users who may be engaging in spamming or other abusive behaviors.
  • Fraud rings: Monitor unique user accounts associated with e.g. a specific device fingerprint, credit card or bank account.
  • Password cracking attempts: Use a Signal + Aggregation to can track multiple failed login attempts or password reset requests within a specific time frame or from a single IP address, alerting you to potential brute-force or account takeover attempts.
  • Rate-limit abuse: If your platform imposes rate limits for certain actions (e.g., API calls or messaging), Aggregations can detect and flag users who repeatedly exceed these limits, indicating potential abuse of your system's resources.

Creating a Signal

To create a new signal, head over to the Signals page. When you create a signal you have to define three things:

  1. A name. This will be appearing on each event where the signal conditions match. Eg. "Suspicious behavior" or "Brute Force IP".
  2. An Aggregation (optional). See below for more details. This is optional, but allows you to create a time-series query that produces a number that can be used in the trigger condition. Eg. "Failed login attempts per IP"
  3. A trigger condition. Defines the criteria which all incoming events are matched against. When met, the event will be tagged with the signal name defined earlier.


When you create a new signal you'll have the option to also define an Aggregation query that runs alongside and is evaluated in real-time. With aggregations, you're able to create advanced velocity checks that can detect suspicious patterns in all sorts of activities, both transaction and non-transaction. For example, compute the average transaction amount per user in the last 24h:

Defining a new aggregation is done from within the modal for creating a new Signal, and consists of a few parameters. For those familiar with SQL, parameters for an Aggregation are overall very similar to the parts that make up a (streaming) SQL statement, e.g.

SELECT $count_unique(properties.referral_code)
FROM events
WHERE name = 'Redeem'
HAVING $count_unique(properties.referral_code) > 1 -- trigger condition, defined by the signal
NameA short description of the Aggregation, like "Transactions per user". This will be used as a reference across the Castle Dashboard, e.g. when creating new filters and/or policies
DescriptionAn optional longer description to communicate the intent with this Aggregation. This can be useful for other team members to better understand the behavior
MethodThe aggregation method together with a potential argument. Available options are
- Average ($avg)
- Count Events ($count)
- Count Unique ($count_unique)
- First Value ($first)
- Last Value ($last)
- Max Value ($max)
- Minimum Value ($min)
- Sum ($sum)
Group ByAn optional argument that describes a grouping for the aggregation. For example, you can pick to split up transaction volume per user instead of computing it across the entire app.
WhereDefine optional filters to apply before computing the aggregation. For example, you can filter by $transaction type events to count all transactions per user.

The output from each aggregation is a value (typically a number) that is persisted and available on each event. This means that if you e.g. created a Signal with the name "Transactions per user", this value will be available to use in the filters dropdown. More on this in the next section.

Using Signals

Once created, you can make use of your custom signals in a few different ways. Any custom signal will:

  1. Be available as a filter in the Explore view, and when creating Policies (and more generally wherever a filter can be applied)
  2. The signal aggregation value is also available as a filter. So e.g. if you created a signal for "Brute Force IP" with an aggregation for "Failed logins per IP", this aggregation value will be available to filter your events by. Meaning that you can adjust the threshold of your trigger based on actual historic values.
  3. Be available in the API response from Risk and Filter APIs, and present in the signals object whenever it matches.
  4. Be available in the Events API in the triggered_signals field.
Custom signals in the filter dropdown

Custom signals in the filter dropdown

Managing Signals

From the Signals page you can perform standard actions like create, update or archive signals. In addition, these signals can also be temporarily disabled, which means that incoming events will no longer be tagged with this signal name when matched. Please note that if you've defined an Aggregation as part of the signal, this will also stop being computed.

Signals can be temporarily disabled or archived if no longer used

Signals can be temporarily disabled or archived if no longer used