Skip to content

Stream group updates with XMTP

Stream group metadata changes (name, description, members) in real-time using the group_updated native content type. Group updates allow you to monitor changes to group conversations including member additions/removals, name changes, and description updates.

Listen for group updates

on('group-update', async (ctx) => {
  // handle the group update
  console.log(`Group updated: ${JSON.stringify(ctx.message.content)}`);
});

Group update message structure

{
  conversationId: string,
  contentType: { typeId: "group_updated" },
  content: {
    metadataFieldChanges?: Array<{
      fieldName: string,        // "group_name", "group_description", etc.
      oldValue: string,
      newValue: string
    }>,
    addedInboxes?: Array<{     // New members added
      inboxId: string
    }>,
    initiatedByInboxId?: string // Who triggered the update
  }
}

Usage examples

Monitor group name changes

on('group-update', async (ctx) => {
  const content = ctx.message.content as any;
 
  const nameChange = content.metadataFieldChanges?.find(
    (change) => change.fieldName === 'group_name'
  );
 
  if (nameChange) {
    console.log(
      `Group renamed: ${nameChange.oldValue} → ${nameChange.newValue}`
    );
  }
});

Monitor member additions

on('group-update', async (ctx) => {
  const content = ctx.message.content as any;
 
  if (content.addedInboxes?.length > 0) {
    console.log(`New members added: ${JSON.stringify(content.addedInboxes)}`);
  }
});

Monitor member removals

on('group-update', async (ctx) => {
  const content = ctx.message.content as any;
 
  if (content.removedInboxes?.length > 0) {
    console.log(`Members removed: ${JSON.stringify(content.removedInboxes)}`);
  }
});

Filter by specific group

const targetGroupId = 'your-group-conversation-id';
 
on('group-update', async (ctx) => {
  if (ctx.message.conversationId === targetGroupId) {
    console.log(`Target group updated: ${JSON.stringify(ctx.message.content)}`);
  }
});