# Companies and groups

> Count companies, workspaces or teams as well as people in ClickClacks: the group call in the browser, on servers and in mobile apps, traits and Count by.

- Canonical URL: https://clickclacks.io/docs/groups
- Section: Tracking
- Last updated: 2026-10-01

If your customers are companies, count companies. Tell ClickClacks which company a person is acting for, and Insights, Funnels and Retention can count companies as well as people.

A **group type** is a kind of account in your product: `company`, `workspace`, `team`. A **group** is one of them, such as the company `cmp_311`. “Group” is the word in code. In the app you see each type’s own name, so this page says **Companies**.

## How it works {#how}

Each event carries the groups it belongs to, in a `$groups` property. An event counts for a company only when it carries that company:

```json title="a stamped event"
{
  "name": "Report exported",
  "properties": {
    "format": "csv",
    "$distinct_id": "user_8412",
    "$groups": { "company": "cmp_311", "workspace": "ws_91" }
  }
}
```

- **The `group` call** remembers the company and stamps it on every later event from that browser or app. From a server, you add the company to each event yourself.
- **History stays true.** When Dana moves from Acme to Globex, her old events still count for Acme.
- **Nothing is back-filled.** Events sent before the first `group` call never count for the company.
- **Members are worked out, not stored.** A company’s members are the people whose events carried it in the dates you’re looking at.
- **Traits** describe the company: its name, plan, seats. They live in a company profile, separate from events.

Group analytics is on for every project and every plan. The Companies pages and the **Count by** controls stay hidden until your project has received its first group, so a product without company accounts sees no change.

## From the browser {#browser}

Call `group` once after sign-in, next to [identify](https://clickclacks.io/docs/identify.md):

```js
// After sign-in, once you know which company the person is acting for
window.clickclacks('group', 'company', 'cmp_311', {
  name: 'Acme',
  plan: 'pro',
  seats: 40,
})

// A second type, without traits
window.clickclacks('group', 'workspace', 'ws_91')

// Leave the company
window.clickclacks('group', 'company', null)
```

- The browser remembers one ID per type, at most 5 types, and adds them to every later event as `$groups`.
- With traits, the call also sends a `$group_identify` event that carries them. It’s free: it doesn’t count toward your monthly events.
- `null` as the ID leaves the group. [`reset`](https://clickclacks.io/docs/identify.md#reset) and [`optOut`](https://clickclacks.io/docs/consent.md) forget every group.
- A call with a bad type or ID is ignored, like any other bad call.
- Groups are stored per hostname, like the identified ID. Call `group` on each domain where the person is signed in.

The full rules are under [group](https://clickclacks.io/docs/tracker-api.md#group) in the Tracker API.

## From your servers {#server}

A server doesn’t remember anything between events, so there are two parts: a `group` item records the company’s traits, and each event names its company.

**curl**

```bash title="terminal"
curl https://app.clickclacks.io/api/v1/batch \
  -H "Authorization: Bearer $CLICKCLACKS_SERVER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"items":[
    {"type":"group","group_type":"company","group_id":"cmp_311","properties":{"name":"Acme","plan":"pro","seats":40}},
    {"event":"Seats changed","distinct_id":"user_8412","properties":{"seats":41,"$groups":{"company":"cmp_311"}}}
  ]}'
```

**Node**

```ts title="server.ts"
// The company's traits. The newest call replaces the whole set.
clickclacks.group({
  groupType: 'company',
  groupId: 'cmp_311',
  properties: { name: 'Acme', plan: 'pro', seats: 40 },
})

// An event that counts for the company.
clickclacks.track({
  event: 'Seats changed',
  distinctId: 'user_8412',
  properties: { seats: 41 },
  groups: { company: 'cmp_311' },
})
```

**PHP**

```php title="billing.php"
// The company's traits. The newest call replaces the whole set.
$clickclacks->group([
    'groupType' => 'company',
    'groupId' => 'cmp_311',
    'properties' => ['name' => 'Acme', 'plan' => 'pro', 'seats' => 40],
]);

// An event that counts for the company.
$clickclacks->track([
    'event' => 'Seats changed',
    'distinctId' => 'user_8412',
    'properties' => ['seats' => 41],
    'groups' => ['company' => 'cmp_311'],
]);
```

- Over HTTP, an event names its company in `properties.$groups`. The Node and PHP SDKs take a `groups` option and write it for you.
- A `group` item has no person, so it takes no `distinct_id`. Group items are free.
- An event sent without its company never counts for it later.

See [Groups](https://clickclacks.io/docs/api.md#groups) in Send events for the item’s fields, the `warnings` in the response and the error codes, and the [Node](https://clickclacks.io/docs/node.md#groups) and [PHP](https://clickclacks.io/docs/php.md) SDK pages.

## From a mobile app {#mobile}

The React Native and Expo SDK has the same call. It remembers the company on the device and stamps it on every later event.

```ts title="analytics.ts"
clickclacks.group('company', 'cmp_311', { name: 'Acme', plan: 'pro', seats: 40 })

clickclacks.group('company', null) // leave
```

Calling it again with the same traits sends nothing until 7 days have passed, so it’s safe to call on every launch. See [Mobile apps](https://clickclacks.io/docs/mobile.md#groups).

## Traits and privacy {#traits}

- **The newest traits replace the whole set.** Send every trait you want shown each time, not only the one that changed.
- **A `name` trait** is what the app shows for the company. Without one, it shows the ID.
- **Use opaque IDs,** such as `cmp_311`, not a domain name or an email address.
- **Profiles follow your data retention.** A profile whose traits were last sent longer ago than the project keeps events is deleted. Sending traits at sign-in keeps the profiles of active companies current.

A company profile is seen by everyone who can open the project, so traits that look like personal data are left out by default:

- a trait whose value reads as an email address or a phone number;
- a trait named like `email`, `phone`, `ip`, `address`, `password` or `secret`, including names that contain one of those words, such as `billing_email`.

The server API lists each trait it left out in the response’s `warnings`, as `group_trait_dropped`. With `?strict=true` it refuses the item instead. The browser and the mobile SDK get no answer, so there the trait is simply missing from the profile. If you do need a billing contact on the profile, turn on **Allow personal data in group traits** on the source’s page.

## The Companies pages {#companies}

Once your project has received a group, **Companies** appears in the sidebar under **Data**, after People. With two or more group types the entry reads **Groups** and the page has a tab for each type.

- **The list** shows each company’s name and ID, its active members and events in the date range, and when it was last and first seen. Search by name or ID, sort by last seen, events, active members or name, and pin up to three traits as extra columns.
- **A company’s page** shows its traits and when they were last updated, its members in the date range, and its activity, with **Open in Insights** to chart it.
- **A person’s page** lists the companies their recent events carried.
- **Delete profile** removes a company’s saved traits and can’t be undone. Events aren’t changed: they keep their company, so it still appears in reports and in the list, shown by its ID. It needs permission to change the organization’s settings.

To rename a type, reorder types or hide one, open **Lexicon** and the **Group properties** tab. A hidden type leaves the sidebar and Count by; its data is kept. The same tab is where you describe each trait.

## Count by Companies {#count-by}

| Report | Where | What it counts |
| --- | --- | --- |
| **Insights** | The measure menu of each series: **Unique companies** and **Per-company average**. | The companies that did the event, or the events per company. One chart can show unique people beside unique companies. |
| **Funnels** | **Count by People \| Companies** in the builder. | A company enters at its first step-one event and converts when its members, between them, do the steps in order. Dana can sign up and Sam can send the first invite. |
| **Retention** | **Count by** next to the event pickers. | Companies grouped by when they first did the start event. A company is back in a period when any member does the return event. |

- **Only stamped events count.** A company-counted report says how much it left out, for example “12% of these events have no company and aren’t counted”.
- Count by is saved with the report. Funnels and Retention also carry it in the URL, as `?by=company`.
- A funnel that counts companies can’t use events mode, which counts sessions, and sessions belong to people.
- **Compare** in Funnels and Retention lists the segments of what the report counts: company segments of that type when it counts companies, segments of people when it counts people.
- An alert on a funnel or retention report that counts companies counts companies too.
- Insights can also break a series down by company, or by a company trait. Trait breakdowns use each company’s current traits.
- **Flows** always counts people: a company’s events mix several people’s paths.

## Filters and segments {#filters}

- **Filter by company.** The property picker in a report’s filter bar has a **Company** section (the company itself) and **Company properties** (its traits). A chip reads “Company is Acme” or “Company plan is pro”. These filters work in reports that count people too: “people in companies on the Pro plan”.
- **On boards.** A board’s filters take the same company filters, and an insight tile that counts companies keeps doing so on the board.
- **Company segments.** When you create a [segment](https://clickclacks.io/docs/guides/segments.md), choose whether it holds people or companies; it can’t be changed afterwards. A company segment matches on what the company’s members did or never did, on a trait, or on a fixed list. As a filter on any report it means “events from the segment’s companies”, whatever the report counts. It also narrows the Companies list, and Funnels and Retention can compare company segments when they count that type. Realtime takes segments of people only. Company segments have no “did this, then that” sequence condition and no chart of their size over time.

Reading from an AI agent? The [MCP server](https://clickclacks.io/docs/mcp.md#groups) has tools for group types, companies and company profiles.

## Limits {#limits}

| Limit | Value |
| --- | --- |
| Group types on one event | 5 |
| Group types in a project | 5, in the order they first arrive. A sixth is left off the event; the rest of the event is kept. |
| Group type | 1–64 characters of `a–z`, `0–9` and `_`, such as `company` |
| Group ID | A string of 1–255 characters, with no control characters. The browser tracker and the mobile SDK turn a number into a string; the server API refuses a number. |
| Traits from the browser or a mobile app | 2 KB of JSON |
| Traits from the server API | 8 KiB of JSON, 255 keys, nested 5 levels deep |
| Groups in a project | No limit |

## Groups or a project per client? {#agencies}

They answer different questions, so they don’t compete.

|  | A project per client | Groups inside a project |
| --- | --- | --- |
| **Who it separates** | An agency’s clients, or your own separate products | One product’s own customers, such as Acme and Globex |
| **Access** | Strict: a client’s teammates see only their project | None: everyone who can open the project sees every company |
| **Data** | Separate events, keys, sources and data retention | The same events, counted by company |
| **How you switch** | The project switcher | Count by, filters and the Companies pages |

- **An agency gives each client its own project.** That’s the boundary that keeps one client from seeing another’s data. Groups never replace it. See [Agencies](https://clickclacks.io/docs/guides/agencies.md).
- **Use groups inside a client’s project** when that client sells to companies. Its project then counts its own customers.
- **Don’t run several clients through one project as groups.** There is no access control per group.

## Questions {#faq}

### Why doesn’t this old event count for Acme? {#faq-old-events}

It was sent before the browser or app called `group`, or from a server without `$groups`. An event is stamped when it is sent, and is never stamped afterwards.

### Why isn’t Companies in my sidebar? {#faq-not-in-sidebar}

It appears once the project has received an event that carries a group. If it has, check in Lexicon’s Group properties tab that the type isn’t hidden.

### Someone moved to another company. What happens? {#faq-moved}

Call `group` with the new ID. Their later events count for the new company, and their earlier ones stay with the old one.

### Can a person be in two companies at once? {#faq-two-companies}

A browser or app holds one ID per type at a time, so one company and one workspace, but not two companies. From a server, each event names its own company.

### Do group calls use up my events? {#faq-billing}

No. The trait update (`$group_identify`, or a `group` item) is free. Ordinary events count as they always did, with or without a company.

### Do merged people change company counts? {#faq-merge}

No. A merge changes who a person is. The company is on the event, so company counts stay the same.

### Can I remove a company from my events? {#faq-delete}

No. Delete profile removes the traits only; events are never rewritten. Deleting a person removes their events, and with them their part of a company’s counts.

## Next steps {#next}

- [Tracker API](https://clickclacks.io/docs/tracker-api.md#group): the `group` command in full.
- [Send events](https://clickclacks.io/docs/api.md#groups): the `group` item, `$groups` and warnings.
- [Mobile apps](https://clickclacks.io/docs/mobile.md): groups from React Native and Expo.
- [Identify people](https://clickclacks.io/docs/identify.md): the call that goes next to `group`.
