Rift Documentation

Welcome to Rift

Everything you need to get started, learn the interface, format messages, and connect your own apps using webhooks.

What is Rift?

Rift is a chat platform by ModemINC built for communities and teams. It has servers, channels, voice chat, direct messages, and a powerful message formatting system - all wrapped in a fast, clean interface.

Servers
Communities with channels, roles, and members. Create your own or join via invite link.
Channels
Text, voice, forum, announcement, rules, and log channels - each with a purpose.
Direct Messages
Private conversations with any Rift user. Full formatting support.
Webhooks
Post automated messages from any app or script without a Rift account.
Bots
Full bot accounts with a real-time WebSocket gateway and REST API. React to messages, send replies, and more.

Creating an Account

Go to modeminc.com/rift/signup and enter a username, email, and password.

Once signed in, you'll land in the main app. You can join a server right away using an invite link, or create your own.

Set up your profile in Settings - Profiles: choose a display name, upload an avatar, and write a bio.

Your username is your permanent handle. Your display name is what others see in chat and can be changed at any time.

The Desktop App

Rift has a native Windows desktop app that runs in the system tray and supports voice, screen share, and OS notifications.

Download

Download and run ModemInstaller from cdn.modeminc.com/ModemInstaller.exe. It installs the Rift launcher (RiftDownloader.exe) which downloads Rift and keeps it up to date automatically.

Startup options

In Settings - Windows you can enable:

The app uses the same interface as the web version at modeminc.com/rift - your account works on both.

Interface Overview

The Rift interface has four main areas:

AreaWhat it does
Server Rail (far left)Icons for every server you're in. Click to switch servers. The + button creates or joins a server.
Channel SidebarLists all channels in the current server, grouped by category. DMs are shown here too when no server is selected.
Messages AreaThe main chat area for the selected channel.
Members SidebarShows who's in the server and their online status. Click a member to see their profile.

Settings

Click the gear icon at the bottom of the channel sidebar to open Settings. Tabs cover your profile, account, appearance, notifications, voice & video, and (in the desktop app) Windows-specific options.

Servers

Creating a server

Click the + button in the server rail, then choose Create a Server. Give it a name and an optional icon. Rift automatically creates a General text channel and a General voice channel to get you started.

Joining a server

Click + and choose Join a Server, then paste an invite link. You can also click a direct invite URL (e.g. modeminc.com/rift/invite/abc123).

Inviting people

Right-click any text channel and select Invite People, or go to Server Settings - Invites - Create Invite. Share the link anywhere.

Server Settings

Click the server name at the top of the channel list to open the server menu, then choose Server Settings. From here you can:

Roles & Permissions

Roles control what members can do. Go to Server Settings - Roles to create roles, set permissions, and assign colors. The @everyone role applies to all members. Roles higher in the list have more authority over lower roles.

The server owner always has every permission regardless of role configuration. There is no permission check that can override the owner.

Channels

Create a channel by clicking + next to a category name in the channel list. Choose a type:

TypeDescription
TextStandard chat channel. Members send messages, react, reply, and share files.
VoiceJoin to talk with others. Supports video and screen share.
AnnouncementOnly members with the right permission can post. Good for server-wide news.
ForumPosts with titles and tags. Members reply to individual posts.
RulesA read-only numbered list of server rules.
LogAudit log for bot/webhook messages. Read-only in the UI. Messages auto-delete after 24 hours.

Channel Permissions

Right-click a channel and select Edit Channel, then go to Permissions. You can allow or deny specific actions for individual roles or members - for example, making a channel read-only for everyone except moderators.

Messaging

Sending a message

Click in the message bar at the bottom of the channel and start typing. Press Enter to send. Use Shift+Enter for a new line without sending.

Replying

Hover over a message and click the reply arrow to reply directly to it. Your message will show a reference to the original above it.

Editing & Deleting

Hover over your own message to reveal the action bar in the top-right corner. Click the pencil to edit or the trash to delete. Server moderators can delete any message.

Reactions

Hover over a message and click the smiley face icon. Pick an emoji from the picker. Click an existing reaction to add yours too. Click your own reaction again to remove it.

Pinning messages

Moderators can pin important messages. Right-click a message (or use the action bar) and select Pin Message. View pinned messages by clicking the pin icon in the channel header.

Formatting toolbar

Click the A icon above the message input to open the format toolbar. It has buttons for Bold, Italic, Underline, Strike, Code, Code Block, Spoiler, Color, Rainbow, Glow, Bar graph, Circle graph, Gauge, and Stat block.

Attachments

Click the + icon in the message bar to attach a file. Images and videos are embedded inline. Files are stored with their original filename.

Direct Messages

Click a user's avatar or username anywhere in Rift to open their profile, then click Send Message. DMs appear in the left sidebar when you're not in a server.

You can also use the friends panel (the person icon in the server rail) to manage friend requests and open DMs with friends.

Closing a DM hides it from your list but does not delete the message history. If the person messages you again, it reappears.

Voice & Video

Click a voice channel in the sidebar to join. A control bar appears at the bottom with:

Click a user's avatar in the voice channel to adjust their volume for you locally.

In Settings - Voice & Video you can select your input and output devices and adjust microphone sensitivity.

Markdown Formatting

Rift supports standard markdown syntax in all messages and webhooks. Formatting is rendered client-side - the server stores raw text.

SyntaxResult
**bold**Bold text
*italic*Italic text
~~strikethrough~~Strikethrough
||spoiler||Hidden until clicked
`inline code`Inline monospace code
```lang + newline + code + ```Syntax-highlighted code block
![alt](https://url)Embedded image
[label](https://url)Hyperlink
bare URLAuto-linked
@usernameUser mention
@everyone / @hereMass mention

Rift Widgets

Rift has custom formatting tags that go beyond markdown. Use them in messages or webhook content. All widget tags are processed before markdown.

Colored text

Wrap text in a color name or hex code:

rift
[red:This text is red]
[#6c63ff:This text is purple]
[orange:Warning!]

Rainbow text

rift
[rainbow:Hello Rift!]

Each character cycles through a set of colors.

Glow text

rift
[glow:purple:Online]
[glow:#22c55e:Success]

Bar graph

rift
[bargraph:75%:green]
[bargraph:40%:#4ecbff]

Inline horizontal progress bar. Value is 0-100%.

Circle graph

rift
[circlegraph:50%:orange]

SVG circular progress ring with percentage in the center.

Gauge

rift
[gauge:80%:red]

Semicircular speedometer-style gauge.

Stat block

rift
[stat:Username:kipi9876]
[stat:Account Age:7957 days][stat:Time Spent:6 minutes]

Small card with a label above a value. Stack multiple on one line to make a stat row.

Pill badge

rift
[pill:ONLINE:green]
[pill:ERROR:#ef4444]

Rounded colored badge - useful for status labels alongside other content.

What are Webhooks?

A Rift webhook is a URL you can POST JSON to and a message appears in your channel instantly. You need a Rift account to create one, but once created any app or script can use the URL - no login required to post.

Each webhook has a name shown as the message author (with an APP badge), an optional avatar, a secret URL, and a channel it posts into.

Keep your webhook URL private. It contains your secret - anyone with the URL can post to your channel. If it leaks, use Refresh to rotate it immediately.

Creating a Webhook

Click the server name at the top of the channel list and open Server Settings.

Go to the Webhooks tab. Enter a name (e.g. "GitHub Bot"), choose a channel, and click Create Webhook.

Click Copy next to the generated URL. Save it somewhere safe - that URL is your credential.

The webhook URL looks like:

url
https://rift.modeminc.com/v1/webhooks/{id}/{secret}

You can also manage webhooks here: rename, change avatar, refresh the secret, or delete.

Sending Messages

Send a POST to your webhook URL with a JSON body. Only Content-Type: application/json is required.

Fields

FieldRequiredDescription
contentrequiredThe message text. Max 2000 characters. All Rift formatting works here.
The display name comes from the webhook's name set in Server Settings. It is fixed and does not need to be sent with each request.

Quick test

bash
curl -X POST YOUR_WEBHOOK_URL \
  -H 'Content-Type: application/json' \
  -d '{"content": "Hello from a webhook!"}'

With widgets

Use Rift widgets to build rich messages. Stat blocks are especially useful for join/leave notifications:

json
{
  "content": "Gav2011 has joined the server.\n[stat:Username:Gav2011][stat:Account Age:7957 days]\n[stat:Time Spent:6 minutes]"
}
Post to a Log channel for audit-style messages. Log channels are read-only in the UI and automatically delete messages older than 24 hours.

Code Examples

bash
# Simple message
curl -X POST YOUR_WEBHOOK_URL \
  -H 'Content-Type: application/json' \
  -d '{"content":"Deployment complete"}'

# With formatting
curl -X POST YOUR_WEBHOOK_URL \
  -H 'Content-Type: application/json' \
  -d '{"content":"**Build #42 passed** [pill:OK:green]"}'

# Stat block notification
curl -X POST YOUR_WEBHOOK_URL \
  -H 'Content-Type: application/json' \
  -d '{"content":"Server alert!\n[stat:CPU:89%][stat:RAM:74%][bargraph:89%:red]"}'
javascript
const WEBHOOK = 'YOUR_WEBHOOK_URL';

async function notify(content) {
  await fetch(WEBHOOK, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ content })
  });
}

// Simple alert
notify('Server restarted');

// Rich stat notification
notify(`Gav2011 joined.\n[stat:Username:Gav2011][stat:Level:42][stat:Playtime:166h]`);

// CI/CD status
notify(`**Deploy complete** on \`main\` [pill:LIVE:green]\nhttps://myapp.com`);
python
import requests

WEBHOOK = "YOUR_WEBHOOK_URL"

def notify(content: str):
    requests.post(WEBHOOK, json={"content": content}).raise_for_status()

# Simple
notify("Backup complete")

# Stat block
notify(
    "Gav2011 left the server.\n"
    "[stat:Username:Gav2011][stat:Account Age:7957 days][stat:Time Spent:6 minutes]"
)

# GitHub Actions
import os
notify(
    f"**{os.environ['GITHUB_WORKFLOW']}** finished on `{os.environ['GITHUB_REF_NAME']}` [pill:PASSED:green]"
)
go
package main

import (
    "bytes"; "encoding/json"; "net/http"
)

const webhook = "YOUR_WEBHOOK_URL"

func notify(content string) {
    body, _ := json.Marshal(map[string]string{"content": content})
    http.Post(webhook, "application/json", bytes.NewReader(body))
}

func main() {
    notify("Deploy complete [pill:LIVE:green]")
    notify("Tests failed [pill:FAIL:red]")
}

What are Bots?

Rift bots are automated accounts your code controls. They appear in chat with a BOT badge next to their name and can send messages, react to messages, read channel history, and listen to real-time events via WebSocket - all from a server you write yourself.

Unlike webhooks (which only post messages), bots are full participants. They see everything happening in a server in real time and can respond intelligently.

Real-time events
Receive MESSAGE_CREATE, REACTION_ADD, MEMBER_JOIN, VOICE_JOIN and more over a WebSocket gateway.
REST API
Send messages, delete messages, add reactions, list members, fetch voice states - all over simple HTTP.
No approval needed
Create and deploy a bot instantly. The Verified badge is optional and requires an application.
Per-server install
Server owners install your bot via an invite link. The bot only sees servers it has been added to.

Creating an Application

Go to the Developer Portal and sign in with your Rift account.

Click + New Application. Enter a name (2-32 characters) and an optional description, then click Create.

Your bot token is shown once only. Copy it immediately and store it somewhere safe - you cannot view it again. If you lose it, regenerate it from the portal (which invalidates the old token).

Optionally upload a profile picture for your bot by clicking the avatar in Manage.

Never share or commit your bot token. Anyone with the token controls your bot. If it leaks, regenerate it immediately from the Developer Portal under Manage β†’ Regenerate Token.

Token format

Bot tokens look like:

token format
rbt_bot_XXXXXXXXXXXXXXXXXX.YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY

Use it as an Authorization header in every API call:

http
Authorization: Bot rbt_bot_XXXX.YYYY

Installing a Bot

Each bot has an invite link that server owners use to add it:

url
https://modeminc.com/rift/bot-invite/{bot_id}

Copy your invite link from the Developer Portal (the Copy Invite Link button on your app card). When a server owner opens it they can choose which of their servers to add the bot to.

A server member with Manage Server permission can also install via the API directly:

bash
# Server owner installs the bot (uses user JWT, not bot token)
curl -X POST https://rift.modeminc.com/v1/api/bots/{bot_id}/install \
  -H 'Authorization: Bearer {user_jwt}' \
  -H 'Content-Type: application/json' \
  -d '{"server_id": "srv_abc123"}'

To remove the bot from a server:

bash
curl -X DELETE https://rift.modeminc.com/v1/api/bots/{bot_id}/install/{server_id} \
  -H 'Authorization: Bearer {user_jwt}'

Real-time Gateway

Connect your bot to the WebSocket gateway to receive events in real time. Your bot will receive events for every server it is installed in.

Connecting

url
wss://rift.modeminc.com/v1/bot/gateway?token={bot_token}
Pass the token as a query parameter (without the Bot prefix). The Authorization header approach also works if your WebSocket client supports it: Authorization: Bot {token}.

READY event

Immediately after connecting you receive a READY event with your bot info and the list of server IDs you are in:

json
{
  "type": "READY",
  "payload": {
    "bot": {
      "id": "bot_XXXX",
      "name": "My Bot",
      "avatar_hash": "1234567890",
      "verified": false
    },
    "guilds": ["srv_abc", "srv_xyz"]
  }
}

Events

Event typeWhen it fires
message_createA message is sent in any channel in a server the bot is in
message_updateA message is edited
message_deleteA message is deleted
reaction_addA user adds an emoji reaction
reaction_removeA user removes a reaction
member_joinA user joins a server
member_leaveA user leaves or is kicked from a server
voice_state_updateA user joins or leaves a voice channel
presence_updateA member's online status changes

Event shape

All events follow the same envelope:

json
{
  "type": "message_create",
  "payload": {
    "id": "msg_XXXX",
    "channel_id": "ch_XXXX",
    "content": "Hello!",
    "timestamp": 1748800000,
    "author": {
      "id": "usr_XXXX",
      "username": "gavin",
      "avatar_hash": "abc",
      "bot": false
    }
  },
  "meta": { "server_id": "srv_XXXX", "channel_id": "ch_XXXX", "timestamp": 1748800000 }
}

JavaScript example

javascript
const BOT_TOKEN = 'rbt_bot_XXXX.YYYY';
const ws = new WebSocket(
  `wss://rift.modeminc.com/v1/bot/gateway?token=${BOT_TOKEN}`
);

ws.addEventListener('message', (event) => {
  const { type, payload, meta } = JSON.parse(event.data);

  if (type === 'READY') {
    console.log('Connected as', payload.bot.name);
  }

  if (type === 'message_create' && !payload.author.bot) {
    // Reply to "!ping"
    if (payload.content === '!ping') {
      sendMessage(payload.channel_id, 'Pong!');
    }
  }
});

async function sendMessage(channelId, content) {
  await fetch(
    `https://rift.modeminc.com/v1/bot/channels/${channelId}/messages`,
    {
      method: 'POST',
      headers: {
        'Authorization': `Bot ${BOT_TOKEN}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ content })
    }
  );
}

REST API

All bot REST endpoints are under https://rift.modeminc.com/v1/bot/ and require the header:

http
Authorization: Bot {your_bot_token}

Get bot info

http
GET /v1/bot/me

List guilds (installed servers)

http
GET /v1/bot/guilds

List channels in a server

http
GET /v1/bot/guilds/{server_id}/channels

List members in a server

http
GET /v1/bot/guilds/{server_id}/members

Get voice states in a server

http
GET /v1/bot/guilds/{server_id}/voice

Read messages

http
GET /v1/bot/channels/{channel_id}/messages?limit=50
ParamDescription
limitoptionalNumber of messages to return. Max 100, default 50.

Send a message

http
POST /v1/bot/channels/{channel_id}/messages
Content-Type: application/json

{ "content": "Hello from my bot!" }
FieldDescription
contentrequiredMessage text. Max 2000 characters. All Rift widget formatting supported.

Delete a message

Bots can only delete their own messages.

http
DELETE /v1/bot/channels/{channel_id}/messages/{message_id}

Add a reaction

http
POST /v1/bot/channels/{channel_id}/messages/{message_id}/reactions/{emoji}

URL-encode the emoji: %F0%9F%91%8D for πŸ‘, %E2%9D%A4%EF%B8%8F for ❀️.

Edit a message

Bots can only edit their own messages.

http
PATCH /v1/bot/channels/{channel_id}/messages/{message_id}
Content-Type: application/json

{ "content": "Edited text" }

Assign / change a member's roles

Requires the manage_roles permission. Replaces the member's roles with the list you send (send an empty array to clear them).

http
PUT /v1/bot/guilds/{server_id}/members/{user_id}/roles
Content-Type: application/json

{ "role_ids": ["role_abc", "role_def"] }

Add a single role to a member

Requires the manage_roles permission. Adds just this one role, leaving the member's other roles untouched. Returns the member's full role_ids after the change.

http
PUT /v1/bot/guilds/{server_id}/members/{user_id}/roles/{role_id}

Remove a single role from a member

Requires the manage_roles permission. Removes just this one role.

http
DELETE /v1/bot/guilds/{server_id}/members/{user_id}/roles/{role_id}

Add / remove several roles at once

Requires the manage_roles permission. Adds and/or removes multiple roles in a single atomic request, leaving the member's other roles untouched. Prefer this over firing several single-role calls in parallel - those can race and clobber each other. Returns the member's full role_ids after the change.

http
PATCH /v1/bot/guilds/{server_id}/members/{user_id}/roles
Content-Type: application/json

{ "add": ["role_a", "role_b", "role_c"], "remove": ["role_x"] }

Kick a member

Requires the kick_members permission.

http
DELETE /v1/bot/guilds/{server_id}/members/{user_id}

Create a channel

Requires the manage_channels permission. type is one of text, voice, stage, announcement, forum, rules, log (defaults to text).

http
POST /v1/bot/guilds/{server_id}/channels
Content-Type: application/json

{ "name": "general", "type": "text", "topic": "optional", "category_id": "optional" }

Delete a channel

Requires the manage_channels permission.

http
DELETE /v1/bot/channels/{channel_id}

Move a member to another voice channel

Requires the move_members permission. Works for both mesh and SFU voice channels.

http
POST /v1/bot/guilds/{server_id}/voice/{user_id}/move
Content-Type: application/json

{ "to_channel_id": "ch_xxxx" }

Disconnect a member from voice

Requires the move_members permission.

http
POST /v1/bot/guilds/{server_id}/voice/{user_id}/disconnect

Error responses

StatusMeaning
401Missing or invalid bot token
403Bot is not installed in that server
404Channel or message not found
400Validation error (e.g. content too long)

Verified Bot Badge

Any user can create a bot and use it right away - no approval required. The βœ“ VERIFIED badge is an optional distinction for bots that are widely used, well-maintained, and serve a clear purpose.

Verified bots display a green checkmark next to the BOT badge in every message they send.

Open the Developer Portal and find your application.

Click Apply for Verified Badge. Write a short reason describing your bot's purpose and how many servers it's in.

The Rift team reviews the application. Approved bots get the badge applied immediately and it appears in all past and future messages.

You don't need verification to build useful bots. Apply when your bot is mature, has real users, and you want to build trust in larger servers.

What is RiftScript?

RiftScript is a tiny automation language built into every server. With it you can react to messages, hand out (or remove) roles, post replies, and move members between voice channels - all without running a bot. The server owner and administrators can edit it under Server Settings β†’ Code. (Because a script can hand out roles, it's intentionally locked to that level - a regular moderator can't use it to elevate themselves.)

It is deliberately simple and safe: there are no loops, variables, or network access, so it can run on every message and reaction without slowing your server down or doing anything you didn't write. One script lives per server and runs automatically once saved and enabled.

New to it? The editor has a row of Templates (Welcome, Reaction role, AFK command, and more) - click one to drop a ready-made rule into your script, then tweak the names to match your server.

A script is made of rules. Each rule starts with on … (a trigger), followed by a { … } block of actions. Comments start with # or // and can be on their own line or at the end of a line.
riftscript
# When anyone says "ping", reply with pong
on message "ping" {
  reply "pong πŸ“"
}

Triggers

A trigger decides when a rule runs. Text matching is case-insensitive.

triggers
on message "hello"             # message is exactly "hello"
on message contains "spoiler"  # message contains the word
on message starts "!"          # message starts with "!"
on reaction "βœ…"               # βœ… added to ANY message
on reaction "βœ…" on "msg_id"   # βœ… added to ONE specific message
on unreaction "βœ…"             # βœ… REMOVED from a message (also: on removereaction)
on unreaction "βœ…" on "msg_id" # βœ… removed from ONE specific message
on join                        # a member joins the server
on leave                       # a member leaves the server

The member who sent the message, added or removed the reaction, or joined is called the actor - actions like giverole and movevoice apply to them. on unreaction is the mirror of on reaction: pair them to give a role when someone reacts and take it back when they un-react.

For a classic reaction-role message (react on a pinned post to get a role), scope the trigger to that message: post the message, hover it and click Copy message ID (the icon next to Reply), then use it as on reaction "βœ…" on "the_id". Without on "id", the rule fires for that emoji on every message.

Conditions

Wrap actions in an if block to run them only when a condition is true. Add not to invert it.

conditions
if hasrole "Pong Master" { … }       # actor has this role
if hasrole "Mod", "Admin" { … }      # actor has ANY of these roles
if not hasrole "Muted" { … }         # actor does NOT have the role
if inchannel "general", "chat" { … } # event was in any of these channels
if isowner { … }                     # actor is the server owner
Role and channel names must match exactly (case doesn't matter). If the name has spaces, keep them inside the quotes: "Pong Master". List several, comma-separated, and the condition is true if any match - e.g. if hasrole "Mod", "Admin". Names or copied ids both work.

Add an else { … } block to run something when the condition is false:

if / else
on message "!verify" {
  if hasrole "Verified" {
    reply "You're already verified βœ…"
  } else {
    giverole "Verified"
    reply "You're verified now! πŸŽ‰"
  }
}

Actions

Actions are what a rule does. Most take one quoted value; a few (delete, removeallroles) take none.

actions
reply "text"                       # reply to the triggering message
send "text"                        # post in the same channel
send "mod-log" "text"              # post into a named channel instead
react "πŸ˜€"                         # add a reaction to the triggering message
delete                             # delete the last message this rule sent
delete "msg_id"                    # delete one specific message
wait "5"                           # pause 5 seconds before the next action
giverole "Verified"                # give the actor a role
removerole "Muted"                 # remove a role from the actor
removeallroles                     # strip every role from the actor
movevoice "AFK"                    # move the actor into a voice channel
moveallvoice "General" "AFK"       # move EVERYONE from one voice channel to another
post "https://your-api.com" "{}"   # POST a JSON body to a URL
get "https://your-api.com/ping"    # GET a URL
delete with no value removes the last message this rule sent this run; if the rule hasn't sent one yet, it removes the message that triggered it. Give it a message id to delete a specific message (it must be in your server). wait "5" pauses before the next action - handy for a temporary message: reply "Verifying…", giverole "Verified", wait "3", delete. Waits are capped (up to 10s each, 20s total per run).

Give send two values to target another channel: the first is the channel, the second is the message. The channel must be a text or announcement channel in the same server.

For on join / on leave there is no triggering message, so reply and react do nothing - use send "channel" "text" to post a welcome/goodbye. giverole and movevoice work and apply to the member who joined or left. {user} is their name.

Names or IDs

Anywhere you name a role or channel (giverole, removerole, movevoice, and the send target) you can use either its name or its copied ID. Right-click a role or channel and choose Copy ID to paste it in - handy when two roles share a name or a name has tricky characters.

When you Save, the editor checks every role and channel you named. If one doesn't exist yet (e.g. a typo, or a role you haven't created), it saves anyway but shows a yellow warning like Role "NewComer" doesn't exist in this server. so you can fix the name or create the role.
using ids
on reaction "βœ…" {
  giverole "role_a1b2c3d4"     # by id
  giverole "Verified"          # or by name - both work
}

Calling an external API (post / get)

post "url" "json" sends a JSON POST; get "url" sends a GET. Use them to call your own webhook or API when something happens. The URL and body can include {user} / {mention}.

api example
on message "!deploy" {
  if hasrole "Maintainer" {
    post "https://api.yoursite.com/deploy" "{\"by\":\"{user}\"}"
    reply "Deploy triggered."
  }
}

on message "!status" {
  get "https://api.yoursite.com/ping"
}
Only http/https URLs are allowed, requests time out after 5 seconds, and the response is never read back into Rift - a script can trigger your API but can't pull data back in.

Inside any reply or send text you can use placeholders and references:

Arguments let you build commands that take input. They work in any value - including role/channel names - so a member can type the value:

command arguments
# A member types: !role Movie Night
on message starts "!role " {
  giverole "{args}"          # gives the "Movie Night" role
  reply "Gave you {args} 🎬"
}

# A member types: !say hello everyone
on message starts "!say " {
  if hasrole "Mod" { send "{args}" }
}

For on message starts "…", {args} is the text after the trigger word. For on message contains it's the whole message, and for an exact on message "…" there are no arguments.

Variables

Store a value with set name = "value" and reuse it anywhere as {name}. The value can include arguments and other placeholders, and is worked out at the moment you set it. Variables live for a single run of the script (they are not saved between messages).

variables
on message starts "!hi " {
  set who = "{arg1}"
  giverole "Member" "{who}"
  reply "Welcome {who}! πŸ‘‹"
}

Targeting another member

By default giverole, removerole, removeallroles and movevoice act on the member who triggered the rule. Add a target as the last value - a user id, username, or an argument - to act on someone else (they must be a member of your server):

targeting
giverole "Muted" "usr_abc123"      # give a role to a specific member
removeallroles "{arg1}"            # a member types: !wipe usr_abc123
movevoice "AFK" "{arg1}"           # move a named member to AFK

Moving a whole voice channel

moveallvoice "fromVC" "toVC" moves everyone currently in one voice channel into another - so you can build your own command:

!moveall command
# a mod types: !moveall General AFK   (names or channel ids both work)
on message starts "!moveall " {
  if hasrole "Mod" {
    moveallvoice "{arg1}" "{arg2}"
  }
}
Targeting and bulk moves are powerful. A script can only ever affect members of its own server, but you decide who can run a command - always gate destructive ones behind a condition like if hasrole "Mod" or if isowner so a regular member can't run !wipe on someone else.
welcome with mention & channel
on join {
  giverole "Newcomer"
  // greet them and point to the rules channel
  send "welcome" "Welcome {mention}! Please read the rules in ch_0syK4QTs3kAc πŸ“œ"
}
Messages from reply and send are posted as {ServerName}_RiftScript. They're saved like normal messages, so they survive reloads and a moderator can delete them. reply always posts in the channel that triggered it; to post elsewhere use send "channel" "text" with a channel name or id. Each event runs at most 25 actions.

For react, type a : in the Code editor to open an emoji picker, or paste any emoji directly. You can also react with a plain word - it's stored as-is.

Examples

Only let one role get a reply (everyone else is ignored):

role-gated reply
on message "ping" {
  if hasrole "Pong Master" {
    reply "pong πŸ“"
    react "πŸ“"
  }
}

Reaction roles - react on one specific message (copy its ID first) to self-assign a role:

reaction roles
on reaction "βœ…" on "msg_aBc123" {
  giverole "Verified"
}

on reaction "πŸ””" on "msg_aBc123" {
  giverole "Announcements"
}

Owner-only command to wipe all of your own roles:

reset roles
on message "!resetmyroles" {
  if isowner {
    removeallroles
    reply "All your roles were removed."
  }
}

Move yourself to the AFK channel with a command:

voice move
on message "!afk" {
  movevoice "AFK"
}

Welcome new members and auto-assign a starter role; say goodbye when they leave:

welcome & goodbye
on join {
  giverole "Newcomer"
  send "welcome" "Welcome to the server, {user}! πŸ‘‹"
}

on leave {
  send "welcome" "{user} just left. πŸ‘‹"
}

Log a keyword to a separate mod channel:

cross-channel log
on message contains "report" {
  send "mod-log" "{user} mentioned a report."
}

Auto-react to feedback posts, but only in one channel:

channel-scoped
on message contains "feedback" {
  if inchannel "suggestions" {
    react "πŸ‘"
    react "πŸ‘Ž"
  }
}

Limits

RiftScript only does the specific triggers, conditions, and actions listed on this page - it's not a general-purpose programming language.

HTML Pages

An HTML channel renders a custom web page (or an embedded external URL) right inside a server. They're created and edited by the Rift owner, and the page runs in a locked-down sandbox: it can use scripts, forms and popups, but it cannot read your token, your messages, or anything else in Rift.

Theme API

So your page can match the user's Rift appearance, Rift sends the current theme to your page with postMessage. Listen for it:

match Rift's light / dark theme
<script>
  window.addEventListener('message', (e) => {
    if (e.data && e.data.rift === true && e.data.type === 'theme') {
      // e.data.theme is "light", "dark", or "custom"
      document.documentElement.dataset.theme = e.data.theme;
    }
  });

  // Optional: ask for the theme immediately on load instead of waiting.
  parent.postMessage({ rift: true, type: 'getTheme' }, '*');
</script>
That's the whole bridge - Rift only ever sends the theme to your page. There's no way for a sandboxed page to read user data or call Rift on your behalf, by design.

Core & Quantum

Rift is free. Core and Quantum unlock extra features for power users.

For full pricing details, feature comparisons, and to subscribe, visit the Rift Pricing page.

Subscribe via BuyMeACoffee and link your account in Settings - Core & Quantum to activate your plan.