> ## Documentation Index
> Fetch the complete documentation index at: https://www.chapterjs.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Reactions and voice

> React to the reactions people add and to who joins a voice channel, and see why some events only give an id

People do more on Discord than write: they react to messages, vote in polls, join voice channels. Each of these is an event too, with its name. This page adds two to your bot, a bookmark that works with a reaction and a greeting in voice, and shows what is different about them: some events come with less than a message does.

## A bookmark with a reaction

Create `src/events/bookmark.ts`:

```ts src/events/bookmark.ts theme={"theme":{"light":"github-light","dark":"vesper"}}
import { event } from 'chapterjs';

export default event({
  name: 'reactionAdd',
  async run({ reaction: { emoji, member, channel, messageId }, guild }) {
    if (emoji.name !== '🔖') return;
    const link = `https://discord.com/channels/${guild.id}/${channel.id}/${messageId}`;
    await member.send(`You bookmarked a message in #${channel.name}: ${link}`);
  },
});
```

Save it, then react 🔖 to any message of your test server: the bot sends you its link in private. There was no switch to turn on this time:

```text theme={"theme":{"light":"github-light","dark":"vesper"}}
↻ Your files now need more from Discord (GUILD_MESSAGE_REACTIONS): reconnecting...
```

Reactions are not privileged: Discord does not consider them personal, unlike what people write.

The function receives the `reaction` and the server, `guild`, and takes from the reaction what it needs: `emoji`, `member`, `channel`, `messageId`. `emoji` is the emoji of the reaction. For a standard emoji, `emoji.name` is the character itself (`'🔖'`); a custom emoji of a server has a name and an `id`.

## Safe by default, again

The rules of the [previous page](https://www.chapterjs.org/tutorial/message-events.md) hold here: by default a reaction file runs **for people, in servers**. The reactions of bots are left out, yours included, so the file never reacts to what it does itself; `bots: true` lets them in. And because the file listens in servers, `guild`, and the `channel` and `member` of the reaction, are always there, with no `?.` to write. `where: 'dm'` or `where: 'both'` change that exactly like for messages.

## Only an id for the message

Look at what the reaction holds: `messageId`, not a message. When someone reacts, Discord sends who reacted and with what, but not the message: it may be years old. And your bot [remembers no message](https://www.chapterjs.org/tutorial/memory-and-limits.md). So the reaction gives its id, and `reaction.message` is `null`.

Often the id is enough: the link above is built from it, without asking Discord anything. When you really need the message, ask for it: `await channel.fetchMessage(messageId)`. Do it after the checks, never for every reaction.

`reactionRemove` goes further: Discord sends only the id of who removed their reaction. ChapterJS asks Discord who it is the first time, then remembers them, so `reaction.user` is always there; `reaction.member` is only there when the bot remembers that member.

## Hello in voice

Create `src/events/greeter.ts`:

```ts src/events/greeter.ts theme={"theme":{"light":"github-light","dark":"vesper"}}
import { event } from 'chapterjs';

export default event({
  name: 'voiceJoin',
  async run({ voice: { member, channel } }) {
    await channel.send(`Welcome to ${channel.name}, ${member.displayName}!`);
  },
});
```

Join a voice channel of your test server: the bot writes in the chat of that channel. Every voice channel has a text chat, and `voice.channel` is a `VoiceChannel` you can send to. The function receives `voice` (who, where, and their voice state) and the server, `guild`.

Discord tells a bot only that "someone's voice state changed". ChapterJS remembers who is in which channel, compares, and gives you four events instead of one:

| `name` | Runs when |
| - | - |
| `voiceJoin` | Someone joins a voice channel |
| `voiceLeave` | Someone leaves, or is disconnected |
| `voiceMove` | Someone goes from one channel to another |
| `voiceUpdate` | Someone mutes, deafens, starts a stream or a camera |

## And the others

Polls (`pollVoteAdd`), typing (`typingStart`), bans (`banAdd`), the audit log, invites, emojis, scheduled events, threads and presences all work the same way: an `event()` with the name of the event, and what your function receives typed from that name. The [Guide](https://www.chapterjs.org/events.md) has a page for each family.

## Points of attention

* **A reaction gives an id, not a message.** Build what you can from the ids; fetch the message only when you need it.
* **Reactions are frequent.** Like for messages, keep the check first and cheap, and `return` early.
* **Presences are privileged, and heavy.** `presenceUpdate` needs the Presence Intent and arrives for every change of every member: only add it when your bot really needs it.
* **Voice greetings can be noisy.** Someone reconnecting five times gets greeted five times: keep the message short, or write it only in some channels.

## Recap

* `reactionAdd`, `reactionRemove`, `pollVoteAdd`, `typingStart`, the voice events and the others are declared with `event()`, like `memberJoin`.
* Reactions ignore bots and private messages by default, like messages; `bots` and `where` change it.
* Every event gives what it is about and `guild`: `reaction`, `vote`, `voice`... Some only hold ids: `reaction.messageId` is always there, `reaction.message` is `null`; `user` is asked to Discord once when needed.
* Four voice events tell a join, a leave, a move and a change apart.

> [card] [Playing in voice](https://www.chapterjs.org/tutorial/voice.md)
>
> Make your bot join a voice channel and play a sound.

> [card] [Guide: Reactions, polls and typing](https://www.chapterjs.org/events/reactions.md)
>
> The same events, in short.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.