Playbook Rules

5 min read

Footprint’s rules engine enables you to customize user onboarding decisioning to fit your business’s risk model.

When you create a playbook from a template, rules nodes are preloaded with a default set of rules. Businesses may find this default set of rules sufficient, or they may choose to customize the onboarding flow using the Footprint rules editor. Rules are written as CEL (Common Expression Language) expressions.

Rule evaluation

Rules enable businesses to express custom logic for risk decisioning or data collection. For example, rules can be used for each of the following:

  • Assign final user statuses based on different risk signals.
  • Split an onboarding flow based on user attributes (e.g. different onboarding flows for U.S. and international users).
  • Define Enhanced Due Diligence (EDD) or step-up flows.

A rules node sets an outcome value based on the data and risk signals available during onboarding. Rules are organized into groups, where each group has a value and a set of associated rules. Groups are evaluated in the order they are displayed (top-to-bottom), and a group matches if any of its associated rules evaluates to true. The first matching group's value is used, and the result is written to an onboarding data key (e.g. data.kyc_outcome) that the rest of the playbook can act on. If no group matches, the default value is used. A default value is required and is always displayed last.

Rules as CEL expressions

Rules are expressions written in CEL (Common Expression Language) — a simple, type-safe language from Google — that evaluate during onboarding to either true or false. They are composed of input features, comparison expressions, and boolean operators.

Input features have the format <namespace>.<feature>. There are three namespaces of features:

  • risk_signal: Risk signals derived from verification checks
  • vault: Data vaulted during onboarding
  • data: Values computed earlier in the onboarding flow (for example, by an upstream rules or expression node)

Within each of the namespaces is a number of features (for example, risk_signal.watchlist_hit_ofac, vault.id.country, and data.charge_risk_score).

Features available to a rule are suggested as you type in the rules editor. Press CTRL + SPACE to see the variables available in the current scope.

Risk signal expressions

Risk signal input features in the risk_signal namespace take on boolean values (true or false), indicating whether that risk signal was triggered by a verification check. Therefore, the simplest rule is a single risk signal. For example:

Rule
1risk_signal.watchlist_hit_ofac

This rule evaluates to true if the verification checks yielded this risk signal.

The ! operator negates a risk signal, meaning the following evaluates to true if the verification checks did not yield this risk signal:

Rule
1!risk_signal.watchlist_hit_ofac

The complete list of risk signals available can be found in the Risk Signal Glossary.

Vault data expressions

Vault data input features in the vault namespace take on string values. The features in this namespace map one-to-one to the vault fields listed here. For example id.zip is available to rules as the feature vault.id.zip and business.country is available as vault.business.country.

Since rules are boolean expressions and vault data features are strings, vault data features must be compared to a specific value. CEL uses == for equality:

Rule
1vault.id.country == "US"

This would evaluate to true if the country entered during onboarding is US.

Vault data also supports inequality checks with the != operator:

Rule
1vault.id.country != "CA"

You can also check membership in a list with the in operator:

Rule
1vault.id.country in ["US", "CA", "MX"]

Compound rule expressions

Expressions can be composed together with the logical operators ! (not), && (and), and || (or), and grouped using parentheses to express more complex conditions. For example:

Rule
1risk_signal.device_high_risk && (!risk_signal.attested_device_apple || vault.id.country != "US")

The && operator takes precedence over the || operator, and the ! operator has the highest precedence. Take for example this rule without parentheses:

Rule
1!risk_signal.attested_device_apple || vault.id.country != "US" && !risk_signal.device_high_risk

Formatted with parentheses to clarify the order of operations, the above rule is equivalent to:

Rule
1(!risk_signal.attested_device_apple)
2||
3(
4    vault.id.country != "US"
5    &&
6    (!risk_signal.device_high_risk)
7)

Because CEL is a full expression language, rules can also use ternaries (? :), string functions, and helpers like size(...) when you need them.

Best practices

To keep your rules easy to understand, you may split up top-level || expressions into multiple rules within the same group. Take for example this compound rule:

Rule
1!risk_signal.document_ocr_name_matches || !risk_signal.document_selfie_matches

This rule can be split up into two rules in the same group:

Rule
1!risk_signal.document_ocr_name_matches
Rule
1!risk_signal.document_selfie_matches

Since a group matches if any one of its associated rules matches, these two rule sets express the same logic.