Home / admin / chatter-group-governance
chatter-group-governance
Use when admins are governing the Chatter group lifecycle — creation policy, public/private/unlisted visibility decisions, group ownership transfer when owners leave, archived vs inactive vs deleted state changes, auto-archive behavior, naming conventions, group templates (Information Templates), and orphan-group cleanup after user terminations.
Open the skill folder on GitHub
Chatter Group Governance
Activate this skill when an admin needs to design or repair Chatter group lifecycle controls — naming, visibility, ownership, archival, and cleanup. The skill is about governance of the group population, not about feed noise inside a single group (use admin/chatter-notification-tuning for that).
Before Starting
Gather this context before proposing changes:
- How many groups exist and how many are dormant. Run a quick
SELECT COUNT(Id) FROM CollaborationGroupand a follow-up grouped byIsArchived. Most orgs that ask for "governance" have 5–20× more groups than active people, with the bulk dormant for 12+ months. - Who can create groups today. Group creation is a user permission, not a Chatter Settings checkbox: "Any user with the Create and Own New Chatter Groups permission can create public, private, and unlisted groups, including in any Experience Cloud sites they belong to" (Object Reference,
CollaborationGroupSpecial Access Rules, object_reference.txt L67098–67099). Retrieve the profiles and permission sets and read who actually holds it — broad grants are the single biggest driver of sprawl. Unlisted groups are separately gated by the org settingunlistedGroupsEnabledinChatter.settings(api_meta.txt L112602–112608). - What ownership currently looks like. Run
SELECT OwnerId, COUNT(Id) FROM CollaborationGroup WHERE IsArchived = false GROUP BY OwnerId ORDER BY COUNT(Id) DESC. Concentrations of ownership on inactive users (User.IsActive = false) are the primary cleanup target. TheOwnerIdof a group remains pointed at the deactivated user — Salesforce does not auto-reassign on user deactivation. - Archiving levers, in order. Three of them, at different scopes. Org-wide:
allowChatterGroupArchivinginChatter.settingscovers "whether manual and automatic group archiving are allowed on all Chatter groups" (api_meta.txt L112476–112480) — afalsehere removes the archive option entirely, not just the sweep. Per group, automatic:CollaborationGroup.IsAutoArchiveDisabledexempts one group from the sweep (object_reference.txt L67282–67290). Per group, manual:IsArchived(L67274–67281). Inactivity is measured againstLastFeedModifiedDate— "the date of the last post or comment on the group" (L67298–67314) — so a description edit or a member add does not reset the clock. - Are end users creating private groups for sensitive content? Private and Unlisted groups bypass the standard sharing model for posts inside the group — a Private group is a parallel data island. Compliance teams care.
Questions to Ask Before Configuring
Ask these before touching Setup or writing a cleanup script. Each one maps to a gotcha that turns a tidy-looking cleanup into an irreversible one.
| Ask | Why it matters | What a good answer adds |
|---|---|---|
| "Who in this org holds Manage Unlisted Groups, and can they name themselves?" | View All Data and Modify All Data do not reach unlisted groups (L67109–67115), so an "all groups" report run by a system admin is silently incomplete | Either a named compliance holder, or the decision to set unlistedGroupsEnabled to false |
"Is allowChatterGroupArchiving on, and has anyone turned it off to stop surprise archiving?" | That flag covers manual archiving too (api_meta.txt L112476–112480); with it off, delete is the only lever and delete cascades to files shared elsewhere | The right fix — per-group IsAutoArchiveDisabled — instead of an org-wide switch |
| "For the groups you want to keep alive, is anyone posting, or only reading?" | The archive clock runs on LastFeedModifiedDate, the last post or comment (L67298–67314); reads never advance it | The exemption list to set IsAutoArchiveDisabled = true on, before the next sweep |
| "Do any of these groups hold files that are also shared somewhere else?" | Deleting a group "removes the files from other locations where they were shared" (L67402–67404) | The archive-vs-delete split, decided on evidence rather than on inactivity alone |
| "Who is the transfer target, and are they a person or a service account?" | Only the owner or a Modify All Data holder can repoint OwnerId (L67378–67379); a person-owner re-orphans on their next departure | A steward account for ownership plus a named human manager for moderation |
| "Is this cleanup happening alongside a batch user deactivation?" | Deactivating multiple users at once hard-deletes the EntitySubscription rows between them, unrecoverable on reactivation (L111169–111174) | A sequencing decision, and an EntitySubscription export taken before the wave |
"Are guests (CanHaveGuests) already true on any group in scope?" | That flag "cannot be set back to false" once true (apexrefguide.txt L111947–111948) | An honest exit plan — remove guests and archive — instead of a promise to close the group later |
What a proper configuration adds over just archiving the dead groups: the org keeps a discoverable, auditable group population — every active group has a reachable owner, every exemption from the archive sweep is a deliberate per-group flag rather than an org-wide switch, unlisted groups are either governed by a named permission holder or turned off, and the settings baseline lives in source control so the next org inherits the same policy instead of rediscovering it.
Core Concepts
Concept 1 — Three group types, three sharing models
CollaborationGroup.CollaborationType is a picklist with three values that drive visibility very differently:
| Type | Discoverable in group list | Posts visible to | Membership requires approval |
|---|---|---|---|
| Public | Yes | All internal users (and Customer Community users with feed access if so configured) | No — anyone can join |
| Private | Yes (name + description visible, posts not) | Members only | Yes — owner / manager approves |
| Unlisted | No — and not to View All Data / Modify All Data holders either; only Manage Unlisted Groups reaches it | Members and Manage Unlisted Groups holders | Invitation only |
Two consequences admins miss:
- A Public group is the only type where post content is visible to non-members. If the goal is "broadcast announcement," Public is correct. If the goal is "team workspace with sensitive material," it must be Private or Unlisted.
- Unlisted groups are invisible to admin seniority as well as to end users, and this is the most-often-wrong belief in the topic. The guide states it twice: a View All Data holder "can't view unlisted group information, unless they have the Modify Unlisted Groups permission as well," and a Modify All Data holder "can't view or modify unlisted group information, unless they have the Manage Unlisted Groups permission as well" (L67109–67115). A SOQL query run by an ordinary system admin therefore returns an incomplete group list and says nothing about what it omitted. Either provision Manage Unlisted Groups to named compliance holders or set
unlistedGroupsEnabledtofalse—references/metadata-examples.mdsections 1 and 2 carry both.
Concept 2 — Archived ≠ Inactive ≠ Deleted
Three distinct lifecycle states. Confusing them is the most common admin error:
- Active —
IsArchived = false. Group accepts new posts, members receive notifications, group counts against any per-org group limits in shipped product features. - Archived —
IsArchived = true. Set by the org's automatic sweep againstLastFeedModifiedDate, or manually by the owner or a Modify All Data holder. Archived groups:- Stay in
CollaborationGroup— not deleted. - Past posts and members are preserved and queryable.
- No new posts accepted via UI; the group becomes read-only.
- Members continue to be members;
EntitySubscriptionrecords persist. - The group can be unarchived (manually only) and resume activity.
- Stay in
- Deleted — record-level
deleteonCollaborationGroup, and the cascade reaches outside the group: "Deleting a group permanently deletes all posts and comments to the group. It also deletes all files and links posted to the group and removes the files from other locations where they were shared" (L67402–67404). Compliance impact: the audit trail of group conversations is gone, and so is any file that also lived in three other places.
There is no "Inactive" state in metadata — the term is colloquial for "Archived but not yet Deleted." Decide explicitly: archive (preserve audit trail, hide from active lists) or delete (purge permanently).
Concept 3 — Group ownership and the deactivated-owner problem
CollaborationGroup.OwnerId is a hard reference to a User record. Two non-obvious behaviors:
- Deactivating the owner does NOT reassign the group. The user is set
IsActive = false. The group'sOwnerIdstill points at them. The group continues to function — members can post, the group can be modified by other group managers — but the owner-only operations (deleting the group, transferring it, changing its type) are now stuck unless a system admin intervenes. - Only the current owner or a Modify All Data holder can transfer ownership — "Only the current group owner or people with the Modify All Data permission can update the
OwnerId" (L67378–67379). Not "an admin" loosely: that specific permission. The member-side note says the same thing from the other direction — "To change the group owner, use theOwnerIdfield on theCollaborationGroupobject" (L67477–67478) — so promoting someone to group manager is explicitly not a transfer.
The governance pattern: every group should have a backup manager (a CollaborationGroupMember with CollaborationRole = 'Admin' — "Managers can post and comment, change member roles, edit group settings, add and remove members, delete posts and comments, and edit the group information field", L67473–67476). The backup manager covers moderation but cannot transfer ownership; a Modify All Data holder must do that. So the offboarding workflow is:
- Detect groups owned by users being deactivated (run before the deactivation, ideally).
- Reassign owner to the named backup manager (or to a generic "Chatter Stewards" service account if no backup exists).
- Then deactivate the user.
Doing it in the other order leaves orphaned-owner groups that require manual cleanup later.
Concept 4 — Group templates (Information Templates) and naming conventions
Salesforce ships Group Information Templates — admin-configured Markdown-style templates that prefill the group's "Information" tab on creation. Two practical uses:
- Encode naming convention in the template. The template can include explicit guidance ("Name format:
Team-<Department>-<Purpose>") and required sections (Charter, Members, Cadence). Users who follow the template produce navigable groups; users who skip the template produce orphans. - Encode lifecycle policy in the template. Include "Owner backup," "Auto-archive after N days," "Delete trigger" sections. This makes the policy visible at creation time, not buried in admin docs.
Templates do not enforce anything — a determined user can ignore them. But combined with restricting group creation to a permission set (so only "trained" users can create groups at all), they cut sprawl materially.
A common structural naming convention for orgs of any size:
<Type>-<Scope>-<Purpose>
Examples:
Project-AcmeMigration-CoreTeam ← a project workstream
Team-Sales-EnterpriseAEs ← a standing team
Topic-Salesforce-ReleaseTrack ← an interest / topic group
Announce-AllHands ← broadcast group
Customer-AcmeCorp-AccountTeam ← a customer-specific group
Prefixes like Project-, Team-, Topic-, Announce-, Customer- make bulk operations (archive all Project-* groups closed last quarter) trivial via SOQL WHERE Name LIKE 'Project-%'.
Recommended Workflow
- Retrieve the metadata baseline and lint it.
sf project retrieve start --metadata Settings:Chatter,PermissionSet,Profile, then run the bundled checker:python3 scripts/check_chatter_group_governance.py --manifest-dir force-app/main/defaultTwo findings stop everything else:
CGG-UNLISTED-UNGOV(unlisted groups are on and nobody holds Manage Unlisted Groups, so your inventory in step 2 will be incomplete) andCGG-ARCHIVE-OFF(archiving is disabled org-wide, so the archive branch of step 4 does not exist yet).references/metadata-examples.mdsections 1–2 carry the deployableChatter.settingsandPermissionSetshapes for whatever you have to change. - Export the group population and lint that too. Groups are data, not metadata — the export query
is in
references/metadata-examples.mdsection 3. Run it as a user who holds Manage Unlisted Groups if step 1 says one exists, then:python3 scripts/check_chatter_group_governance.py \ --manifest-dir force-app/main/default \ --group-inventory groups.csv \ --name-prefixes Project- Team- Topic- Announce- Customer- \ --inactive-days 365CGG-INV-ORPHANis the ownership-transfer queue,CGG-INV-STALEthe archive queue,CGG-INV-EMPTYthe delete candidates,CGG-INV-NAMINGthe convention debt. Record the counts — they are the baseline you re-measure against in step 7. - Decide creation policy, and write it as metadata. Move Create and Own New Chatter Groups off
profiles and onto a named
Chatter_Group_Creatorpermission set; addUnlisted_Group_Auditorif the org keeps unlisted groups. Both shapes are inreferences/metadata-examples.mdsection 2 — read the UNVERIFIED note there about the permission API names before you deploy them. - Reassign every orphaned owner, before you archive anything. Use the manager-first script in
references/metadata-examples.mdsection 4: it prefers an active group manager and falls back to a steward service account, in three queries and one partial-success DML. Archiving a group whose owner is already gone just hides the problem — gotchas 2 and 3. - Split stale from empty, then archive or delete. Archive (
IsArchived = true) anything withsubstantive history; delete only groups the checker flagged
CGG-INV-EMPTYand whose directCollaborationGroupMembercount you confirmed —MemberCountis a nillable rollup, gotcha 9. Before any delete, check the group's files: the delete cascade removes them from every other location they were shared into, gotcha 7. Standing groups that should never auto-archive getIsAutoArchiveDisabled = trueinstead (section 5 of the metadata examples), not an org-wide setting change. - Wire the offboarding hook and sequence it. Ownership transfer runs before
User.IsActiveflips.Read
references/llm-anti-patterns.mdanti-pattern 2 first — the obvious record-triggered Flow is the wrong shape here. And if this is a deactivation wave, read gotcha 11: deactivating several users at once hard-deletes the follow relationships between them, with no restore on reactivation. - Re-measure quarterly and diff the counts. Re-run both checker invocations from steps 1–2.
CGG-INV-ORPHANshould trend to zero,CGG-INV-NAMINGshould fall as the permission set narrows who creates groups, and a rising archived-to-active ratio is health, not decay. Commit theChatter.settingsand permission-set files so the policy travels with the org.
Reference Files
| File | Read it when |
|---|---|
references/metadata-examples.md | Writing the deployable Chatter.settings and PermissionSet XML, the package.xml and sf project commands, or any of the data-side artefacts — inventory SOQL, ownership-transfer Apex and CSV, archive/unarchive updates, orphan and empty-group detection |
references/gotchas.md | The cleanup ran and something is irreversible, invisible, or missing — unlisted groups absent from an audit, files vanished from unrelated records, a manager who cannot take over a group, a name collision on a bulk load |
references/examples.md | Working a scenario end to end before any XML exists — inventory, creation lockdown, bulk reassignment, the archive-vs-delete call, auto-archive tuning, and the Group Information Template |
references/well-architected.md | Justifying open creation vs permission-set restriction, archive vs delete, or person-owner vs steward-owner — and locating the official source behind a claim in this skill |
references/llm-anti-patterns.md | Reviewing output an AI assistant produced here, especially "just delete the dormant groups" or an offboarding Flow that deactivates and reassigns in one transaction |
templates/chatter-group-governance-template.md | Running workflow steps 1–2 — the inventory, policy, and disposition worksheet |
scripts/check_chatter_group_governance.py | Workflow steps 1, 2, and 7 — before any settings deploy and before any bulk archive or delete |
Related Skills
admin/chatter-notification-tuning— feed noise, digest frequency, and notification volume tuning inside groups (this skill governs the group population; that skill governs what's noisy inside a group)apex/apex-connect-api-chatter— programmatic group creation / membership / posting via Connect APIadmin/user-management— broader user-deactivation workflow that this skill plugs into for the ownership-transfer step