# Understand events

**URL:** https://heroiclabs.com/docs/satori/concepts/performance-monitoring/understand-events/
**Summary:** Events are the behavioral signal Satori uses to build player profiles, compute properties, and populate every metric, report, and audience in your project.
**Keywords:** analytics events, event tracking, player behavior, custom events, event history, computed properties, audience segmentation, event instrumentation, core events, player data, adimpression, ad revenue, IAP revenue
**Categories:** satori, monitoring

---


# Understand players with analytics events

Events are the behavioral signal Satori uses to build player profiles, compute properties, and populate every metric, report, and audience in your project.

## How an event is structured

Each event must have `name`, `value` and `metadata`. Each field has a defined schema that the event must adhere to.

| Field | Description |
|---|---|
| `name` | The unique identifier for the event. Must exactly match the event name registered in **Taxonomy > Events**. |
| `metadata` | Key-value context that describes the event. Use this to enrich analysis and data lake exports.|
| `value` | A measure used for computed properties and metrics. Use this to power automatic computed properties (for example, send the tutorial ID as a value for `tutorialCompleted` to update `tutorialCompletedSeenLast`) and to feed Metrics in the dashboard. |


```json
// Example event (tutorialCompleted):
{
  "name": "tutorialCompleted",
  "value": 3,
  "metadata": {
    "tutorialType": "movement",
    "isSkipped": false
  }
}
```
## How events flow through Satori

When your game fires an event, Satori records it against the player's identity and immediately runs it through the event pipeline. This triggers two things:

- **[Computed properties](../../segmentation/understand-player-properties/#computed-properties)**: Satori generates or updates a set of properties on the identity based on the event (count, timestamps, values). These properties feed your audience filter expressions and segmentation.
- **Metrics and reports**: Events feed directly into the performance monitoring surfaces: the dashboard, retention reports, RoAS calculations, and any custom metrics you define.

If an event isn't fired, it doesn't exist in Satori, and any downstream feature that depends on it will be incomplete or empty.

## View event history per player

Every event your game fires is recorded against the player's identity and visible in the **Events** tab on the identity detail view. Search by keyword or filter by event type or session ID to debug a specific player's event history.

{{< screenshot src="images/pages/satori/concepts/monitoring/player_events_list.gif" alt="Player Events tab showing event name, received timestamp, value, and metadata" >}}

Open any event to see full event details, value, and metadata.

{{< screenshot src="images/pages/satori/concepts/monitoring/monitoring_player_event_detail.png" alt="Player event detail showing session ID, event ID, receive time, value, and metadata" >}}

## Event types

Satori recognizes three types of events.

- [Core events](#core-events)
- [Synthetic events](#synthetic-events)
- [User-defined events](#user-defined-events)

### Core events

Core events are predefined by Satori. They represent standard player behaviors that Satori's built-in audiences, computed properties, and monitoring features depend on. A series of computed properties are automatically generated and tracked per identity for each core event. 

{{< note "important" >}}
Core events are _not_ auto‑captured by the SDK. Your game client (or server, where noted) must fire them to enable downstream features.

Some default [audiences](../../segmentation/understand-audiences/) depend on computed properties generated from these default events. If you don't fire the events, those audiences will be incomplete or empty.
{{< /note >}}


The schema for core events can't be modified. See all core events and their schemas in the Satori console at **Taxonomy > Events** by toggling on **Show Core**. 

{{< accordion title="View all core events" >}}
| Event | Value | Metadata | Description |
|---|---|---|---|
| `achievementClaimed` | any | Object | Indicates an achievement with the given identifier was claimed. |
| `achievementUpdated` | numeric | Object | Indicates an achievement with the given identifier was updated. |
| `adImpression` | any | Event-Revenue-Metadata | The amount in US cents of ad revenue. |
| `adPlacementFailed` | any | Object | Indicates an ad placement with the given identifier has failed. |
| `adPlacementStarted` | any | Object | Indicates an ad placement with the given identifier was started. |
| `adPlacementSucceeded` | any | Object | Indicates an ad placement with the given identifier has succeeded. |
| `adStarted` | string | Object | Indicates an ad with the given identifier was started. |
| `appLaunched` | string | Object | Indicates the application with the given identifier was started. |
| `auctionBid` | any | Object | Indicates an auction with the given identifier was bid. |
| `auctionCancelled` | any | Object | Indicates an auction with the given identifier was cancelled. |
| `auctionClaimBid` | any | Object | Indicates an auction claim with the given identifier was bid. |
| `auctionClaimCreated` | any | Object | Indicates an auction claim with the given identifier was created. |
| `auctionCreated` | any | Object | Indicates an auction with the given identifier was created. |
| `challengeClaimed` | any | Object | Indicates the challenge with the given identifier has been claimed. |
| `challengeCreated` | any | Object | Indicates the challenge with the given identifier has been created. |
| `challengeInvitationAccepted` | any | Object | Indicates the invitation for the challenge with the given identifier has been accepted. |
| `challengeInvitationSent` | any | Object | Indicates an invitation for the challenge with the given identifier has been sent. |
| `challengeJoined` | any | Object | Indicates a player joined the challenge with the given identifier. |
| `challengeLeft` | any | Object | Indicates a player has left the challenge with the given identifier. |
| `challengeUpdated` | numeric | Object | Indicates the challenge with the given identifier has been updated. |
| `currencyGranted` | numeric | Object | Indicates a currency with the given identifier was granted. |
| `currencySpent` | numeric | Object | Indicates a currency with the given identifier was spent. |
| `donationClaimed` | any | Object | Indicates a donation with the given identifier was claimed. |
| `donationGiven` | any | Object | Indicates a donation with the given identifier was given. |
| `donationRequested` | any | Object | Indicates a donation with the given identifier was requested. |
| `energyGranted` | numeric | Object | Indicates an energy with the given identifier was granted. |
| `energyModifierGranted` | numeric | Object | Indicates an energy with the given identifier was modified. |
| `energySpent` | numeric | Object | Indicates an energy with the given identifier was spent. |
| `eventLeaderboardClaimed` | any | Object | Indicates an event leaderboard with the given identifier has been claimed. |
| `eventLeaderboardRolled` | any | Object | Indicates an event leaderboard with the given identifier has been rolled. |
| `eventLeaderboardUpdated` | numeric | Object | Indicates an event leaderboard with the given identifier has been updated. |
| `gameFinished` | string | Object | Indicates a game with the given identifier was finished. A game marks the outer gameplay envelope for a player's session, including menus, loading screens, and other activities. It's distinct from the concept of a match or round. |
| `gameStarted` | string | Object | Indicates a game with the given identifier was started. |
| `incentiveCreated` | any | Object | Indicates an incentive with the given identifier was created. |
| `incentiveDeleted` | any | Object | Indicates an incentive with the given identifier was deleted. |
| `incentiveRecipientClaimed` | any | Object | Indicates an incentive with the given identifier has been claimed by the recipient. |
| `incentiveSenderClaimed` | any | Object | Indicates an incentive with the given identifier has been claimed by the sender. |
| `itemSpent` | numeric | Object | Indicates an item with the given identifier was spent. |
| `itemUpdated` | any | Object | Indicates an item with the given identifier was updated. |
| `itemsConsumed` | numeric | Object | Indicates an item with the given identifier was consumed. |
| `itemsGranted` | numeric | Object | Indicates an item with the given identifier was granted. |
| `progressionPurchased` | any | Object | Indicates a progression with the given identifier was purchased. |
| `progressionReset` | any | Object | Indicates a progression with the given identifier was reset. |
| `progressionUpdated` | numeric | Object | Indicates a progression with the given identifier was updated. |
| `purchaseCompleted` | numeric | Event-Revenue-Metadata | The amount in US cents of the purchase. |
| `purchaseIntent` | any | Object | Indicates that there has been an intent for a purchase with the given identifier. |
| `rewardModifierGranted` | numeric | Object | Indicates a reward with the given identifier was modified. |
| `screenViewed` | string | Object | Indicates a game screen with the given identifier was viewed. |
| `statUpdated` | numeric | Object | Indicates a stat with the given identifier was updated. |
| `teamCreated` | numeric | Object | Indicates a team with the given identifier was created. |
| `tutorialAbandoned` | numeric | Object | Indicates a tutorial with the given identifier was abandoned. |
| `tutorialAccepted` | any | Object | Indicates a tutorial with the given identifier was accepted. |
| `tutorialCompleted` | numeric | Object | Indicates a tutorial with the given identifier was completed. |
| `tutorialDeclined` | any | Object | Indicates a tutorial with the given identifier was declined. |
| `tutorialReset` | any | Object | Indicates a tutorial with the given identifier was reset. |
| `tutorialStarted` | numeric | Object | Indicates a tutorial with the given identifier was started. |
| `tutorialStepCompleted` | numeric | Object | The step number of a multipart tutorial that was completed. |
| `unlockableClaimed` | any | Object | Indicates an unlockable with the given identifier has been claimed. |
| `unlockableCreated` | any | Object | Indicates an unlockable with the given identifier was created. |
| `unlockableSlotPurchased` | numeric | Object | Indicates an unlockable slot has been created. |
| `unlockableUnlockPurchased` | any | Object | Indicates an unlockable with the given identifier has been purchased. |
| `unlockableUnlockStarted` | numeric | Object | Indicates an unlockable with the given identifier has been unlocked. |
{{< /accordion >}}

#### Report ad revenue using core events

To report ad revenue, use the `adImpression` event with the `Event-Revenue-Metadata` metadata schema. The schema has three fields (also viewable in the console at **Taxonomy > Schema Validators**):

| Field | Type | Description |
|---|---|---|
| `amount` | string | The revenue amount in the source currency. |
| `currency` | string | A 3-character ISO 4217 currency code (for example, `USD`, `EUR`, `GBP`). |
| `test` | boolean | Set to `true` to mark this as a test ad or purchase. Omit or set to `false` for production events. |

If your ad network already provides the revenue in US cents, set the `value` field directly. If you need currency conversion, leave `value` as `0` and provide the `amount` and `currency` in the metadata. Satori converts the `amount` and `currency` to a USD equivalent and automatically sets the event's `value` field of the `adImpression` event in US cents. Satori also forwards these events to any configured data lake integrations.

{{< code hideable="false" >}}
```json
{
  "name": "adImpression",
  "value": 0,
  "metadata": {
    "amount": "0.012",
    "currency": "EUR",
    "test": false
  }
}
```
{{< / code >}}

#### Report IAP revenue using core events

For in-app-purchase reporting, use `purchaseCompleted` event. This event expects the `value` field to be a numeric value and the `metadata` field to use the **Event-Revenue-Metadata** schema. Similar to `adImpression` event, set the `value` field directly if you know the revenue in US cents. Alternatively,you can leave the `value` field as 0 as Satori converts the amount reported to USD. Satori uses an external tool to determine the conversation rate for the currency reported to the USD. These rates are updated daily to keep the conversion as close as possible to the real values. The revenue reported by `purchaseCompleted` event is the **gross** revenue before platform commissions and taxes.

{{< code hideable="false" >}}
```json
{
  "name": "purchaseCompleted",
  "value": 0,
  "metadata": {
    "amount": "4.99",
    "currency": "EUR",
    "test": false
  }
}
```
{{< / code >}}

### Synthetic events

Synthetic events, also known as server-side events, are automatically generated and tracked by Satori in response to certain actions. For example, Satori fires `_propertiesUpdate` whenever a player's properties change, whether from a client SDK call or during authentication. You don't need to instrument these.

| Event | Description |
|---|---|
| `_identityCreate` | The Satori identity was created. |
| `_sessionStart` | A new play session has started. |
| `_identify` | An anonymous user has been identified. The previous anonymous identity has been merged into the new identity, along with all of its events. |
| `_propertiesUpdate` | The Satori identity had its properties updated. |
| `_experimentJoin` | The Satori identity joined a phase, including experiment, phase, and variant info. |
| `_liveEventJoin` | The Satori identity joined a live event. |

### User-defined events

User-defined events are events you create for game-specific behaviors that core events don't cover, such as `questCompleted`, `achievementUnlocked`, or `offerViewed`. Like core events, user-defined events must be fired explicitly by your game client. Create and manage them in **Taxonomy > Events** in the console, or programmatically via the [Console API](../../../console/).

Define a custom event in the Satori console before your client sends it. The event name you register here is what your metrics will reference and what your client code must send exactly. 

## Define valid events

In the **Taxonomy** page of the console, the **Events** tab displays the complete list of events that must be accepted by Satori from clients. It describes the list of valid event schemas.

From here you can delete existing events, or create new ones. Note that Satori comes with a set of [core events](#core-events) whose schema configuration can't be modified or deleted.

{{< screenshot src="images/pages/satori/concepts/monitoring/monitoring_taxonomy_events_tab.png" alt="Taxonomy Events tab showing the list of core and user-defined events" >}}

## Update event schema

You can update the value schema and metadata schema of a user-defined event after creation. The event name cannot be changed. You can do this either directly on the console at **Taxonomy > Events** or via the [Console API](../../../console/).

## Validate data with schema validators

Every event's value is checked against a schema to ensure your data remains reliable and consistent. Schema validators define the expected shape of an event's value or metadata field, and Satori rejects any event that doesn't match.

The **Validators** tab in the **Taxonomy** page displays the complete list of schema validators that Satori uses to validate data from Events, Feature Flags, Experiments, and Live Events.

Satori provides the following built‑in validators:

- ANY - Accepts any value; no validation.
- Number - Expects a numeric value.
- String - Expects a string.
- Object - Expects a JSON object (arbitrary keys/values allowed).
- Event‑Revenue‑Metadata - Specialized object for revenue events; include at least amount and currency (and optional test) to enable correct conversion and revenue calculations.

You can define your own validator. If an analytic event requires a specific payload shape, define the validator here first, then reference it when you create the event in the Events tab.

{{< screenshot src="images/pages/satori/concepts/monitoring/monitoring_taxonomy_validators.png" alt="Taxonomy Schema Validators tab showing the list of core validators" >}}

## How Satori handles invalid events

When Satori receives events that don't match your taxonomy, it returns a HTTP 400 error to the client. The rejected events are captured in a temporary buffer, visible at **Taxonomy>Debugger** on the console. See [How to debug invalid analytic events](../../../guides/debug-invalid-events/) to resolve the errors and clear the buffer.

Satori still forwards rejected events through the ingestion pipeline to your data lake (for example, BigQuery), so your data is not discarded. Invalid events will show up in data lake exports with an additional `_error` field in the metadata of the event, to indicate the rejection reasons. You can use the same debug guide to fix the errors. 

## Send the event from the client

Once the event is created, instrument your game client to send it when the relevant action occurs. The event name in your code must exactly match the name you registered in the console.

```csharp
var session = await client.AuthenticateAsync("<playerId>");
await client.EventAsync(session, new Satori.Event("level_complete", DateTime.Now));
```

Satori begins computing metrics and updating audiences as events arrive. The event doesn't need to reach a minimum threshold before you can create a metric against it.

For a step-by-step guide on how to use custom events to drive audience and experiments, see [Experimenting with audiences](../../experiments/experimenting-with-audiences/).

## Tracking players before sign-in

When a player starts your game without signing in, Satori can still track their activity under a temporary identity (typically device-based). If that player later authenticates, Satori merges their guest history into their permanent identity.

Here's what happens:

1. **Player starts as guest:** Your client calls `Authenticate` with a temporary ID. Satori fires `_identityCreate` and `_sessionStart` for this identity.
2. **Player generates activity:** All events, properties, and experiment assignments are tracked under the temporary identity.
3. **Player signs in:** Your client calls `Identify` with the player's permanent ID. Satori fires `_identify`, migrates all data from the temporary identity to the permanent one, and deletes the temporary identity.

See [Identifying a session with a new ID](../../../client-libraries/unity/#identifying-a-session-with-a-new-id) for more details.

## Commonly confused terms

Some Satori terms sound similar but have distinct meanings. The following clarifies what each one means.

### `itemSpent` vs `itemConsumed`

Use the item events to distinguish **cost** from **use**:

{{< table name="satori.concepts.identities.events.itemSpent-itemConsumed-scope" >}}

{{< note "important" >}} If you enable **Satori Publisher** in **Hiro**, `itemSpent` and `itemConsumed` are triggered automatically and forwarded to Satori. See [Publishers](https://heroiclabs.com/docs/hiro/concepts/publishers/) and [Unity analytics](https://heroiclabs.com/docs/hiro/unity/analytics/). {{< /note >}}

## See also


- [How to Send Server-Side Analytic Events](../../../guides/server-events/)
- [How to use Satori for Effective Session Management ](../../../guides/session-management/)
