Member statuses are the roles that can be assigned to each participant (inbox ID) in a group chat. These are the available member statuses:
Member
Everyone in a group chat is a member. A member can be granted admin or super admin status. If a member’s admin or super admin status is removed, they are still a member of the group.
Admin
Super admin
When a group is created, all groups have the same initial member “roles” set:
There is one super admin, and it is the group creator
There are no admins
Each user added to the group starts out as a member
If you do not select a policy set, the group uses All members.
Permission
All members
Admin only
Add member
All members
Admin
Remove member
Admin
Admin
Add or remove admin
Super admin
Super admin
Update permissions
Super admin
Super admin
Update name, description, image, app data
All members
Admin
Update disappearing messages
Admin
Admin
DMs use neither set. Participants cannot change membership or permissions, and both can change metadata.
Add admin and remove admin cannot use an allow-all policy. A custom policy can allow admins to perform these actions. Only a super admin can update the permission policies or grant and revoke the super admin role.
A custom set contains nine policies: add member, remove member, add admin, remove admin, update name, update description, update image URL, update disappearing messages, and update app data.
Pass a custom GroupPermissionMode in CreateGroupOptions.permissions. The custom variant contains a PermissionPolicySet. This option is available on all four SDKs.
All four SDKs use group.updatePermission(kind, policy, metadataField). Use PermissionUpdateKind for the action and PermissionPolicy for the policy. For a metadata update, also pass MetadataFieldKind. This includes the disappearing-message and app-data policies. Swift uses the labels kind:, policy:, and metadataField:.
The backend sets the group member limit. The default limit is 250 inboxes.
Use addMembers and removeMembers with a list of inbox IDs or a list of PublicIdentity values. Swift uses the members: label. Call members() to read the member list on all four SDKs. These calls are asynchronous.
A PublicIdentity list can hold handles and accounts together, and each call makes one commit. A handle that no inbox claimed fails the call with IdentityNotFound before any change.
Sync before you read the member list.
Each Member has handle, the inbox’s current handle, and otherHandles, its other handles with the most recent first. Show handle as the text that identifies the member, and show otherHandles only as secondary information. See Show handles.
A member can request removal from a group by calling requestRemoval(). A super admin must process the request before the member is removed. After removal, the group becomes inactive for that member.
The call is refused if the caller is a super admin, is the only member, or is in a DM. After the request is processed locally, group.state() reports membershipState as pending removal. This does not mean that the member has already been removed.
Group chats can have metadata, like names, descriptions, and images. Metadata can help users more easily identify their group chats.
Field
Update
Limit
Name
updateName(name)
100 bytes
Description
updateDescription(description)
1,000 bytes
Image URL
updateImageUrl(url)
2,048 bytes
App data
updateAppData(data, expected)
8,192 bytes
Read metadata from the asynchronous group.state() snapshot on all four SDKs. App data is a string. Pass the previous value as expected to update app data only if it still matches, or pass undefined on Browser and Node or null/nil on mobile to omit that check. Serialize structured data before you set it. See Disappearing messages.
An operator can publish additional fields through
[[application_components]].
These fields can hold a group value, a set, or a map. An inbox-keyed map holds
one value per user. All members who can read the conversation can read these
values. User fields are conversation data, not a global inbox profile.
New groups and DMs register the fields selected by in_groups and in_dms.
Registration defines the type and the insert, update, and delete policies. It
does not set a value. Existing conversations can register missing fields when
a client with registry write authority makes a commit. A backend configuration
change does not replace a field already in the conversation’s registry.
Use the conversation’s descriptors to build a form or validate a value:
Method
Result
metadataFields()
Registered field descriptors, with refs, types, policies, and isUserField.
metadataField(name)
The descriptor with this name, or no result.
metadataValue(field)
A scalar, map, or set value, or no value if unset.
metadataValues(fields)
Field and value records in the order requested.
mapValue(field, key)
One map entry, or no value if the key is absent.
updateMetadataField(field, operation)
A typed change checked against the committed field policies.
A MetadataFieldRef identifies a field by componentId. Its name is a label
from the well-known fields or the client’s backend configuration. A field can
have no name when the local configuration does not name its ID. Keep the ref
from the descriptor. Do not use a backend definition to assume the type or
policy of an existing field.
Use ComponentMutation.Replace on Kotlin or .replace on Swift for a scalar.
Use MapDelta or SetDelta on Kotlin, or .mapDelta or .setDelta on Swift,
for collection changes. Map operations insert, update, or delete one key; set
operations insert or delete one key. A field in the immutable application
range can be set only once. Wrong types, unknown fields, unsupported types, and
denied writes produce typed errors.
Browser and Node use records with kind: "replace", kind: "mapDelta", or
kind: "setDelta". A scalar value is a FieldValue with kind: "string" or
kind: "bytes" and a matching value.
Application scalars, collection keys, and collection values have an 8,192-byte
limit. A serialized collection has a 65,536-byte limit. These limits also apply
to USER_DISPLAY_NAME and GROUP_IMAGE. The existing string fields retain the
limits in the table above.
USER_DISPLAY_NAME is a well-known string map keyed by inbox ID. It is
registered in new groups and DMs. Members can set or remove their own value.
The default policy also lets members remove an entry for an inbox that has
left. An application field such as USER_PRONOUNS can use the same shape and
policies. The USER_ prefix is a naming convention. The inbox-keyed map type
determines whether isUserField is true.
updateUserData(values) uses the caller’s inbox ID. Each value sets that
inbox’s entry; an undefined value on Browser and Node, null on Kotlin,
or nil on Swift removes it. All changes
in the call use one commit. Duplicate fields, non-user fields, and type
mismatches fail the call. Clearing an absent entry makes no change.
The following examples run with an existing group. The operator must publish
GROUP_CATEGORY and USER_PRONOUNS as shown in the backend guide. The group
must have registered them, and the caller must be an admin to set the category.
userData(fields, inboxIds) returns a map from inbox ID to present field and
value records. Omit the filters with undefined on Browser and Node,
null on Kotlin, or nil on Swift to read all user fields for current members
or the two DM participants. An empty filter selects nothing. An inbox with no
selected values has an empty list. Supply inbox IDs to read entries for former
members. Sync before reads when you need changes from other members.
GROUP_IMAGE holds opaque bytes. It is separate from the GROUP_IMAGE_URL
string and is registered in new groups. An app can upload an image with the
attachment API,
serialize the returned RemoteAttachment, and store those bytes with
updateMetadataField. Agree on the serialization format with the other apps
that read the group. The SDK does not parse or fetch these bytes. A reader
decodes the descriptor and explicitly requests the attachment download.