Full Integration of Castle

This chapter assumes that you have completed the Baseline Integration.

Step 1. Secure Mode

This feature prevents hackers and bad actors from spoofing requests and impersonating your users. It also prevents bad actors from feeding Castle’s risk engine with fake data. If you are using Castle’s risk scores to lock or challenge user accounts (recommended), you’ll want to make sure you have this enabled to prevent those bad actors from locking user accounts.

Secure mode works by requiring a backend generated signature on all incoming requests. Signatures are in SHA-256 HMAC hex format and should use your API Secret (viewable in your Castle dashboard) and the User ID value being tracked in identify.

Secure mode will activate automatically once we receive your first valid request with the proper signature.

Once secure mode has been activated, non-secured requests will be rejected

<script type="text/javascript">
  _castle('identify', 'e325bcdd10ac');
    "<%= OpenSSL::HMAC.hexdigest('sha256', 'YOUR_API_SECRET', 'e325bcdd10ac') %>");
<script type="text/javascript">
  _castle('identify', 'e325bcdd10ac');
    "<?= hash_hmac('sha256', 'e325bcdd10ac', 'YOUR_API_SECRET'); ?>");

Step 2. Tracking Password Resets

Castle can track scenarios where a password reset request is made for a particular user account. Our engine is able to ingest password resets made for both existing users and non-existent users, and can also ingest the values in the username field on each attempt. We can also track when the legitimate users successfully reset their accounts or when they fail to do so.

  • $password_reset_request.succeeded: A successful attempt was made to reset a user's password.
  • $password_reset_request.failed: Use to record a failed attempt to reset a user's password e.g. reset request for non-existing user. The signature of this event is identical to $login.failed
  • $password_reset.succeeded: The user completed all of the steps in the password reset process and the password was successfully reset. Password resets do not require knowledge of the current password.
  • $password_reset.failed: Use to record when a user failed to reset their password.

Step 3. Tracking User Profile Updates

Some bad actors will attempt to immediately change the profile information after successfully taking over an account. By tracking the $profile_update.succeeded event Castle is able to ingest these profile updates and will adapt the risk score if we detect anomalies around these kinds of activities.

Castle not only tracks when the profile was updated, but also detects when the profile details were actually changed by monitoring the following user_traits for updates:

  • email
  • phone
  • address

As well as when you set the following field to true:

  • password_changed

If you wish to not disclose the actual values for other fields than the password, there is also a *_changed version for each field, e.g. phone_changed

The update monitoring is trained to only detect actual updates and discard formatting updates such as updating phone from "+1 414-245-9224" to "4142459224".

    event: '$profile_update.succeeded',
    user_id: 'e325bcdd10ac',
    user_traits: {
      email: 'johan@castle.io',
      password_changed: true,
      phone: '+14142549224',
      address: {
        street: '466 8th St, Suite 201',
        city: 'San Francisco',
        postal_code: '94103',
        region: 'California',
        country: 'United States'
rescue Castle::Error => e
  puts e.message
try {
    'event' => '$profile_update.succeeded',
    'user_id' => 'e325bcdd10ac',
    'user_traits' => array(
      'email' => 'johan@castle.io',
      'password_changed' => true,
      'phone' => '+14142549224',
      'address' => array(
        'street' => '466 8th St, Suite 201',
        'city' => 'San Francisco',
        'postal_code' => '94103',
        'region' => 'California',
        'country' => 'United States'
} catch (Castle_Error $e) {
  // ...
    'event': '$profile_update.succeeded',
    'user_id': 'e325bcdd10ac',
    'user_traits': {
        'email': 'johan@castle.io',
        'password_changed': True,
        'phone': '+14142549224',
        'address': {
            'street': '466 8th St, Suite 201',
            'city': 'San Francisco',
            'postal_code': '94103',
            'region': 'California',
            'country': 'United States'
CastleContext context = Castle.contextBuilder()

ImmutableMap userTraits = ImmutableMap.builder()
  .put("email", "johan@castle.io")
  .put("password_changed", true)
  .put("phone", "+14142549224")

curl https://api.castle.io/v1/track \
  -X POST \
  -H "Content-Type: application/json" \
  -d '
      "event": "$profile_update.succeeded",
      "user_id": "e325bcdd10ac",
      "user_traits": {
        "email": "johan@castle.io",
        "password_changed": true,
        "phone": "+14142549224",
        "address": {
          "street": "466 8th St, Suite 201",
          "city": "San Francisco",
          "postal_code": "94103",
          "region": "California",
          "country": "United States"
      "context": {
        "client_id": "a97b492d-dcc3-4fc1-87d6-65682955afa5",
        "ip": "",
        "headers": {
          "User-Agent": "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko",
          "Accept": "text/html",
          "Accept-Language": "en-us,en;q=0.5"

Step 4. Mobile SDKs

Castle offers support for iOS and Android with our SDKs. If you have a mobile application, downloading these SDKs enriches the behavioral profiles of your users and their devices. It will also allow Castle to build behavioral profiles of uniquely mobile users if those login events are coming from a different backend.

Follow the Mobile Integration Guide to get started on iOS and Android.