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.

Stream group updates

on('group-update', async (ctx) => {
  console.log('Group updated:', ctx.message.content);
});

Conversation type will show as group_updated.

const type = ctx.message.contentType;

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:`, 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:`, 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:', ctx.message.content);
  }
});