Discord bot message variables

Variables let a Better Tickets message change depending on who it's about. Type {{author.username}} in a ticket welcome message and each member sees their own name. This page covers the template syntax (output tags, if conditions and the random tag) and lists every variable available in ticket, application and leveling messages.

A welcome message field in the Better Tickets dashboard using {{author.username}} variables
A welcome message field using variables, on the dashboard

Output tags: {{ }}

Wrap a variable name in double braces to insert its value.

{{author.username}} opened this ticket.

Renders as alex opened this ticket. if author.username is alex. Nest with dots ({{author.username}}, {{server.name}}), spacing inside braces doesn't matter. An unknown variable renders as empty, not an error.

{{now}} is always available and holds the current time as a Unix timestamp. Use it inside a Discord timestamp tag, such as Opened <t:{{now}}:R>, to show a time in each reader's own time zone. The Discord timestamp generator explains every timestamp format.

Conditional tags: {% if %}

text
{% if fruit %}You picked {{fruit}}.{% else %}No fruit picked yet.{% endif %}

A condition is either:

  • Truthy: {% if fruit %}, true if set at all.
  • Equality: {% if fruit == "apple" %} or !=. Quotes optional for single words, required if the value has spaces. The right side can be another dotted variable too, e.g. {% if author.userId == server.ownerId %}.

Chain more branches with {% elsif %}:

text
{% if status == "accepted" %}Accepted{% elsif status == "denied" %}Denied{% else %}Pending{% endif %}

Both % symbols matter, {% if claimer} (missing one) is left as broken literal text.

A broken {% if %} (missing {% endif %} or an unparseable condition) makes everything from that point to the end of the message render as raw text. Everything before it still works.

The random tag: {{random: ...}}

Picks one option at random each render, comma-separated:

text
{{random: A staff member will be with you shortly., Please wait for a staff member., Hello\, we'll be right with you.}}

This is what the default welcome message uses. Escape a literal comma with \,.


Common variables

Available in both ticket and application messages, only author's meaning changes.

nownumber
Current time as a Unix timestamp, everywhere.
author.userIdstring
The ticket's author or the applicant.
author.usernamestring
Their Discord username.
author.globalNamestring
Their display name.
author.createdAtnumber
Account creation time, Unix timestamp.
author.joinedAtnumber
When they joined this server. Only set where live member data is available, check with {% if author.joinedAt %} first.
reasonstring
The current action's reason, if any: a close, accept or deny reason.
levelnumber
author's current level, available even if Leveling is off.
totalXpnumber
author's lifetime total XP.
currentXpnumber
XP earned within the current level.
requiredXpnumber
XP needed for the next level.
server.idstring
The server's Discord ID.
server.namestring
The server's name.
server.ownerIdstring
The server owner's Discord user ID.
server.memberCountnumber
The server's member count.

Where you can use variables

Tickets

Every ticket message field gets the common variables plus ticketId (the category's identifier). What else each one adds:

FieldAlso gets
Channel name template (Premium)Everything below; this field gets every ticket variable
Welcome message / Footer textauthor.joinedAt, reason, level variables, claimer.*
Claimed / Unclaimed messageclaimer.*, user.*, ticketNumber, guildTicketNumber
Escalated messageclaimer.*, user.*, fromCategory, toCategory, ticketNumber, guildTicketNumber
Member added / removed messageclaimer.*, user.*, target.*, ticketNumber, guildTicketNumber
Close message (kept open)claimer.*, user.*, reason, ticketNumber, guildTicketNumber
claimer.userIdstring
Claimer's Discord user ID. Only set once claimed, check with {% if claimer %}.
claimer.usernamestring
Claimer's username. Only set once claimed.
claimer.globalNamestring
Claimer's display name. Only set once claimed.
user.userIdstring
Whoever performed the action: claimed, unclaimed, escalated, added/removed a member, or closed a kept-open ticket.
user.usernamestring
Their username.
user.globalNamestring
Their display name.
target.userIdstring
The member added to or removed from the ticket.
target.usernamestring
Their username.
target.globalNamestring
Their display name.
ticketNumbernumber
This category's own ticket counter.
guildTicketNumbernumber
The server-wide ticket counter, across every category.
fromCategorystring
Escalated message only, the category the ticket moved out of.
toCategorystring
Escalated message only, the category it moved into.

Default channel name, used unless you set a template with Premium:

text
{% if claimer %}✅{{author.username}}-{{claimer.username}}{% else %}{{ticketId}}-{{author.username}}{% endif %}

Default footer:

text
{% if claimer %}Opened by {{claimer.username}} for {{author.username}}.{% else %}Opened by {{author.username}}.{% endif %}

Applications

Every application field gets the common variables, except Title/Description which only gets server (there's no applicant yet). What each field adds:

FieldAlso gets
Submission message (Premium)reviewer.*, decision, decidedAt, qa, applicationNumber, guildApplicationNumber
Accepted / Denied DMreviewer.*, reason, level variables, applicationNumber, guildApplicationNumber
Reapply cooldown messagereadyAt
Application timeout DMapplicationName, applicationNumber, guildApplicationNumber
Review thread nameapplicationNumber, guildApplicationNumber
reviewer.userIdstring
The staff member who accepted or denied the application.
reviewer.usernamestring
Reviewer's username.
reviewer.globalNamestring
Reviewer's display name.
qastring
The formatted Q&A list. Submission message only, once per message.
decisionstring
"Accepted" or "Denied", once decided.
decidedAtstring
When the application was decided.
applicationNumbernumber
This category's own application counter.
guildApplicationNumbernumber
The server-wide application counter, across every category.
readyAtstring
Reapply message only, when the cooldown ends.
applicationNamestring
Timeout DM only, the category name.

Default submission message:

text
**New application**
Author: <@{{author.userId}}>.
Username: {{author.username}}.
Nickname: {{author.globalName}}
{{qa}}

A decided-by footer is added automatically and can't be edited.

Leveling

Message template (Announcements tab). Common variables plus {{level}}.

Default: 🎉 {{author.username}} just reached level **{{level}}**!

Roleplay

Message template and Footer text (Premium). Does not use common variables, server isn't available and author/target only expose id/username.

author.idstring
Whoever ran the command.
author.usernamestring
Their username.
target.idstring
Set only if a target was given, check with {% if target.id %}.
target.usernamestring
Same optionality as target.id.
verbstring
Full verb phrase, e.g. is hugging you.
gerundstring
-ing form for solo, no-target use, e.g. hugging.
paststring
Past-tense phrase, e.g. have hugged.
isBackboolean
true for a reciprocation via the back button.
mutualCountnumber
Times this pair has done the action together. 0 if not tracked.
receivedCountnumber
Times target has had this done to them by anyone. 0 if not tracked.
givenCountnumber
Times author has performed this action on anyone.
rp.animeNamestring
Source anime, when known. Check with {% if rp.animeName %}.
rp.artistNamestring
Artist credit, when available.
rp.artistHrefstring
Link to the artist, when available.
rp.sourceUrlstring
Link to the image's source, when available.
rp.urlstring
Direct URL of the fetched image.
rp.widthnumber
Image width in pixels.
rp.heightnumber
Image height in pixels.

Default message (handles with/without target in one template):

text
{% if target.id %}<@{{target.id}}>! {{author.username}} {{verb}}{% if isBack %} back{% endif %}.
 
{% if mutualCount %}-# {{author.username}} and {{target.username}} {{past}} {{mutualCount}} time(s).{% elsif receivedCount %}-# {{target.username}} {{past}} {{receivedCount}} time(s).{% endif %}{% else %}{{author.username}} is {{gerund}}.{% endif %}

Default footer: {% if rp.animeName %}-# Anime name: {{rp.animeName}}.{% endif %}

Per-command reference, what {{verb}}/{{gerund}}/{{past}} resolve to ({{past}} only shows on actions that track a count):

Command{{verb}}{{gerund}}{{past}}
/hugis hugging youhugginghave hugged
/kissis kissing youkissinghave kissed
/patis patting youpattinghas been patted
/cuddleis cuddling youcuddlinghave cuddled
/slapis slapping youslappinghas been slapped
/pokeis poking youpokinghas been poked
/tickleis tickling youticklinghas been tickled
/biteis biting youbitinghas been bitten
/kickis kicking youkickinghas been kicked
/punchis punching youpunchinghas been punched
/feedis feeding youfeedinghas been fed
/waveis waving at youwaving athas been waved at
/peckis pecking youpeckinghave pecked
/carryis carrying youcarryinghas been carried
/bonkis bonking youbonkinghas been bonked
/handholdis holding hands with youholding hands withhave held hands
/highfiveis high-fiving youhigh-fivinghas been high-fived
/shakeis shaking youshakinghas been shaken
/handshakeis shaking hands with youshaking hands withhave shaken hands
/nomis nomming on younomming onhas been nommed on
/blowkissis blowing a kiss to youblowing a kiss tohas been blew a kiss to
/yeetis yeeting youyeetinghas been yeeted
/shootis shooting youshootinghas been shot
/lickis licking youlickinghas been licked
/cryis crying with youcryinghas cried
/laughis laughing with youlaughinghas laughed
/angryis angry at youangryhas been angry
/blehis sticking their tongue out at youbeing blehhas been bleh
/blushis blushing at youblushinghas blushed
/boredis bored around youboredhas been bored
/clapis clapping for youclappinghas clapped
/confusedis confused about youconfusedhas been confused
/danceis dancing with youdancinghas danced
/facepalmis facepalming at youfacepalminghas facepalmed
/happyis happy around youhappyhas been happy
/lurkis lurking near youlurkinghas lurked
/nodis nodding at younoddinghas nodded
/nopenopes at younoping outhas noped out
/nyanyas at youbeing nyahas been nya
/poutis pouting at youpoutinghas pouted
/shockedis shocked by youshockedhas been shocked
/shrugis shrugging at youshrugginghas shrugged
/sipis sipping tea at yousipping teahas sipped tea
/sleepis sleeping near yousleepinghas slept
/smileis smiling at yousmilinghas smiled
/smugis smug around yousmughas been smug
/spinis spinning with youspinninghas spun
/tableflipis flipping a table for youflipping a tablehas flipped a table
/teeheeis giggling at yougigglinghas giggled
/thinkis thinking about youthinkinghas thought
/thumbsupis giving you a thumbs upgiving a thumbs uphas given a thumbs up
/wagis wagging their tail at youwagging their tailhas wagged their tail
/winkis winking at youwinkinghas winked
/yawnis yawning near youyawninghas yawned
/runis running with yourunning awayhas run
/saluteis saluting yousalutinghas saluted
/stareis staring at youstaringhas stared
/bakais calling you bakacalling bakahas been called baka