> ## 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.

# Messages

> React to messages sent, edited or deleted, in servers or in private, from people or from bots

Three events are about messages: `messageCreate`, `messageUpdate` and `messageDelete`. A `messageCreate` event runs every time someone writes in a server your bot is in:

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

export default event({
  name: 'messageCreate',
  async run({ message }) {
    if (message.content === '!ping') await message.reply('Pong!');
  },
});
```

That is all. By default, the file only runs for messages written **by people, in servers**: not for bots (yours included), not for webhooks, and not for private messages. So `message.guild`, `message.channel` and `message.member` are always there, and you never write `if (message.author.bot) return;`.

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

export default event({
  name: 'messageCreate',
  async run({ message }) {
    // No "?." needed: a message of a server has a server, a channel and a member.
    console.log(`${message.member.displayName} wrote in #${message.channel.name} of ${message.guild.name}`);
  },
});
```

> [!NOTE]
>
> The full list of what a message has is in [Message](https://www.chapterjs.org/reference/message.md); the three events, with what they give, are in the [reference](https://www.chapterjs.org/reference/events.md#messagecreate).

## Message Content Intent

Reading what people write is a **privileged intent**: `messageCreate` and `messageUpdate` need the Message Content Intent, enabled for your bot in the [Developer Portal](https://www.chapterjs.org/setup/discord-application.md). Without it, the messages written by other people come without their text: `message.content` is empty. `chapterjs dev` tells you when it is missing and waits for you to enable it, like for every [intent](https://www.chapterjs.org/events.md#intents-nothing-to-list). `messageDelete` does not need it.

## Where a file listens

`where` says where a declaration listens. Write it next to `name`, and what your function receives follows it:

> [tab] 'guild' (default)
>
> The file runs for the messages of servers. The message is a [`MemberMessage`](https://www.chapterjs.org/reference/message#membermessage): `guild`, `channel` and `member` are always there.
>
> ```ts src/events/hello.ts theme={"theme":{"light":"github-light","dark":"vesper"}}
> import { event } from 'chapterjs';
>
> export default event({
>   name: 'messageCreate',
>   async run({ message }) {
>     await message.channel.send(`Hello ${message.member.displayName}!`);
>   },
> });
> ```

> [tab] 'dm'
>
> The file runs for the private messages people send to your bot. The message is a [`DmMessage`](https://www.chapterjs.org/reference/message#dmmessage): nothing about a server exists on it, so your editor does not even offer `message.guild`.
>
> ```ts src/events/support.ts theme={"theme":{"light":"github-light","dark":"vesper"}}
> import { event } from 'chapterjs';
>
> export default event({
>   name: 'messageCreate',
>   where: 'dm',
>   async run({ message }) {
>     await message.reply(`Thanks ${message.author.displayName}! A moderator will answer you soon.`);
>   },
> });
> ```

> [tab] 'both'
>
> The file runs for both. The message is a `MemberMessage` or a `PrivateMessage` (`MemberMessage | PrivateMessage`), told apart by `message.guild`: one `if` narrows everything, and inside it the channel and the member are the ones of a server.
>
> ```ts src/events/everywhere.ts theme={"theme":{"light":"github-light","dark":"vesper"}}
> import { event } from 'chapterjs';
>
> export default event({
>   name: 'messageCreate',
>   where: 'both',
>   async run({ message }) {
>     if (message.guild) {
>       await message.channel.send(`Hello ${message.member.displayName}!`);
>     } else {
>       await message.reply('Hello! We are in private here.');
>     }
>   },
> });
> ```

Each file decides for itself: in the same folder, one file can listen in servers and another in private messages.

> [!NOTE]
>
> `chapterjs dev` runs your bot in your test server only, so a file with `where: 'dm'` can't be tried there. It tells you once:
>
> ```text theme={"theme":{"light":"github-light","dark":"vesper"}}
> ℹ src/events/support.ts this messageCreate file only works in private messages, and chapterjs dev only runs your bot in My Server. Try it with chapterjs start.
> ```
>
> Private messages reach your bot with [`chapterjs start`](https://www.chapterjs.org/run/start).

## Messages of bots and webhooks

By default, `messageCreate` and `messageUpdate` ignore the messages written by bots (this one included) and by webhooks: a bot that answers bots can end up answering itself, or another bot, forever. To receive them too, pass `{ bots: true }`:

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

export default event({
  name: 'messageCreate',
  bots: true,
  async run({ message }) {
    // Also runs for bots and webhooks: make sure it can't answer itself.
    if (message.webhookId) console.log(`A webhook posted: ${message.content}`);
  },
});
```

With `bots: true`, the message of a server is a [`GuildMessage`](https://www.chapterjs.org/reference/message#guildmessage): `guild` and `channel` are still there, but a webhook is not a member of the server, so `message.member` can be `null`.

Both options go together: `{ bots: true, where: 'both' }` receives everything, as a `GuildMessage | PrivateMessage`.

## A deleted message

A message that was deleted no longer exists, so the `message` of `messageDelete` is what is left of it: its `id`, the `channel` it was in, and `before`, the message itself **as it was** when the bot remembered it.

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

export default event({
  name: 'messageDelete',
  run({ message, guild }) {
    console.log(`Message ${message.id} was deleted in #${message.channel.name} of ${guild.name}`);
  },
});
```

In a server, `guild` and `message.channel` (a `GuildTextBasedChannel`) are always there. `message.before` is `null` when the bot did not remember the message: the bot [remembers no message](https://www.chapterjs.org/memory.md) today, so always use `message.id`.

`messageDelete` takes `where` like the other two, and what your function receives follows it: with `'dm'`, there is no `guild` nor `message.guildId` at all; with `'both'`, `guild` is `null` for a private message and tells the two apart. It has no `bots` option: a deleted message has no author anymore.

## Intents follow your options

Discord sends the messages of servers and private messages through two different intents, and ChapterJS only asks for what your files listen to: a file with `where: 'dm'` asks for private messages only, a file without `where` for the messages of servers only, and a file with `'both'` for both.

```text theme={"theme":{"light":"github-light","dark":"vesper"}}
ℹ Intents computed from your files: GUILDS, GUILD_MESSAGES, MESSAGE_CONTENT
```

## A channel the bot does not know

A message can arrive in a channel your bot has never seen, like a thread created before it connected. ChapterJS then asks Discord for that channel once, before running your files, so that `message.channel` is always there. Everything that happens in that channel meanwhile waits for the same answer, and is delivered in the order it happened. When Discord refuses, the event is not delivered and you are told:

```text theme={"theme":{"light":"github-light","dark":"vesper"}}
⚠ A messageCreate event was not given to your files: Discord did not let the bot read the channel it happened in (Discord refused GET /channels/{channel.id}: Missing Access (50001)).
```

> [card] [Sending messages](https://www.chapterjs.org/messages.md)
>
> Everything a reply can contain: text, embeds, files, polls.

> [card] [What your bot remembers](https://www.chapterjs.org/memory.md)
>
> Members, users and messages: what is kept, and how little it costs.


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