# Set up built-in Personalizers

**URL:** https://heroiclabs.com/docs/hiro/guides/personalizer/setup-personalizers/
**Keywords:** set up built-in personalizers, hiro, setup personalizers
**Categories:** hiro, setup-personalizers, personalizer

---


# Set up built-in Personalizers

This guide explains how to set up Hiro's built-in Personalizers to enable dynamic, real-time configuration changes without requiring deployments.

Hiro provides two built-in [Personalizer](../../../concepts/personalizer/) implementations:

- **`StoragePersonalizer`**: Pulls configuration from Nakama storage objects for server-wide changes
- **`SatoriPersonalizer`**: Pulls configuration from Satori Feature Flags for audience targeting, experiments, and live events

You can use either one, both, or extend them by creating your own custom implementation.

## Before you start

Before you set up Hiro's built-in Personalizers, ensure you have:

- [Installed Nakama](../../../../nakama/getting-started/install/docker/)
- [Installed Hiro](../../../concepts/getting-started/install/)
- Initialized Hiro systems with at least one configured system (Achievements, Economy, Energy, etc.)
- An active Satori account if you wish to use `SatoriPersonalizer`

## Set up `StoragePersonalizer`

`StoragePersonalizer` lets you modify configuration using Nakama storage objects. Changes apply to all players equally, making it useful for balance patches, bug fixes, and manual rollouts.

### Register `StoragePersonalizer`

On the server, add `StoragePersonalizer` after initializing your Hiro systems:

{{< code type="server" filename="main.go">}}

```go
systems, err := hiro.Init(ctx, logger, nk, initializer, binPath, hiroLicense,
  hiro.WithBaseSystem("base-system-dev1.json", true),
  // Register other Hiro systems here
)
if err != nil {
  return err
}

systems.AddPersonalizer(hiro.NewStoragePersonalizerDefault(logger, initializer, true))
```

{{< /code >}}

This creates the configuration pipeline: JSON → Storage

### Import the storage template

Hiro provides a pre-configured JSON template that creates storage collections for each Hiro system.

1. Download the [storage template JSON](https://github.com/heroiclabs/hiro/blob/main/personalizer_storage_nakama.json) from the Hiro repository.

2. Open your Nakama Console and navigate to **Settings** > **Data Management**.

3. Upload the JSON file.

The template creates a storage collection for each Hiro system. You'll see collections appear in the **Storage** section of your Nakama Console.

<figure>
  <img src={{< fingerprint_image "images/hiro-datadefinition-example.png" >}} alt="Hiro data definition storage collections in Nakama Console">
  <figcaption>After importing the JSON file, the new storage objects will appear under the collection "hiro_datadefinitions"</figcaption>
</figure>

### Verify `StoragePersonalizer` works

To verify `StoragePersonalizer` is working, modify a configuration value in storage and check if it applies to your game.

1. In your Nakama Console, navigate to **Storage**.

2. Find the collection for the Hiro system you want to modify (for example, `hiro_achievements`).

3. Create or edit a storage object to override a configuration value. For example, to modify an achievement's reward:

```json
{
  "collection": "hiro_achievements",
  "key": "achievements",
  "user_id": "00000000-0000-0000-0000-000000000000",
  "value": {
    "first_win": {
      "reward": {
        "currencies": {
          "gems": {
            "min": 200
          }
        }
      }
    }
  }
}
```

- This overrides the `first_win` achievement's reward to grant 200 gems instead of the base configuration value.

4. In your game client, call the relevant Hiro operation (for example, `GetAchievements()`).

   The personalized configuration should reflect your storage changes. If the achievement now grants 200 gems, `StoragePersonalizer` is working correctly.

## Set up `SatoriPersonalizer`

`SatoriPersonalizer` lets you modify configuration using Satori Feature Flags. This enables audience targeting, A/B testing, time-limited events, and real-time adjustments based on player behavior. It can also publish gameplay events to Satori, enabling you to track player actions and use that behavioral data for segmentation and targeting.

{{< note "important" >}}
`SatoriPersonalizer` requires a Satori instance. [Satori](../../../../satori/) is Heroic Labs' LiveOps platform for managing player engagement, experiments, and personalization.
{{< /note >}}

### Configure the Satori connection

Before you can use `SatoriPersonalizer`, connect your Nakama server to your Satori instance.

1. Open your Satori Console and navigate to **Settings** > **API Keys**.

2. Copy the **API Key Name** and **API Key** values.

3. Navigate to the **Configuration** tab in your Satori Console.

4. Search for `session.signing_key` and copy its value.

5. Open your Nakama server's `local.yml` configuration file.

6. Add the Satori connection settings:

{{< code type="server" filename="local.yml" hideable="false">}}

```yaml
# Replace the placeholder values with the values you copied from your Satori Console.
satori:
  api_key_name: "default"
  api_key: "00000000-0000-0000-0000-000000000000"
  signing_key: "abcdefghijklmnop"
  url: "https://<satori-address>:443"
```

{{< /code >}}

7. Restart your Nakama server to apply the configuration changes.

{{< note "important" >}}
You must configure the Satori connection on every environment where you want to use `SatoriPersonalizer` (dev, QA, production, etc.). Each environment needs its own configuration in the respective Nakama server settings.
{{< /note >}}

### Register `SatoriPersonalizer`

After configuring the Satori connection, register `SatoriPersonalizer` in your server code.

Add `SatoriPersonalizer` after initializing your Hiro systems:

{{< code type="server" filename="main.go">}}

```go
systems, err := hiro.Init(ctx, logger, nk, initializer, binPath, hiroLicense,
  hiro.WithBaseSystem("base-system-dev1.json", true),
  // Register other Hiro systems here
)
if err != nil {
  return err
}

systems.AddPersonalizer(hiro.NewSatoriPersonalizer(ctx))
```

{{< /code >}}

After registering `SatoriPersonalizer`, you can use Satori Feature Flags to personalize your Hiro configuration. Satori automatically creates Feature Flags for each Hiro system (following the `Hiro-[SystemName]` naming convention). You just need to enable and edit them with your personalized configuration. For details on working with Feature Flags, see [Satori Feature Flags](../../../../satori/concepts/remote-configuration/).

The example above registers `SatoriPersonalizer` for remote configuration only. To also publish gameplay analytics events to Satori, which enables player segmentation and behavioral targeting, you pass event publishing options when initializing it. See [Publishers](../../../concepts/publishers/#satoripersonalizer) for the full list of options, including important guidance on session behavior when both Nakama and your game client send events to Satori.

### Verify `SatoriPersonalizer` works

To verify `SatoriPersonalizer` is working, check if your Feature Flag configuration applies to your game.

1. In your game client, call the relevant Hiro operation (for example, `GetAchievements()`).

   The personalized configuration should include your Feature Flag changes. If the new `holiday_champion` achievement appears in the results, `SatoriPersonalizer` is working correctly.

2. To test audience targeting, create a Feature Flag with specific audience conditions and verify it only applies to targeted players.

## Chain both Personalizers

You can use both `StoragePersonalizer` and `SatoriPersonalizer` together to create layered customizations. This creates a three-layer configuration pipeline: JSON → Storage → Satori.

Register both Personalizers in order:

{{< code type="server" filename="main.go">}}

```go
systems, err := hiro.Init(ctx, logger, nk, initializer, binPath, hiroLicense,
  hiro.WithBaseSystem("base-system.json", true),
  // Register other Hiro systems here
)
if err != nil {
  return err
}

systems.AddPersonalizer(hiro.NewStoragePersonalizerDefault(logger, initializer, true))
systems.AddPersonalizer(hiro.NewSatoriPersonalizer(ctx))
```

{{< /code >}}

### Example: Layered personalization

This example shows how chaining Personalizers creates layered customizations:

**Base configuration** (JSON files):

```json
{
  "daily_reward": {
    "name": "Daily Reward",
    "reward": {
      "guaranteed": {
        "currencies": {
          "gems": {
            "min": 100
          }
        }
      }
    }
  }
}
```

`StoragePersonalizer` returns:

```json
{
  "daily_reward": {
    "reward": {
      "currencies": {
        "gems": {
          "min": 150
        }
      }
    }
  }
}
```

`SatoriPersonalizer` returns (for experimental cohort):

```json
{
  "daily_reward": {
    "reward": {
      "currencies": {
        "gems": {
          "min": 200
        }
      }
    }
  }
}
```

**Final result:**

- Most players receive 150 gems (JSON + Storage)
- Experimental cohort receives 200 gems (JSON + Storage + Satori)

## See also

- [Personalizers](../../../concepts/personalizer/): Learn about how Personalizers work and when to use them.
- [Publishers](../../../concepts/publishers/): Learn about using Publishers to enrich event data sent by Hiro.
- [Satori Feature Flags](../../../../satori/concepts/remote-configuration/): Learn about Feature Flags in Satori.
- [SatoriPersonalizer source code](https://github.com/heroiclabs/hiro/blob/main/personalizer_satori.go): Reference implementation for building custom Personalizers.
