Skip to content

Privacy & the 5-person floor

InPolicy’s analytics are designed to measure policy performance without turning compliance into surveillance. This page explains the privacy model, why some data you might expect to see is hidden, and what you can and can’t do about it.

Our public privacy commitment says: violation and engagement metadata must be non-user-linkable. That one line drove most of how analytics are built:

  • Events don’t carry user IDs.
  • Events don’t carry the text that triggered them.
  • Events don’t carry IP addresses or other network identifiers.
  • Division-level rollups are suppressed below a minimum group size so statistics can’t effectively identify individuals.

None of this is a flag you can flip. It’s how the data is collected, stored, and queried.

What the analytics can and can’t tell you

Section titled “What the analytics can and can’t tell you”
QuestionCan analytics answer?
How many violations did we flag last month?Yes
Which policies trigger most often?Yes
Is the Engineering team generating more violations than Legal?Only if both teams have ≥ 5 people assigned
Which specific person violated policy X?No — by design
Who dismissed a violation card instead of applying the fix?No — by design
Can I export a user-level activity log?No — by design

This is intentional. An InPolicy rollout often sits in the trust gap between “we need to manage compliance” and “we don’t want to create a tattle-tale tool.” The data model resolves that gap by making user-level attribution impossible at the query level.

Division-level analytics are suppressed when fewer than 5 users are assigned to the Division. Specifically:

  • For each Division, we count users where User.department matches the Division’s name (case-insensitive).
  • If that count is less than 5, the Division’s row is hidden from the Team Compliance table.
  • A footer note says how many teams were suppressed.

This is a form of k-anonymity: by requiring at least k=5 people in any reported group, we prevent an aggregate statistic from effectively pointing at an individual. Even “the Legal team had 1 violation last week” becomes identifying information when the Legal team has 2 people — and the point of anonymity is to keep violations collective.

It’s a common threshold in statistical disclosure control: not so high that small-team analytics become useless, not so low that small groups leak. It’s hard-coded — the threshold is not a configuration setting.

  • New tenant with a 3-person “Legal” department → that department is hidden from team analytics until it grows past 5 people.
  • Reorgs that drop a team below 5 → the team disappears from analytics retroactively.
  • Tenant-wide rollups (KPI cards, Top Policies table, Violations by Area, Violations by Severity) always work regardless of team size. The floor only affects the per-team breakdown.

If the Team Compliance table shows “3 team(s) hidden (fewer than 5 members)”, that’s telling you three of your Divisions fell below the threshold over the selected date range.

If every Division is below 5, the table shows: “All teams suppressed by k-anonymity. Assign User.department to at least 5 users per team to surface a row.” Usually this means your tenant hasn’t populated the department field on user records yet.

The 5-person count uses the User.department field — a free-text string on each user record. Two important properties:

  • It’s metadata, not role enforcement. The department field doesn’t gate any permissions. It’s only used for analytics grouping.
  • Matching is case-insensitive. “Engineering”, “engineering”, and “ENGINEERING” all match the same Division name.

Where does the department field come from?

  • SSO-imported users get their department from the directory if the provider exposes it (Workspace and Entra both do).
  • Email-invited users get whatever the inviter typed in the optional “Department” field on the invite form.
  • Anyone else has it set by an admin after the fact, either manually or by re-running a directory import.

If your tenant’s team analytics are mostly hidden, the fix is usually to populate department on more user records.

To be explicit about what the system never writes to disk:

  • The text that triggered a violation is not persisted. The detection API processes the text in-memory and returns the result.
  • Keystroke timing or typing patterns are not captured. The Mac app and extension debounce before sending; nothing about how you type is stored.
  • Screen content is never captured. Neither the Mac app nor the extension has screen-recording permissions.

Violation events stored for analytics carry:

  • The policy ID (what was triggered).
  • The severity (inherited from the policy at event time).
  • The outcome — flagged, accepted, dismissed, self-resolved.
  • The timestamp.
  • (Optionally) the Division, derived from the policy’s Area chain.

That’s it. No text, no user, no session.

When rolling out InPolicy internally, two phrases help:

  1. “Nobody can look up which violations you personally generated.” This is not a policy statement — it’s a technical fact about the data model.
  2. “Team-level analytics only surface for teams of 5+, so small teams don’t become identifiable.” Users on a 3-person team know their team won’t be spotlit.

That usually resolves the “is this going to be used to track me?” concern faster than a legal explanation.