or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

client.mdcommands.mdcomponents.mddiscord-models.mdevents.mdextensions.mdindex.md

events.mddocs/

0

# Events & Listeners

1

2

Comprehensive event system covering Discord gateway events and internal bot events.

3

4

## Event System Overview

5

6

The interactions library provides a rich event system with two main categories:

7

- **Discord Events**: Gateway events from Discord (messages, guilds, users, etc.)

8

- **Internal Events**: Bot lifecycle and framework events (startup, command completion, errors, etc.)

9

10

## Listening to Events

11

12

### Basic Event Listener

13

14

```python

15

from interactions import listen, Client, events

16

17

bot = Client(token="TOKEN")

18

19

@listen()

20

async def on_message_create(event: events.MessageCreate):

21

"""Listen to all message create events"""

22

message = event.message

23

print(f"Message from {message.author}: {message.content}")

24

25

@listen(events.GuildJoin)

26

async def on_guild_join(event: events.GuildJoin):

27

"""Listen to guild join events"""

28

guild = event.guild

29

print(f"Joined guild: {guild.name} ({guild.id})")

30

```

31

32

### Multiple Event Types

33

34

```python

35

@listen(events.MessageCreate, events.MessageUpdate)

36

async def on_message_event(event):

37

"""Listen to both message create and update events"""

38

if isinstance(event, events.MessageCreate):

39

print(f"New message: {event.message.content}")

40

elif isinstance(event, events.MessageUpdate):

41

print(f"Message edited: {event.after.content}")

42

```

43

44

### Class-Based Listeners

45

46

```python

47

from interactions import Extension, listen

48

49

class EventExtension(Extension):

50

@listen()

51

async def on_ready(self, event: events.Ready):

52

"""Extension-based event listener"""

53

print(f"Bot ready! Logged in as {self.bot.user}")

54

55

@listen(events.MemberAdd)

56

async def on_member_join(self, event: events.MemberAdd):

57

"""Welcome new members"""

58

member = event.member

59

channel = member.guild.system_channel

60

if channel:

61

await channel.send(f"Welcome {member.mention} to {member.guild.name}!")

62

```

63

64

## Discord Gateway Events

65

66

### Connection Events

67

68

```python

69

@listen(events.Ready)

70

async def on_ready(event: events.Ready):

71

"""Bot is ready and connected"""

72

user = event.user

73

guilds = len(event.guilds)

74

print(f"Ready! Logged in as {user} in {guilds} guilds")

75

76

@listen(events.Connect)

77

async def on_connect(event: events.Connect):

78

"""Bot connected to gateway"""

79

print("Connected to Discord gateway")

80

81

@listen(events.Disconnect)

82

async def on_disconnect(event: events.Disconnect):

83

"""Bot disconnected from gateway"""

84

print("Disconnected from Discord gateway")

85

86

@listen(events.Resume)

87

async def on_resume(event: events.Resume):

88

"""Gateway connection resumed"""

89

print("Gateway connection resumed")

90

```

91

92

### Guild Events

93

94

```python

95

@listen(events.GuildJoin)

96

async def on_guild_join(event: events.GuildJoin):

97

"""Bot joins a new guild"""

98

guild = event.guild

99

print(f"Joined guild: {guild.name} with {guild.member_count} members")

100

101

@listen(events.GuildLeft)

102

async def on_guild_leave(event: events.GuildLeft):

103

"""Bot leaves/gets kicked from guild"""

104

guild = event.guild

105

print(f"Left guild: {guild.name}")

106

107

@listen(events.GuildUpdate)

108

async def on_guild_update(event: events.GuildUpdate):

109

"""Guild settings updated"""

110

before = event.before

111

after = event.after

112

print(f"Guild {after.name} was updated")

113

114

@listen(events.GuildAvailable)

115

async def on_guild_available(event: events.GuildAvailable):

116

"""Guild becomes available after outage"""

117

guild = event.guild

118

print(f"Guild {guild.name} is now available")

119

120

@listen(events.GuildUnavailable)

121

async def on_guild_unavailable(event: events.GuildUnavailable):

122

"""Guild becomes unavailable due to outage"""

123

guild = event.guild

124

print(f"Guild {guild.name} is now unavailable")

125

```

126

127

### Member Events

128

129

```python

130

@listen(events.MemberAdd)

131

async def on_member_join(event: events.MemberAdd):

132

"""New member joins guild"""

133

member = event.member

134

guild = member.guild

135

136

# Send welcome message

137

if guild.system_channel:

138

embed = Embed(

139

title="Welcome!",

140

description=f"Welcome {member.mention} to {guild.name}!",

141

color=0x00ff00

142

)

143

await guild.system_channel.send(embed=embed)

144

145

@listen(events.MemberRemove)

146

async def on_member_leave(event: events.MemberRemove):

147

"""Member leaves guild"""

148

member = event.member

149

print(f"{member} left {member.guild.name}")

150

151

@listen(events.MemberUpdate)

152

async def on_member_update(event: events.MemberUpdate):

153

"""Member profile updated (roles, nick, etc.)"""

154

before = event.before

155

after = event.after

156

157

# Check if roles changed

158

if before.roles != after.roles:

159

added_roles = set(after.roles) - set(before.roles)

160

removed_roles = set(before.roles) - set(after.roles)

161

162

for role in added_roles:

163

print(f"{after} gained role: {role.name}")

164

for role in removed_roles:

165

print(f"{after} lost role: {role.name}")

166

```

167

168

### Message Events

169

170

```python

171

@listen(events.MessageCreate)

172

async def on_message(event: events.MessageCreate):

173

"""New message sent"""

174

message = event.message

175

176

# Ignore bot messages

177

if message.author.bot:

178

return

179

180

# Auto-react to messages with "python"

181

if "python" in message.content.lower():

182

await message.add_reaction("🐍")

183

184

@listen(events.MessageUpdate)

185

async def on_message_edit(event: events.MessageUpdate):

186

"""Message was edited"""

187

before = event.before

188

after = event.after

189

190

if before and after and before.content != after.content:

191

print(f"Message edited in #{after.channel.name}")

192

print(f"Before: {before.content}")

193

print(f"After: {after.content}")

194

195

@listen(events.MessageDelete)

196

async def on_message_delete(event: events.MessageDelete):

197

"""Message was deleted"""

198

message = event.message

199

print(f"Message deleted in #{message.channel.name}: {message.content}")

200

201

@listen(events.MessageDeleteBulk)

202

async def on_bulk_delete(event: events.MessageDeleteBulk):

203

"""Multiple messages deleted"""

204

messages = event.messages

205

channel = messages[0].channel if messages else None

206

print(f"Bulk deleted {len(messages)} messages in #{channel.name}")

207

```

208

209

### Reaction Events

210

211

```python

212

@listen(events.MessageReactionAdd)

213

async def on_reaction_add(event: events.MessageReactionAdd):

214

"""User adds reaction to message"""

215

reaction = event.reaction

216

user = event.user

217

message = event.message

218

219

# Role reaction system example

220

if str(reaction.emoji) == "πŸ‘" and not user.bot:

221

role = message.guild.get_role(THUMBS_UP_ROLE_ID)

222

if role:

223

await user.add_role(role)

224

225

@listen(events.MessageReactionRemove)

226

async def on_reaction_remove(event: events.MessageReactionRemove):

227

"""User removes reaction from message"""

228

reaction = event.reaction

229

user = event.user

230

231

if str(reaction.emoji) == "πŸ‘" and not user.bot:

232

role = event.message.guild.get_role(THUMBS_UP_ROLE_ID)

233

if role:

234

await user.remove_role(role)

235

236

@listen(events.MessageReactionRemoveAll)

237

async def on_reactions_clear(event: events.MessageReactionRemoveAll):

238

"""All reactions removed from message"""

239

message = event.message

240

print(f"All reactions cleared from message in #{message.channel.name}")

241

```

242

243

### Channel Events

244

245

```python

246

@listen(events.ChannelCreate)

247

async def on_channel_create(event: events.ChannelCreate):

248

"""New channel created"""

249

channel = event.channel

250

print(f"New channel created: #{channel.name}")

251

252

@listen(events.ChannelUpdate)

253

async def on_channel_update(event: events.ChannelUpdate):

254

"""Channel settings updated"""

255

before = event.before

256

after = event.after

257

print(f"Channel #{after.name} was updated")

258

259

@listen(events.ChannelDelete)

260

async def on_channel_delete(event: events.ChannelDelete):

261

"""Channel deleted"""

262

channel = event.channel

263

print(f"Channel deleted: #{channel.name}")

264

265

@listen(events.ChannelPinsUpdate)

266

async def on_pins_update(event: events.ChannelPinsUpdate):

267

"""Channel pins updated"""

268

channel = event.channel

269

print(f"Pins updated in #{channel.name}")

270

```

271

272

### Thread Events

273

274

```python

275

@listen(events.ThreadCreate)

276

async def on_thread_create(event: events.ThreadCreate):

277

"""New thread created"""

278

thread = event.thread

279

print(f"Thread created: {thread.name}")

280

281

@listen(events.ThreadUpdate)

282

async def on_thread_update(event: events.ThreadUpdate):

283

"""Thread updated"""

284

before = event.before

285

after = event.after

286

print(f"Thread updated: {after.name}")

287

288

@listen(events.ThreadDelete)

289

async def on_thread_delete(event: events.ThreadDelete):

290

"""Thread deleted"""

291

thread = event.thread

292

print(f"Thread deleted: {thread.name}")

293

294

@listen(events.ThreadMemberUpdate)

295

async def on_thread_member_update(event: events.ThreadMemberUpdate):

296

"""User's thread membership updated"""

297

member = event.member

298

thread = event.thread

299

print(f"{member.user} updated in thread {thread.name}")

300

```

301

302

### Voice Events

303

304

```python

305

@listen(events.VoiceStateUpdate)

306

async def on_voice_state_update(event: events.VoiceStateUpdate):

307

"""User's voice state changed"""

308

before = event.before

309

after = event.after

310

member = after.member if after else before.member

311

312

# User joined voice channel

313

if not before.channel and after.channel:

314

print(f"{member} joined voice channel: {after.channel.name}")

315

316

# User left voice channel

317

elif before.channel and not after.channel:

318

print(f"{member} left voice channel: {before.channel.name}")

319

320

# User moved between channels

321

elif before.channel != after.channel:

322

print(f"{member} moved from {before.channel.name} to {after.channel.name}")

323

324

# Convenience voice events

325

@listen(events.VoiceUserJoin)

326

async def on_voice_join(event: events.VoiceUserJoin):

327

"""User joins voice channel (convenience event)"""

328

member = event.member

329

channel = event.channel

330

print(f"{member} joined {channel.name}")

331

332

@listen(events.VoiceUserLeave)

333

async def on_voice_leave(event: events.VoiceUserLeave):

334

"""User leaves voice channel (convenience event)"""

335

member = event.member

336

channel = event.channel

337

print(f"{member} left {channel.name}")

338

339

@listen(events.VoiceUserMove)

340

async def on_voice_move(event: events.VoiceUserMove):

341

"""User moves between voice channels"""

342

member = event.member

343

before_channel = event.before_channel

344

after_channel = event.after_channel

345

print(f"{member} moved from {before_channel.name} to {after_channel.name}")

346

```

347

348

### Role Events

349

350

```python

351

@listen(events.RoleCreate)

352

async def on_role_create(event: events.RoleCreate):

353

"""New role created"""

354

role = event.role

355

guild = event.guild

356

print(f"Role created in {guild.name}: {role.name}")

357

358

@listen(events.RoleUpdate)

359

async def on_role_update(event: events.RoleUpdate):

360

"""Role updated"""

361

before = event.before

362

after = event.after

363

print(f"Role updated: {after.name}")

364

365

@listen(events.RoleDelete)

366

async def on_role_delete(event: events.RoleDelete):

367

"""Role deleted"""

368

role = event.role

369

guild = event.guild

370

print(f"Role deleted from {guild.name}: {role.name}")

371

```

372

373

### Ban Events

374

375

```python

376

@listen(events.BanCreate)

377

async def on_member_ban(event: events.BanCreate):

378

"""Member banned from guild"""

379

ban = event.ban

380

user = ban.user

381

guild = event.guild

382

reason = ban.reason or "No reason provided"

383

print(f"{user} was banned from {guild.name}: {reason}")

384

385

@listen(events.BanRemove)

386

async def on_member_unban(event: events.BanRemove):

387

"""Member unbanned from guild"""

388

user = event.user

389

guild = event.guild

390

print(f"{user} was unbanned from {guild.name}")

391

```

392

393

### Interaction Events

394

395

```python

396

@listen(events.InteractionCreate)

397

async def on_interaction(event: events.InteractionCreate):

398

"""Any interaction received"""

399

interaction = event.interaction

400

print(f"Interaction received: {interaction.type}")

401

```

402

403

## Internal Framework Events

404

405

### Bot Lifecycle Events

406

407

```python

408

@listen(events.Startup)

409

async def on_startup(event: events.Startup):

410

"""Bot starting up"""

411

print("Bot is starting up...")

412

413

@listen(events.Login)

414

async def on_login(event: events.Login):

415

"""Bot logged in"""

416

print("Bot has logged in to Discord")

417

418

@listen(events.Ready)

419

async def on_ready(event: events.Ready):

420

"""Bot is ready to receive events"""

421

print(f"Bot is ready! Logged in as {event.user}")

422

423

@listen(events.WebsocketReady)

424

async def on_websocket_ready(event: events.WebsocketReady):

425

"""WebSocket connection established"""

426

print("WebSocket connection ready")

427

```

428

429

### Command Events

430

431

```python

432

@listen(events.CommandCompletion)

433

async def on_command_complete(event: events.CommandCompletion):

434

"""Command completed successfully"""

435

ctx = event.ctx

436

command = event.command

437

print(f"Command {command.name} completed by {ctx.author}")

438

439

@listen(events.CommandError)

440

async def on_command_error(event: events.CommandError):

441

"""Command encountered an error"""

442

ctx = event.ctx

443

error = event.error

444

command = event.command

445

446

print(f"Error in command {command.name}: {error}")

447

448

# Send error message to user

449

await ctx.send(f"An error occurred: {str(error)}", ephemeral=True)

450

```

451

452

### Component Events

453

454

```python

455

@listen(events.Component)

456

async def on_component_interaction(event: events.Component):

457

"""Generic component interaction"""

458

ctx = event.ctx

459

print(f"Component interaction: {ctx.custom_id}")

460

461

@listen(events.ComponentCompletion)

462

async def on_component_complete(event: events.ComponentCompletion):

463

"""Component interaction completed"""

464

ctx = event.ctx

465

print(f"Component {ctx.custom_id} completed")

466

467

@listen(events.ComponentError)

468

async def on_component_error(event: events.ComponentError):

469

"""Component interaction error"""

470

ctx = event.ctx

471

error = event.error

472

print(f"Component error in {ctx.custom_id}: {error}")

473

474

@listen(events.ButtonPressed)

475

async def on_button_press(event: events.ButtonPressed):

476

"""Button was pressed (convenience event)"""

477

ctx = event.ctx

478

print(f"Button pressed: {ctx.custom_id}")

479

480

@listen(events.Select)

481

async def on_select_menu(event: events.Select):

482

"""Select menu used (convenience event)"""

483

ctx = event.ctx

484

values = ctx.values

485

print(f"Select menu {ctx.custom_id} used with values: {values}")

486

```

487

488

### Modal Events

489

490

```python

491

@listen(events.ModalCompletion)

492

async def on_modal_complete(event: events.ModalCompletion):

493

"""Modal submitted successfully"""

494

ctx = event.ctx

495

print(f"Modal {ctx.custom_id} submitted")

496

497

@listen(events.ModalError)

498

async def on_modal_error(event: events.ModalError):

499

"""Modal submission error"""

500

ctx = event.ctx

501

error = event.error

502

print(f"Modal error in {ctx.custom_id}: {error}")

503

```

504

505

### Extension Events

506

507

```python

508

@listen(events.ExtensionLoad)

509

async def on_extension_load(event: events.ExtensionLoad):

510

"""Extension loaded"""

511

extension = event.extension

512

print(f"Extension loaded: {extension.name}")

513

514

@listen(events.ExtensionUnload)

515

async def on_extension_unload(event: events.ExtensionUnload):

516

"""Extension unloaded"""

517

extension = event.extension

518

print(f"Extension unloaded: {extension.name}")

519

```

520

521

### Error Events

522

523

```python

524

@listen(events.Error)

525

async def on_general_error(event: events.Error):

526

"""General error occurred"""

527

error = event.error

528

print(f"General error: {error}")

529

530

@listen(events.AutocompleteError)

531

async def on_autocomplete_error(event: events.AutocompleteError):

532

"""Autocomplete error"""

533

ctx = event.ctx

534

error = event.error

535

print(f"Autocomplete error: {error}")

536

```

537

538

## Event Base Classes

539

540

### BaseEvent

541

542

```python

543

class BaseEvent:

544

"""Base class for all events"""

545

bot: Client

546

547

class RawGatewayEvent(BaseEvent):

548

"""Raw gateway event data"""

549

data: dict

550

sequence: int

551

event_name: str

552

553

class GuildEvent(BaseEvent):

554

"""Base for guild-related events"""

555

guild: Guild

556

```

557

558

## Advanced Event Features

559

560

### Event Filtering

561

562

```python

563

@listen(events.MessageCreate)

564

async def on_message_in_channel(event: events.MessageCreate):

565

"""Only process messages in specific channel"""

566

message = event.message

567

568

# Filter by channel

569

if message.channel.id != SPECIFIC_CHANNEL_ID:

570

return

571

572

# Process message

573

await process_message(message)

574

575

@listen(events.MemberAdd)

576

async def on_member_join_specific_guild(event: events.MemberAdd):

577

"""Only process joins in specific guild"""

578

member = event.member

579

580

if member.guild.id != SPECIFIC_GUILD_ID:

581

return

582

583

await welcome_member(member)

584

```

585

586

### Conditional Event Handling

587

588

```python

589

@listen(events.MessageCreate)

590

async def on_message_with_conditions(event: events.MessageCreate):

591

"""Message event with multiple conditions"""

592

message = event.message

593

594

# Skip bot messages

595

if message.author.bot:

596

return

597

598

# Only process messages with attachments

599

if not message.attachments:

600

return

601

602

# Only process in guild channels

603

if not message.guild:

604

return

605

606

# Process the message

607

await handle_attachment_message(message)

608

```

609

610

### Event Data Access

611

612

```python

613

@listen(events.MessageUpdate)

614

async def on_message_edit_detailed(event: events.MessageUpdate):

615

"""Access detailed message edit data"""

616

before = event.before # Message before edit (may be None if not cached)

617

after = event.after # Message after edit

618

619

if before and after:

620

# Compare content changes

621

if before.content != after.content:

622

print(f"Content changed from: {before.content}")

623

print(f"Content changed to: {after.content}")

624

625

# Check embed changes

626

if before.embeds != after.embeds:

627

print("Embeds were modified")

628

```

629

630

## Event Listener Patterns

631

632

### Class Method Listeners

633

634

```python

635

class MyBot(Client):

636

def __init__(self):

637

super().__init__(token="TOKEN")

638

639

@listen()

640

async def on_ready(self, event: events.Ready):

641

"""Method-based event listener"""

642

print(f"{self.user} is ready!")

643

644

@listen(events.MessageCreate)

645

async def handle_messages(self, event: events.MessageCreate):

646

"""Handle messages in class context"""

647

message = event.message

648

if message.content.startswith(f"<@{self.user.id}>"):

649

await message.reply("You mentioned me!")

650

```

651

652

### Decorator Stacking

653

654

```python

655

@listen(events.GuildJoin)

656

@listen(events.GuildAvailable)

657

async def on_guild_accessible(event):

658

"""Listen to multiple related events"""

659

guild = event.guild

660

print(f"Guild accessible: {guild.name}")

661

```