The ctx object
Every script has a global ctx available with details about the event that
triggered it. Not every property is populated on every trigger; see
Triggers for exactly which. The dashboard's script
editor autocompletes only the properties valid for the script you're editing.
Top-level properties
27 properties on ctx itself.
The guild's Discord snowflake ID (as a string).
Available on: All triggersThe acting user's Discord snowflake ID (as a string).
Available on: Most triggers (see Triggers for exceptions)The acting user's own member data: username, display name, nickname, avatar URL, roles and join date, so you don't have to call getMember(ctx.actorId) yourself. On commands, buttons and modals it comes straight from Discord and is always current; on other events it is read from the member cache, so it is null for a user the bot hasn't cached (and its discriminator is empty, a field Discord has retired anyway). ctx.actor is always the person who acted, whereas on UserCommand ctx.member is the right-clicked target.
Available on: Most triggers (wherever ctx.actorId is set)The channel's Discord snowflake ID (as a string).
Available on: Most triggers (see Triggers for exceptions)The event type that triggered this script.
Available on: All triggersKey/value map of arguments passed to the script (e.g. slash-command options). Every value arrives as a string; see Commands & modals.
Available on: All triggersCustom environment variables set via the Database page: the single 'env' KV record holds a JSON object whose keys are exposed here (e.g. {"mod_log_channel_id":"123"} becomes ctx.env.mod_log_channel_id). Read-only during script execution.
Available on: All triggersAdmin-only secrets (API keys, etc.) from the Database page's 'secrets' record. Each key maps to an OPAQUE placeholder token "{{secret:NAME}}", never the real value, which is substituted server-side only inside fetch() (in the url, header values, and body). A key is present only when an admin has set a non-empty value, so `if (ctx.secret.MyKey)` safely tests whether it's configured. Because scripts only ever hold the placeholder, logging it, sending it in a message, or throwing it can never leak the real secret.
Available on: All triggersHow many fetch() calls remain in the guild's hourly budget when this execution starts. A fetch() beyond this throws, so size data-dependent loops against it.
Available on: All triggersHow many Discord actions (sends, bans, role changes, etc.) remain in the guild's hourly rate-limited action budget when this execution starts. An action beyond this throws, immediately ending the script: actions it already performed remain applied, and anything after the throw simply never runs.
Available on: All triggersMessage data. On MessageCommand(: Modal) it's the right-clicked target message. On MessageUpdate, content is the edited (new) version and previousContent is what it said before: null when that isn't known, since the pre-edit text comes from the 30-minute message cache, which a restart empties. On MessageDelete, content is the deleted text recovered from that same cache.
Available on: MessageCreate, MessageUpdate, MessageDelete, DirectMessageCreate, MessageCommand, MessageCommand: ModalMember data. On UserCommand(: Modal) it's the right-clicked target member (ctx.actorId is the invoker).
Available on: GuildMemberAdd, GuildMemberRemove, GuildMemberUpdate, UserCommand, UserCommand: ModalReaction data.
Available on: MessageReactionAdd, MessageReactionRemove, MessageReactionRemoveAll, MessageReactionRemoveEmojiBulk delete data.
Available on: MessageBulkDeleteVoice state data; channelId is empty when the user disconnected.
Available on: VoiceStateUpdateComponent interaction data. values holds the submitted form's text inputs keyed by input id, only non-empty on the ": Modal" triggers.
Available on: ButtonClick, ButtonClick: Modal, SlashCommand: Modal, MessageCommand: Modal, UserCommand: ModalRaw JSON payload of the event; no typed DTO, since the shape varies by action type.
Available on: GuildAuditLogEntryCreate, AutoModerationActionExecutionTwitch event data; messages is populated only for TwitchChatBatch (all chat from the last ~10 minutes, dispatched as one batch, never per message).
Available on: TwitchStreamOnline, TwitchStreamOffline, TwitchChannelUpdate, TwitchChatBatchThread / forum post data. isForumPost is true for forum/media posts; parentId is the channel it was created under, ctx.channelId is the thread itself, and tags holds the forum tags applied (resolved to names, empty for non-forum threads and on ThreadDelete).
Available on: ThreadCreate, ThreadUpdate, ThreadDeleteBan data. Who performed it is in the audit log, not here.
Available on: GuildBanAdd, GuildBanRemoveInvite data. InviteDelete only has code + channelId (Discord sends nothing else).
Available on: InviteCreate, InviteDeleteScheduled-event data. Create/Update/Delete carry the full event; UserAdd/UserRemove carry only id + userId (the (un)subscribing user).
Available on: GuildScheduledEventCreate/Update/Delete/UserAdd/UserRemovePoll-vote data; answerId identifies which poll answer was voted for or retracted.
Available on: MessagePollVoteAdd, MessagePollVoteRemoveStage-instance data; channelId is the stage voice channel.
Available on: StageInstanceCreate/Update/DeleteUpdated guild settings.
Available on: GuildUpdateEmoji/sticker set data; kind is "emojis" or "stickers", and count/names describe the set after the change.
Available on: GuildEmojisUpdate, GuildStickersUpdateBan appeal data. platform is "Discord" or "Twitch" depending on which identity the submitter proved; submitterId isn't a Discord snowflake for Twitch submitters, so it isn't also exposed as ctx.actorId.
Available on: AppealSubmittedNested types
The full field list for every object type referenced above.
AttachmentContext
An attachment on a message. Appears inside MessageContext.attachments and CachedMessage.attachments.
fileName(string)contentType(string)size(number)url(string)
MessageContext
Message data, present on message-related events (ctx.message).
id(string)content(string)authorId(string)authorUsername(string)authorDisplayName(string): Discord display name (global_name), falling back to username when unset.authorAvatarUrl(string)channelId(string)attachments(AttachmentContext[])referencedMessageId(string): ID of the message this one replies to (empty when not a reply).isForwarded(boolean): True when the message is a forward.previousContent(string | null): On MessageUpdate, the content before the edit: null when it isn't known (any other trigger, or a message not in the 30-minute cache).
MemberContext
Member data: ctx.member on member-related events, and ctx.actor anywhere there is a ctx.actorId.
userId(string)username(string)displayName(string): Nickname, else global display name, else username.discriminator(string): Legacy; Discord has retired discriminators. Empty on a cache-backed ctx.actor.nickname(string)avatarUrl(string): Server avatar, else global avatar, else Discord's default. Never empty.roleIds(string[])joinedAt(string): ISO 8601 join timestamp (empty when unknown).
VoiceStateContext
Voice state data, present on VoiceStateUpdate events (ctx.voiceState).
userId(string)channelId(string): Voice channel the user is now in; empty when they disconnected.
ForumTag
A forum tag: applied to a post (ctx.thread.tags) or defined on a forum (getForumTags()).
id(string)name(string)emojiName(string): Unicode emoji on the tag (empty when none or when the tag uses a custom emoji).emojiId(string): Custom emoji ID on the tag (empty when none or when the tag uses a unicode emoji).moderated(boolean): Whether only moderators can add/remove this tag.
ThreadContext
Thread / forum post data, present on ThreadCreate/Update/Delete events (ctx.thread).
id(string): ID of the thread / forum post (same as ctx.channelId).name(string): The thread / forum post title.ownerId(string): User who created it (same as ctx.actorId).parentId(string): Channel the thread was created under (the forum channel for a forum post).parentType(string): Parent channel kind: "Forum", "MediaForum", "Announcement", "Text", or "Unknown".isForumPost(boolean): True when the parent is a forum/media channel, i.e. this thread is a forum post.tags(ForumTag[]): Forum tags applied to this post, resolved to names (empty for non-forum threads).
BanContext
Ban data, present on GuildBanAdd / GuildBanRemove events (ctx.ban).
userId(string): The banned (GuildBanAdd) or unbanned (GuildBanRemove) user's ID.username(string)
AppealContext
Ban appeal data, present on AppealSubmitted events (ctx.appeal).
platform(string): Which identity the submitter proved: "Discord" or "Twitch".submitterId(string): The submitter's ID on that platform (not a Discord snowflake for Twitch submitters).submitterDisplayName(string)whyBanned(string)wasDeserved(string)whyUnban(string)
InviteContext
Invite data, present on InviteCreate / InviteDelete events (ctx.invite).
code(string): The invite code (the part after discord.gg/).channelId(string)inviterId(string): Inviter's user ID (empty on InviteDelete).maxUses(number): Max uses before expiry (0 = unlimited; 0 on InviteDelete).maxAge(number): Lifetime in seconds (0 = never; 0 on InviteDelete).temporary(boolean)expiresAt(string): ISO 8601 expiry time (empty when it never expires or on InviteDelete).
ScheduledEventContext
Scheduled-event data, present on the GuildScheduledEvent* triggers (ctx.scheduledEvent).
id(string)name(string)description(string)channelId(string): Voice/stage channel (empty for external-location events).location(string): Physical location for external events (empty otherwise).creatorId(string): Event creator's user ID (empty when unknown or on user add/remove).entityType(string): Entity kind: "StageInstance", "Voice", or "External".status(string): Lifecycle status: "Scheduled", "Active", "Completed", or "Canceled".startsAt(string): ISO 8601 scheduled start time.endsAt(string): ISO 8601 scheduled end time (empty when open-ended).userId(string): The (un)subscribing user (GuildScheduledEventUserAdd/Remove only; empty otherwise).
PollVoteContext
Poll-vote data, present on MessagePollVoteAdd / MessagePollVoteRemove events (ctx.pollVote).
userId(string)messageId(string)channelId(string)answerId(number): ID of the poll answer that was voted for / removed.
StageContext
Stage-instance data, present on StageInstanceCreate/Update/Delete events (ctx.stage).
id(string)channelId(string): The stage voice channel this instance is live in.topic(string)privacyLevel(string): Privacy level: "Public" or "GuildOnly".
GuildUpdateContext
Updated guild settings, present on GuildUpdate events (ctx.guildUpdate).
name(string)description(string)ownerId(string)
ExpressionSetContext
Emoji/sticker set data, present on GuildEmojisUpdate / GuildStickersUpdate events (ctx.expressions).
kind(string): Which set changed: "emojis" or "stickers".count(number): Number of items in the set after the change.names(string[]): Names of the items in the set after the change.
TwitchChatMessage
A single Twitch chat message inside a TwitchChatBatch (ctx.twitch.messages[n]).
chatterId(string)chatterLogin(string)chatterDisplayName(string)text(string)rewardId(string): Channel-points reward id when the message was a text-input redemption (empty otherwise).bits(number): Number of bits cheered with this message (0 otherwise).sentAt(string): ISO 8601 timestamp the message was received.
TwitchContext
Twitch event data, present on Twitch* triggers (ctx.twitch).
broadcasterId(string)broadcasterLogin(string)title(string): Stream/channel title (TwitchChannelUpdate only; empty otherwise).category(string): Game/category name (TwitchChannelUpdate only; empty otherwise).startedAt(string): ISO 8601 stream start time (TwitchStreamOnline only; empty otherwise).messages(TwitchChatMessage[]): Chat messages from the last ~10 minutes (TwitchChatBatch only; empty otherwise).messagesDropped(number): Messages dropped from this batch because the per-guild buffer overflowed.
InteractionContext
Component interaction data, present on ButtonClick and the ": Modal" triggers (ctx.interaction).
customId(string)payload(string): Free-form payload set on the button that triggered this.userId(string)messageId(string): Message the component was attached to (empty for form submissions).channelId(string)values(Record<string, string>): Modal text-input values keyed by input id (empty for button clicks).
ReactionContext
Reaction data, present on MessageReactionAdd/Remove events (ctx.reaction).
userId(string)messageId(string)channelId(string)emojiId(string)emojiName(string)
BulkDeleteContext
Bulk delete data, present on MessageBulkDelete events (ctx.bulkDelete).
messageIds(string[])count(number)channelId(string)