# Events, properties and users

> The language of product data: what an event records and how event and user properties differ.

- Course: [Product Analytics: From Data to Decisions](https://productovi.com/courses/product-analytics.md)
- Module: What exactly are we measuring?
- Lesson 1/32, ~28 min
- Source: https://productovi.com/courses/product-analytics/events-properties-users

## Where you work

**Alex Tutor:** Welcome to the course. Picture **Halves**, a small app that splits bills between flatmates, couples and travel groups. It has a free tier and a paid plan, Halves Plus. You've just joined its product team.

**Alex Tutor:** Product lead Maya and growth marketer Theo will bring you real questions, and you'll answer them from the app's data. We start at the beginning: today, what one row of the raw event log actually says.

![Three flatmates at a kitchen table share a long paper receipt torn into equal strips; one of them holds up a phone.](https://productovi.com/courses/product-analytics/inline/events-properties-users-illustration-2.webp)

*Halves lives in moments like this: a shared bill and a group that wants it split fairly.*

## What one row says

**Maya:** The developers sent me last week's raw export: 147 rows I can't read. What's actually in there?

**Sofia:** Every row starts with a time, a user id and a word like `app_opened`. So each row is one thing a person did?

**Alex Tutor:** Close. Each row is an **event**: a record that something happened. It answers **who** (`user_id`), **what** (`event`) and **when** (`event_time`, in UTC). The other columns are details.

**Dataset (CSV):** [Thirteen rows from Halves's event log, 1–4 June](https://productovi.com/datasets/product-analytics/events-properties-users/halves-events-excerpt.csv)

A few rows picked from last week's export, in time order. Times are UTC.

- `event_time`: When it happened, in UTC
- `user_id`: Who: the Halves account
- `event`: What happened
- `platform`: Where the event was logged: ios, android or server
- `entry_method`: expense_added only: manual, receipt_scan or recurring
- `amount_usd`: Amount in US dollars, for expenses and settle-ups
- `settlement_id`: settle_up_recorded only: which settlement the row belongs to

**Alex Tutor:** Row 4: two minutes after opening the app, u007 added a \$116 expense by scanning a receipt.

**Sofia:** And `entry_method` and `amount_usd` are the details?

**Alex Tutor:** Yes, **event properties**. They describe that one moment. The same person's next expense can have a different amount and method.

![One paper receipt pinned to a corkboard, with a small person figure, a tiny clock and a dangling tag attached to it.](https://productovi.com/courses/product-analytics/inline/events-properties-users-illustration-3.webp)

*One event: who, what and when, plus details that describe only that moment.*

> **Exercise:** Read row 10 of the excerpt: `2026-06-04T18:12:00Z, u020, expense_added, android, manual, 91`. What does it record?

## Event properties and user properties

**Sofia:** The users file has columns too: `signup_date`, `acquisition_channel`, `timezone`. Event properties as well?

**Alex Tutor:** No, **user properties**. They describe the person, not a moment, so they're the same for all of that person's events.

**Dataset (CSV):** [The same six people in the users file](https://productovi.com/datasets/product-analytics/events-properties-users/halves-users-excerpt.csv)

One row per person. These values don't change from event to event.

- `user_id`: The Halves account
- `signup_date`: Date the account was created
- `platform`: The user's phone platform: ios or android
- `acquisition_channel`: How the user came to Halves
- `timezone`: The user's home time zone
- `is_internal`: true for a team account, false for a customer

**Alex Tutor:** Quick test: could the value differ between two events a minute apart? An expense amount can. The channel someone signed up from can't.

**Theo:** I want to know if people from paid social add more expenses than invited people. Where does that answer live?

**Alex Tutor:** In both files. Take `expense_added` events, look up each `user_id` in the users file and group by `acquisition_channel`. Event properties say what happened; user properties split it by who.

![Event properties describe one moment and can change every event; user properties describe the person. Look up user_id to split what happened by who.](https://productovi.com/courses/product-analytics/diagrams/m1-l1-event-vs-user-properties.png)

*Join the two files on user_id to split events by who did them.*

> **Exercise:** Which of these columns are **user properties** rather than event properties?

**Alex Tutor:** One more check on Theo's question before we move on: where should the sign-up channel live?

> **Exercise:** **True or false:** to split `expense_added` events by acquisition channel, every `expense_added` event must carry `acquisition_channel` as an event property.

## What deserves to be an event

**Sofia:** Could Halves Plus be an event too? Something like `user_is_premium`?

**Alex Tutor:** Being on Plus is a state, so it's a user property. *Starting* a trial happens at a moment, so it's an event.

**Alex Tutor:** Name events as object plus past-tense verb: `expense_added`, `group_created`, one name on every platform. If Android logs `addExpense` instead, every report shows two halves of one number.

**Sofia:** And screens? Should “balances screen shown” be an event?

**Alex Tutor:** Only if a question needs it. Log the actions a decision depends on, not every tap: each event has to stay correct through every release.

> **Exercise:** Which of these should Halves log as **events**?

**Alex Tutor:** Back to Halves Plus. Two developers proposed two ways to record it. Which one keeps the data honest?

> **Exercise:** Maya wants to know who is on Halves Plus and when people start trials. Which design would you choose?

## Who logged it: the app or the server

**Sofia:** Row 1 looks odd. u001 added a \$420 expense at 06:00 UTC, and the platform is `server`.

**Alex Tutor:** See `entry_method = recurring`. Plus subscribers can make a bill repeat, like rent, and the server adds it on schedule. u001 may have been asleep.

**Alex Tutor:** That's a **server-side event**: the backend logs it, not the app. It's never lost when a phone is offline, but it can happen with nobody touching Halves.

![At night a small server cabinet slides a rent receipt into a phone on a bedside table while its owner sleeps.](https://productovi.com/courses/product-analytics/inline/events-properties-users-illustration-4.webp)

*A server-side event is logged on schedule, even while nobody touches the app.*

**Alex Tutor:** App events are the opposite: real actions, but a phone with no signal may send them late.

**Maya:** So if I count “people who added an expense”, u001 is in there?

**Alex Tutor:** If you count rows, yes. We'll fix that next lesson. For now, ask of every row: who or what caused it?

> **Exercise:** **True or false:** a row with `event = expense_added`, `platform = server` and `entry_method = recurring` shows that the user opened Halves and added an expense.

**Alex Tutor:** Now count with that question in mind: who actually did something themselves in the excerpt?

> **Exercise:** In the 13-row excerpt, how many **different users** have at least one event logged by the app (platform `ios` or `android`, not `server`)?

## One payment, two rows

**Sofia:** Also, `s004` shows up twice, from u013 and u014, both for \$185. Did they pay each other?

**Alex Tutor:** No, it's one payment. The payer records a settle-up, and when the other person confirms, their phone logs it again. Same `settlement_id`, two rows.

**Alex Tutor:** The log is right. But “how many settle-ups?” is answered by the ids, not the rows.

**Sofia:** So to read a log I need to know how the product works, not just the column names.

**Alex Tutor:** Exactly. For each event, note who triggers it, where it's logged and which properties it carries. That list starts a **tracking plan**, which you'll write at the end of this module.

> **Exercise:** The excerpt has three `settle_up_recorded` rows. How many settle-ups (payments) do they describe?

## Your turn: design an event

**Maya:** Next month receipt scanning will split the bill between people automatically. I'll want to know how often dinners get split this way. What do we log?

**Sofia:** `expense_added` with `entry_method = receipt_scan`, plus something about the split?

**Alex Tutor:** Good start. Keep the existing event rather than inventing `dinner_scanned`, and add properties for Maya's next questions: how many people, split how, in what kind of group.

**Alex Tutor:** For each detail, decide: does it describe this moment or the person? The person's details already live in the users file.

> **Exercise:** Someone in a trip group scans a \$120 dinner receipt in Halves and splits it equally between 4 people. Name the event that should record this and list its properties. For each property, say whether it's an event property or a user property, and why.

> **Key ideas**
>
> - An **event** records who, what and when, plus properties.
> - **Event properties** describe one moment (amount, entry method); **user properties** describe the person (sign-up date, channel, time zone) and are joined from the users table.
> - A state (being on Plus) is a property; a change of state (starting a trial) is an event.
> - **Server-side events** can happen without the user; app events record real actions but can arrive late.
> - One action can leave several rows: both sides log a settle-up under one `settlement_id`.

**Alex Tutor:** Next time we take all 147 rows and count how many people really used Halves last week.

- Next lesson: [Totals, unique users and counting traps](https://productovi.com/courses/product-analytics/counting-traps.md)

---
Productovi Learning. Free, no sign-up needed to read.
