Whenever something happens in Discord, it sends an event to your client. This can for example be: someone sends, updates, or deletes a message, your bot joins a new guild, or someone creates a new channel.

There are two main ways to listen to these events. The first is through DiscordClient#onEventSideEffects and friends. We’ll use DiscordClient#onEventSideEffectsIgnore here, and go over the other forms in the next section.

client.onEventSideEffectsIgnore {
  case msg: APIMessage.MessageCreate => println(msg.message.content)

There is nothing that decides where you have to start listening to an event. You can do it anywhere, even inside another listener.

The return type of this method call is EventRegistration[Mat], but most of often just EventRegistration[NotUsed]. This value lets you know when an event listener stops, and a way to stop it.

The second way to listen for events is using an EventsController. If you’ve ever used controllers and actions in the Play framework, then the base idea is the same. To start you pick an event listener builder that best fits your need. Some examples are Event, TextChannelEvent and GuildUserEvent. Depending on which event you chose, it might contain some extra information surrounding the event. You then call to with the event type you are listening to. From there you call one of the methods on it that bests suits you need, like withSideEffects, withRequest, async, and so on.

class MyListeners(requests: Requests) extends EventsController(requests) {
  val onCreate = TextChannelEvent.on[APIMessage.MessageCreate].withSideEffects { m =>

These listeners also need to be registered. That can be done using DiscordClient#registerListener.

val myListeners = new MyListeners(client.requests)

Here is a small example that illustrates the fact that you can define and use your listeners anywhere. There is nothing special about them.

val MessageEvent: EventListenerBuilder[TextChannelEventListenerMessage, APIMessage.MessageCreate] =

val createListeners: EventListener[APIMessage.MessageCreate, NotUsed] =
  MessageEvent.withSideEffects { m =>
    val startMessage = m.event.message

    if (startMessage.content.startsWith("start listen ")) {
      val inChannel  =
      val identifier = startMessage.content.replaceFirst("start listen ", "")

      val listener = client.registerListener(MessageEvent.withSideEffects { m =>
        if ( == inChannel) {
          println(s"$identifier: ${m.event.message.content}")

      //We need lazy and an explicit type here to make Scala happy
      lazy val stopper: EventRegistration[NotUsed] =
        client.registerListener(MessageEvent.withSideEffects { m =>
          if ( == inChannel && m.event.message.content == "stop listen " + identifier) {

      //Initialize stopper

Note that there is no defined order for which event handler will receive an event first. If you register an event handler inside another event handler, it might or might not receive the event that caused its registration.