# Groups

URL: https://pieowl.com/docs/get-started/groups





Groups let you associate users with a shared entity — like a company, workspace, or team — and analyze behavior at that level. Instead of asking "what did Jane do?", you can ask "what is Acme Inc doing?"

This is especially useful for B2B SaaS products where a single paying account has many users.

How Groups work [#how-groups-work]

There are two separate concepts:

1. **The group entity** — created/updated with `upsertGroup()`. Stores metadata about the group (name, plan, etc.).
2. **Group membership** — set with `setGroup()` / `setGroups()`. Links a user profile to one or more groups, and automatically attaches those group IDs to every subsequent `track()` call.

The examples use `pieowl`, a `Pieowl` instance from `@pieowl/web` or `@pieowl/sdk`. With the script tag, call the same methods on `window.pieowl`, for example `window.pieowl('setGroup', 'org_acme')`.

Creating or updating a group [#creating-or-updating-a-group]

Call `upsertGroup()` to create a group or update its properties. The group is identified by its `id` and `type`.

```typescript
pieowl.upsertGroup({
  id: 'org_acme',        // Your group's unique ID
  type: 'company',       // Group type (company, workspace, team, etc.)
  name: 'Acme Inc',      // Display name
  properties: {
    plan: 'enterprise',
    seats: 25,
    industry: 'logistics',
  },
});
```

Group payload [#group-payload]

| Field        | Type     | Required | Description                                         |
| ------------ | -------- | -------- | --------------------------------------------------- |
| `id`         | `string` | Yes      | Unique identifier for the group                     |
| `type`       | `string` | Yes      | Category of group (e.g. `"company"`, `"workspace"`) |
| `name`       | `string` | Yes      | Human-readable display name                         |
| `properties` | `object` | No       | Custom metadata about the group                     |

Managing groups in the dashboard [#managing-groups-in-the-dashboard]

The easiest way to create, edit, and delete groups is directly in the Pieowl dashboard. Open your site and go to the **Groups** section — from there you can manage group names, types, and properties without touching any code.

`upsertGroup()` is the right tool when your group properties are **dynamic and driven by your own data** — for example, syncing a customer's current plan, seat count, or MRR from your backend at login time.

<Callout>
  A good rule of thumb: call `upsertGroup()` on login or when group properties change — not on every request or page view. If you find yourself calling it frequently with the same data, the dashboard is probably the better place to manage that group.
</Callout>

Assigning a user to a group [#assigning-a-user-to-a-group]

After identifying a user, call `setGroup()` to link them to a group. This also attaches the group ID to all future `track()` calls for the current session.

```typescript
// After login
pieowl.identify({ profileId: 'user_123' });

// Link the user to their organization
pieowl.setGroup('org_acme');
```

For users that belong to multiple groups:

```typescript
pieowl.setGroups(['org_acme', 'team_engineering']);
```

<Callout>
  `setGroup()` and `setGroups()` persist group IDs on the SDK instance. All subsequent `track()` calls will automatically include these group IDs until `clear()` is called.
</Callout>

Full login flow example [#full-login-flow-example]

`setGroup()` doesn't require the group to exist first. You can call it with just an ID — events will be tagged with that group ID, and you can create the group later in the dashboard or via `upsertGroup()`.

```typescript
// 1. Identify the user
pieowl.identify({
  profileId: 'user_123',
  firstName: 'Jane',
  email: 'jane@acme.com',
});

// 2. Assign the user to the group — the group doesn't need to exist yet
pieowl.setGroup('org_acme');

// 3. All subsequent events are now tagged with the group
pieowl.track('dashboard_viewed');  // → includes groups: ['org_acme']
pieowl.track('report_exported');   // → includes groups: ['org_acme']
```

If you want to sync dynamic group properties from your own data (plan, seats, MRR), add `upsertGroup()` to the flow:

```typescript
pieowl.identify({ profileId: 'user_123', email: 'jane@acme.com' });

// Sync group metadata from your backend
pieowl.upsertGroup({
  id: 'org_acme',
  type: 'company',
  name: 'Acme Inc',
  properties: { plan: 'pro' },
});

pieowl.setGroup('org_acme');
```

Per-event group override [#per-event-group-override]

You can attach group IDs to a specific event without affecting the SDK's persistent group state:

```typescript
pieowl.track('file_shared', {
  filename: 'q4-report.pdf',
  groups: ['org_acme', 'org_partner'], // Only applies to this event
});
```

Groups passed in `track()` are **merged** with any groups already set on the SDK instance.

Clearing groups on logout [#clearing-groups-on-logout]

`clear()` resets the profile, device, session, and all groups. Always call it on logout.

```typescript
function handleLogout() {
  pieowl.clear();
  // redirect to login...
}
```

Common patterns [#common-patterns]

B2B SaaS — company accounts [#b2b-saas--company-accounts]

```typescript
// On login
pieowl.identify({ profileId: user.id, email: user.email });
pieowl.upsertGroup({
  id: user.organizationId,
  type: 'company',
  name: user.organizationName,
  properties: { plan: user.plan, mrr: user.mrr },
});
pieowl.setGroup(user.organizationId);
```

Multi-tenant — workspaces [#multi-tenant--workspaces]

```typescript
// When user switches workspace
pieowl.upsertGroup({
  id: workspace.id,
  type: 'workspace',
  name: workspace.name,
});
pieowl.setGroup(workspace.id);
```

Teams within a company [#teams-within-a-company]

```typescript
// User belongs to a company and a specific team
pieowl.setGroups([user.organizationId, user.teamId]);
```

API reference [#api-reference]

`upsertGroup(payload)` [#upsertgrouppayload]

Creates the group if it doesn't exist, or merges properties into the existing group.

```typescript
pieowl.upsertGroup({
  id: string;       // Required
  type: string;     // Required
  name: string;     // Required
  properties?: Record<string, unknown>;
});
```

`setGroup(groupId)` [#setgroupgroupid]

Adds a single group ID to the SDK's internal group list and sends an `assign_group` event to link the current profile to that group.

```typescript
pieowl.setGroup('org_acme');
```

`setGroups(groupIds)` [#setgroupsgroupids]

Same as `setGroup()` but for multiple group IDs at once.

```typescript
pieowl.setGroups(['org_acme', 'team_engineering']);
```

What to avoid [#what-to-avoid]

* **Calling `upsertGroup()` on every event or page view** — call it on login or when group properties actually change. For static group management, use the dashboard instead.
* **Not calling `setGroup()` after `identify()`** — without it, events won't be tagged with the group and you won't see group-level data in the dashboard.
* **Forgetting `clear()` on logout** — groups persist on the SDK instance, so a new user logging in on the same session could inherit the previous user's groups.
* **Using `upsertGroup()` to link a user to a group** — `upsertGroup()` manages the group entity only. Use `setGroup()` to link a user profile to it.
