Ephemeral Messages

Ephemeral messages are visible only to a specific user within a thread. They're useful for confirmations, hints, and private notifications.

Send an ephemeral message

lib/bot.ts
await thread.postEphemeral(user, "Only you can see this!", {
  fallbackToDM: true,
});

The fallbackToDM option is required. It controls what happens on platforms without native ephemeral support:

  • fallbackToDM: true: send the message as a DM instead. If the adapter can't open DMs either, nothing is sent and the call returns null.
  • fallbackToDM: false: don't send anything, and return null.

Platform behavior

PlatformNative supportBehaviorPersistence
SlackYesEphemeral in channelSession-only (disappears on reload)
Google ChatYesPrivate message in spacePersists until deleted
TeamsYesTargeted message in conversationTeams-managed
DiscordNoDM fallbackPersists in DM

Discord slash command responses can be made ephemeral with the Discord adapter's interactionFlags option. Outside that interaction flow, postEphemeral still follows the fallback behavior.

Check for fallback

lib/bot.ts
const result = await thread.postEphemeral(user, "Private notification", {
  fallbackToDM: true,
});

if (result?.usedFallback) {
  console.log("Sent as DM instead of ephemeral");
}

Graceful degradation

To send only when the platform supports native ephemeral messages, set fallbackToDM to false and check for null:

lib/bot.ts
const result = await thread.postEphemeral(user, "Contextual hint", {
  fallbackToDM: false,
});

if (!result) {
  // Platform doesn't support native ephemeral
  // Message was not sent
}

Ephemeral cards

Cards work with ephemeral messages too:

lib/bot.tsx
await thread.postEphemeral(
  event.user,
  <Card title="Ephemeral Card">
    <CardText>Only you can see this card.</CardText>
    <Actions>
      <Button id="open_modal" style="primary">Open Modal</Button>
    </Actions>
  </Card>,
  { fallbackToDM: true }
);

Read more