--- title: Groups description: Track analytics at the account, company, or team level — not just individual users. --- import { Callout } from 'fumadocs-ui/components/callout'; 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 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. ## 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 op.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 | 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 The easiest way to create, edit, and delete groups is directly in the OpenPanel dashboard. Navigate to your project and open 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. 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. ## 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 op.identify({ profileId: 'user_123' }); // Link the user to their organization op.setGroup('org_acme'); ``` For users that belong to multiple groups: ```typescript op.setGroups(['org_acme', 'team_engineering']); ``` `setGroup()` and `setGroups()` persist group IDs on the SDK instance. All subsequent `track()` calls will automatically include these group IDs until `clear()` is called. ## 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 op.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 op.setGroup('org_acme'); // 3. All subsequent events are now tagged with the group op.track('dashboard_viewed'); // → includes groups: ['org_acme'] op.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 op.identify({ profileId: 'user_123', email: 'jane@acme.com' }); // Sync group metadata from your backend op.upsertGroup({ id: 'org_acme', type: 'company', name: 'Acme Inc', properties: { plan: 'pro' }, }); op.setGroup('org_acme'); ``` ## Per-event group override You can attach group IDs to a specific event without affecting the SDK's persistent group state: ```typescript op.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 `clear()` resets the profile, device, session, and all groups. Always call it on logout. ```typescript function handleLogout() { op.clear(); // redirect to login... } ``` ## Common patterns ### B2B SaaS — company accounts ```typescript // On login op.identify({ profileId: user.id, email: user.email }); op.upsertGroup({ id: user.organizationId, type: 'company', name: user.organizationName, properties: { plan: user.plan, mrr: user.mrr }, }); op.setGroup(user.organizationId); ``` ### Multi-tenant — workspaces ```typescript // When user switches workspace op.upsertGroup({ id: workspace.id, type: 'workspace', name: workspace.name, }); op.setGroup(workspace.id); ``` ### Teams within a company ```typescript // User belongs to a company and a specific team op.setGroups([user.organizationId, user.teamId]); ``` ## API reference ### `upsertGroup(payload)` Creates the group if it doesn't exist, or merges properties into the existing group. ```typescript op.upsertGroup({ id: string; // Required type: string; // Required name: string; // Required properties?: Record; }); ``` ### `setGroup(groupId)` 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 op.setGroup('org_acme'); ``` ### `setGroups(groupIds)` Same as `setGroup()` but for multiple group IDs at once. ```typescript op.setGroups(['org_acme', 'team_engineering']); ``` ## 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.