Discord Events and Operations: Reactions, Presence, and Config

Covers Discord operational surfaces: reaction notifications, presence events, bot presence, gateway proxying, config writes, and PluralKit. Useful for operators configuring guild behavior and agent wakeups.

Read this when

  • Waking an agent on Discord reactions or presence changes
  • Setting bot presence, a gateway proxy, or PluralKit support

Discord operational surfaces: wakes from reactions and presence, bot presence, gateway proxying, config writes, and PluralKit.

Events and operations

Reaction notifications

Reaction notification mode, set per guild (guilds.<id>.reactionNotifications):

  • off
  • own (default)
  • all
  • allowlist (uses guilds.<id>.users)

Reaction events get converted into system events, which are then attached to the Discord session they route to.

Online presence events

To have a guild wake the routed agent when a human member goes from offline to online:

{
  channels: {
    discord: {
      intents: { presence: true },
      guilds: {
        "111111111111111111": {
          presenceEvents: {
            channelId: "222222222222222222",
            users: ["333333333333333333"], // optional; further narrow channel viewers
            reconnectSuppressSeconds: 300, // optional; new-session quiet window (0 disables)
            burstLimit: 8, // optional; max events per burst window
            burstWindowSeconds: 60, // optional; sliding burst-detection window
          },
        },
      },
    },
  },
}

presenceEvents needs an enabled heartbeat for the routed agent, plus the privileged Presence Intent enabled on the application's Bot page in the Discord Developer Portal. From every complete GUILD_CREATE snapshot, OpenClaw seeds the members currently online, routes offline-to-online transitions it observes, and also counts a later first online signal for a member it has not seen as newly available. That member may have come online or joined after the snapshot, so the event does not claim an exact prior status. Eligibility is limited to humans who can view channelId: channels and public threads need View Channel on the channel or its parent, and private threads also need membership or Manage Threads. users can narrow that audience further. Bots and unchanged online states are ignored, and an eight-hour per-user cooldown persists across Gateway restarts. When Discord starts a new Gateway session and sends READY, OpenClaw suppresses presence-derived events for reconnectSuppressSeconds (default 300, 0 disables) while guild presence state is rebuilt, so re-observed members cannot wake the agent one at a time. Successfully queued events are also rate-limited per guild to burstLimit events (default 8) per burstWindowSeconds sliding window (default 60), with each guild's suppression episode logged once. A resumed session does not count as a new session. For guilds above 75,000 members, Discord limits snapshots; in that case OpenClaw needs an explicit offline update before greeting. The system event carries immutable user, guild, and channel IDs and does not embed mutable display names. Whether and how to greet is the agent's decision.

Presence configuration

Presence updates take effect when you set a status or activity field, or when auto presence is enabled.

Status only:

{
  channels: {
    discord: {
      status: "idle",
    },
  },
}

Activity (custom status is the default activity type when activity is set):

{
  channels: {
    discord: {
      activity: "Focus time",
      activityType: 4,
    },
  },
}

Streaming:

{
  channels: {
    discord: {
      activity: "Live coding",
      activityType: 1,
      activityUrl: "https://twitch.tv/openclaw",
    },
  },
}

Activity type map:

  • 0: Playing

  • 1: Streaming (requires activityUrl; activityUrl in turn requires activityType: 1)

  • 2: Listening

  • 3: Watching

  • 4: Custom (uses the activity text as the status state; emoji is optional)

  • 5: Competing

    Auto presence (runtime health signal):

{
  channels: {
    discord: {
      autoPresence: {
        enabled: true,
        intervalMs: 30000,
        minUpdateIntervalMs: 15000,
      },
    },
  },
}

Auto presence maps runtime availability to Discord status: healthy => online, degraded or unknown => idle, exhausted or unavailable => dnd. Defaults: intervalMs 30000, minUpdateIntervalMs 15000 (must be less than or equal to intervalMs).

Config writes

Config writes started from channels are enabled by default. This affects /config set|unset flows (when command features are enabled).

Disable:

{
  channels: {
    discord: {
      configWrites: false,
    },
  },
}

Gateway proxy

Send Discord gateway WebSocket traffic and startup REST lookups (application ID + allowlist resolution) through an HTTP(S) proxy with channels.discord.proxy. Proxying of the Discord gateway WebSocket is explicit; WebSocket connections do not inherit ambient proxy environment variables from the Gateway process. Startup REST lookups use this proxy when channels.discord.proxy is configured.

{
  channels: {
    discord: {
      proxy: "http://proxy.example:8080",
    },
  },
}

Per-account override:

{
  channels: {
    discord: {
      accounts: {
        primary: {
          proxy: "http://proxy.example:8080",
        },
      },
    },
  },
}

PluralKit support

Enable PluralKit resolution to map proxied messages to system member identity:

{
  channels: {
    discord: {
      pluralkit: {
        enabled: true,
        token: "pk_live_...", // optional; needed for private systems
      },
    },
  },
}

Notes:

  • allowlists can use pk:<memberId>
  • member display names are matched by name/slug only when channels.discord.dangerouslyAllowNameMatching: true
  • lookups query the PluralKit API with the original message ID
  • if lookup fails, proxied messages are treated as bot messages and dropped unless allowBots lets them through
773 words · updated Oct 26, 2026