Skip to main content

Expressions

Kite supports performing calculations and transformations on data using expressions. Expressions are available in the Calculate Value block (which also supports multi-line input) and in every placeholder surrounded by {{ and }}.

Expression syntax​

Expressions are powered by the Expr language, you can learn more about the features and syntax here.

Available variables​

Kite provides the following variables in the expression environment:

user:
id: string
username: string
discriminator: string
display_name: string
avatar_url: string
banner_url: string
mention: string
is_bot: bool
created_at: int # When the account was created, as a Unix timestamp in seconds
role_ids?: []string
nick?: string
# Only filled inside a server
joined_at: int # When the user joined the server, as a Unix timestamp in seconds
top_role: # The highest role of the user, or @everyone without roles
id: string
name: string
mention: string
color: string # Like #5865f2, empty if the role has no color
hoist: bool # Whether the role is shown separately in the member list
mentionable: bool
role_mentions: string # Mentions of all roles of the user, highest first
role_names: string # Names of all roles of the user, highest first, separated by commas
role_count: int
color: string # Color of the highest role that has one, like #5865f2
is_booster: bool
boosting_since: int # Unix timestamp in seconds, 0 if the user isn't boosting
is_timed_out: bool
timeout_until: int # Unix timestamp in seconds, 0 if the user isn't timed out
is_owner: bool # Whether the user owns the server
is_admin: bool # Whether the user owns the server or has the Administrator permission
permissions: []string # Lowercased permission names, like ban_members or manage_messages

message?: # For message events
id: string
channel_id: string
content: string
author: # Same fields as user, empty for reactions and deleted messages
id: string
username: string
reactions: # Empty for message events, get the message with a block to count its reactions
- emoji:
id: string # Empty for a unicode emoji
name: string
count: int
mentions: # Users the message pings, with the same fields as user. Includes the author of the message it replies to if the reply pings them
- id: string
username: string

channel:
id: string
name: string
mention: string
type: string # text, voice, category, announcement, thread, stage, forum, media, dm, group_dm, or unknown for newer types
guild_id: string # The server the channel is in, empty for direct messages and if it isn't known
category_id: string # Empty outside of a category, for a thread the category of its channel
category_name: string

guild?: # For events and interactions inside a server, elsewhere guild is empty and so are its fields
id: string # The id of the server
name: string
icon_url: string # Empty if the server has no icon
member_count: int
boost_count: int
owner_id: string # The id of the user that owns the server
boost_level: int # 0 to 3
created_at: int # When the server was created, as a Unix timestamp in seconds
banner_url: string # Empty if the server has no banner
description: string
vanity_url: string # The custom invite link, empty if the server has none
role_count: int # Without @everyone
channel_count: int # Without categories and threads
emoji_count: int
rules_channel: # Empty if the server has no rules channel
id: string
name: string
mention: string
system_channel: # Where Discord posts join and boost messages, empty if turned off
id: string
name: string
mention: string

interaction?: # For commands and interactive components
id: string
value?: string # The value of the picked option in a select menu, or the ID of the picked user, role or channel
values?: []string # All picked values or IDs if the select menu allows picking more than one
components?: # For modal submissions, by input identifier
identifier:
value: string # What input('identifier') returns
values: []string # What inputs('identifier') returns

app:
user: # Access the underlying user of the app
id: string
mention: string
guild_count: int # The number of servers your app is in
member_count: int # The members of all those servers added up
latency: int # The number of milliseconds Discord took to answer your app's last heartbeat
user_install_count: int # Discord's approximate number of users that installed your app

There are also a few special variables for accessing dynamic variables:

arg('name') # Access value of a command argument
input('identifier') # Access value of a modal input, the first one if several options were picked
inputs('identifier') # Access all picked options of a modal input as a list
picked('identifier') # Access the member, role or channel picked in a modal select, or the uploaded file, the first one if there are several
pickedAll('identifier') # Access all members, roles or channels picked in a modal select, or all uploaded files, as a list
result('id') # Access the result of a previous block
calculate('5 + 5') # Calculate arithmetic written as text, like a message, nothing if it isn't only math
duration('1d 12h') # Read a length of time written as text, like a command argument, nothing if it isn't one

The ID of a block is shown in its settings. New blocks get a short ID that says what they are, like message_k3f for a Create Message block. Older blocks have IDs like owlspush, which keep working.

top_role, role_names, color, is_owner, is_admin and permissions need the roles of the server. They work for user, members from command arguments, and origin.user and previous.user in sub-flows. A member from result('id'), like the result of a Get Member block, or from a variable doesn't know its server, so using them there fails the flow instead of returning a wrong answer. They also fail in a server your app isn't in, where only user-installed commands run.

guild.member_count follows members joining and leaving while your app has a Member Join or Member Leave event listener. Without one, it's the count from when your app last connected to Discord.

app.member_count adds up the member count of each server like guild.member_count, so a user who is in several of your app's servers is counted once for each. app.user_install_count is updated about once a day, and is 0 until Discord first reports it after your app is created. app.latency is 0 while your app connects to Discord. Until Discord answers the first heartbeat after that, it's how long Discord took to accept the connection.

In sub-flows, origin and previous give access to the interaction or event from before the sub-flow, e.g. origin.user.id. Outside of sub-flows they are the current interaction or event, so origin.user.id is the same as user.id.

Examples​

When using the Calculate Value block, you must omit the {{ and }} from the expression.

Get a command argument​

This will return the value of the myarg argument passed to the command.

{{ arg('myarg') }}

Get a user's display name​

This will return the display name of the user who clicked the button or triggered the command or event.

{{ user.display_name }}

Get the message content​

This will return the content of the message that was sent.

{{ message.content }}

Check the reaction emoji​

In a Reaction Add or Reaction Remove event listener, this will return true if the reaction was a 👍. For a custom emoji, compare emoji.id instead.

{{ emoji.name == "👍" }}

Check if a user has a role​

This will return true if the user has the role with the ID 123.

{{ "123" in user.role_ids }}

Get the selected option​

This will return the value of the option that the user picked in a select menu.

{{ interaction.value }}

If the select menu allows picking more than one option, this will return true if the user picked the option with the value option-a.

{{ "option-a" in interaction.values }}

In a user, role, mentionable or channel select, the values are IDs. This mentions the channel that was picked:

<#{{ interaction.value }}>

Welcome a new member​

This will greet a member with the name of the server and their member number.

Welcome to {{ guild.name }}, {{ user.mention }}! You're member #{{ guild.member_count }}.

Check picked modal options​

If a modal input with the identifier colors allows picking more than one option, inputs('colors') returns all picked values as a list. This will return true if the user picked red.

{{ 'red' in inputs('colors') }}

This will return how many options were picked.

{{ len(inputs('colors')) }}

And this will list them separated by commas, e.g. red, blue.

{{ join(inputs('colors'), ', ') }}

Use picked members, roles, and channels​

For a user, role, mentionable or channel select in a modal, input(...) and inputs(...) return IDs. picked(...) returns the picked member, role or channel itself, with the same fields as user, a role or channel, and pickedAll(...) all of them as a list. On its own it shows as a mention. If a modal has a user select with the identifier reported, this will name the reported member.

{{ picked('reported').display_name }} was reported by {{ user.display_name }}.

This will list the names of all picked roles, separated by commas.

{{ join(map(pickedAll('roles'), #.name), ', ') }}

For a file upload in a modal, picked(...) returns the uploaded file, which shows as its URL. This will name the file uploaded with the identifier image and its size in bytes.

{{ picked('image').filename }} ({{ picked('image').size }} bytes)

Check when a user was created​

This will show when the user's account was created, as a Discord timestamp.

<t:{{ user.created_at }}:f>

This will return true if the account is less than 7 days old, which is useful for anti-raid checks. user.joined_at works the same way for how long someone has been in the server.

{{ user.created_at > now().Unix() - 7 * 86400 }}

Only run in a category​

This will return true if the command was used in a channel of the category named Tickets. Use channel.category_id instead to keep working when the category is renamed.

{{ channel.category_name == "Tickets" }}

This will return true inside a thread.

{{ channel.type == "thread" }}

Check if a user owns the server​

This will return true if the user is the owner of the server.

{{ user.is_owner }}

Check the permissions of a user​

This will return true if the user is allowed to ban members. The names are listed below.

{{ "ban_members" in user.permissions }}

user.permissions are the permissions the roles of the user give them in the server. Permissions a single channel grants or denies aren't included. Administrators and the owner of the server have every permission, and user.is_admin is true for them.

PermissionName in the server settings
create_instant_inviteCreate Invite
kick_membersKick, Approve, and Reject Members
ban_membersBan Members
administratorAdministrator
manage_channelsManage Channels
manage_guildManage Server
add_reactionsAdd Reactions
view_audit_logView Audit Log
priority_speakerPriority Speaker
streamVideo
view_channelView Channels
send_messagesSend Messages and Create Posts
send_tts_messagesSend Text-to-Speech Messages
manage_messagesManage Messages
embed_linksEmbed Links
attach_filesAttach Files
read_message_historyRead Message History
mention_everyoneMention @everyone, @here, and All Roles
use_external_emojisUse External Emoji
view_guild_insightsView Server Insights
connectConnect
speakSpeak
mute_membersMute Members
deafen_membersDeafen Members
move_membersMove Members
use_vadUse Voice Activity
change_nicknameChange Nickname
manage_nicknamesManage Nicknames
manage_rolesManage Roles
manage_webhooksManage Webhooks
manage_guild_expressionsManage Expressions
use_application_commandsUse Application Commands
request_to_speakRequest to Speak
manage_eventsManage Events
manage_threadsManage Threads and Posts
create_public_threadsCreate Public Threads
create_private_threadsCreate Private Threads
use_external_stickersUse External Stickers
send_messages_in_threadsSend Messages in Threads and Posts
use_embedded_activitiesUse Activities
moderate_membersTimeout Members
view_creator_monetization_analyticsView Server Subscription Insights
use_soundboardUse Soundboard
create_guild_expressionsCreate Expressions
create_eventsCreate Events
use_external_soundsUse External Sounds
send_voice_messagesSend Voice Messages
set_voice_channel_statusSet Voice Channel Status
send_pollsCreate Polls
use_external_appsUse External Apps
pin_messagesPin Messages
bypass_slowmodeBypass Slowmode

Point to the rules channel​

This will mention the rules channel the server has set in its settings, and is empty if it has none.

Please read {{ guild.rules_channel }} before posting.

Show the roles of a user​

This will mention the highest role of the user, and then all of their roles.

{{ user.top_role.mention }}
{{ user.role_mentions }}

Show bot stats​

This will show how many servers your app is in and its ping, for commands like /botinfo or /ping.

In {{ app.guild_count }} servers with {{ app.member_count }} members, ping {{ app.latency }}ms

Do some math​

This will return the result of the expression.

{{ 1 + 1 }}

To calculate math that members write, like (3 * 4) - 2 in a message, use calculate. It knows + - * / % ^, x and × for times, ÷, and parentheses, and returns nothing for text that isn't only math.

{{ calculate(message.content) }}

Decode a JSON response​

This will return the value of the somefield field in the JSON response of an HTTP request block with the id http_k3f.

{{ result('http_k3f').data().somefield }}

Timestamps​

Discord timestamps are shown in the local timezone of whoever reads the message. Wrap a Unix timestamp in <t:...:style> and pick one of the styles below.

In the message editor, the Time tab of the placeholder picker inserts these for you, for the time the message is sent, a specific date, or some time after it is sent.

<t:{{ now().Unix() }}:t> # Short time, like 5:36 PM
<t:{{ now().Unix() }}:T> # Long time, like 5:36:12 PM
<t:{{ now().Unix() }}:d> # Short date, like 01/02/2026
<t:{{ now().Unix() }}:D> # Long date, like January 2, 2026
<t:{{ now().Unix() }}:f> # Short date and time, like January 2, 2026 5:36 PM
<t:{{ now().Unix() }}:F> # Long date and time, like Friday, January 2, 2026 5:36 PM
<t:{{ now().Unix() }}:R> # Relative time, like 2 minutes ago

This will show a countdown that ends one hour from now.

<t:{{ now().Add(duration("1h")).Unix() }}:R>

duration reads lengths of time like 1h30m, 2h 30m, 1d 12h, 2 hours or 1 day and 30 minutes. The units are s, m, h, d and w, or written out like minutes, in any case, so M is minutes too. For text that isn't a length of time, like a typo in a command argument, it returns nothing, which you can check before using it.

{{ duration(arg('time')) == nil ? "Use a time like 30m or 2h" : "In " + string(duration(arg('time')).Seconds()) + " seconds" }}