A Python wrapper for the Discord RPC API that allows you to create your own custom Rich Presence.
pip install discord-rpcDiscord desktop app must be running on the same machine.
- Go to https://discord.com/developers/applications
- Click "New Application" if you don't have application
- Insert the name of your application
- Copy
APPLICATION ID
Step-by-step making simple rich presence using Discord-RPC.
-
Make sure Discord-RPC is installed.
-
Import Discord-RPC
import discordrpc
-
Make
rpcvariable fromdiscordrpc.RPCwith your unique Application ID.rpc = discordrpc.RPC(app_id=1234)
-
Customizing activity using
rpc.set_activity().rpc.set_activity( state="A super simple rpc", details="simple RPC" )
-
Creating loop for
rpcso that it can keep running.rpc.run()
-
Done! Run your file.
class RPC:
def __init__(...): -> NoneCreates an IPC client and attempts to connect to the local Discord instance.
Parameters:
- app_id (int) — Your Discord Application (Client) ID.
- debug (bool, default:
False) — IfTrue, enables verbose logging (DEBUG). - output (bool, default:
True) — IfFalse, silences logger output. - exit_if_discord_close (bool, default:
True) — IfTrue, raises when Discord is not found or closed. - exit_on_disconnect (bool, default:
True) — IfTrue, exits the process when the socket disconnects.
Variables:
- is_running (bool) — Whether the RPC successfully set an activity.
- try_reconnecting (bool, default:
True) — Whether to attempt reconnecting on disconnect. - User (cached_property) — Returns a
Userobject populated after handshake (see User). - App (cached_property) — Returns an
Applicationobject fetched from Discord API (see App).
def set_activity(...): -> Optional[bool]Sets or updates the current Rich Presence. Returns True on success.
Parameters (all optional unless stated):
- name (str) — Name of the activity. If not provided, Discord uses the application name by default.
- details (str) — Upper line of the activity.
- state (str) — Lower line of the activity.
- act_type (Activity, default:
Activity.Playing) — See Activity Types. - status_type (StatusDisplay, default:
StatusDisplay.Name) — Which field is considered the status name for some clients. - large_image (str) — Key of an uploaded Rich Presence Asset, or an external direct URL.
- large_text (str) — Tooltip when hovering the large image.
- large_url (str) — Optional URL for the large image.
- small_image (str) — Key of a small asset, or an external direct URL.
- small_text (str) — Tooltip for the small image.
- small_url (str) — Optional URL for the small image.
- state_url, details_url (str) — Optional link targets when clicking the text.
- ts_start, ts_end (int) — Unix timestamps (seconds). See Utils for helpers.
- party_id (str) — ID to identify a party or session.
- party_size (list[int, int]) — Current and max size, e.g.
[2, 5]. - join_secret, spectate_secret, match_secret (str) — Secrets for join/spectate/match.
- buttons (list[dict]) — Up to 2 buttons created by
button(). - clear (bool) — If
True, clears the activity.
Notes:
act_typemust be atypes.Activitymember; otherwiseInvalidActivityTypeis raised.Activity.StreamingandActivity.Customare disabled for Rich Presence updates and will raiseActivityTypeDisabled.- Images can be an uploaded asset key or an external direct URL (PNG, JPEG, WebP, GIF, AVIF).
def run(update_every: int = 1, ping_every: int = 15): -> NoneKeeps the RPC alive. Not required if another task is running on the same file.
Parameters:
- update_every (int, default:
1) — Loop sleep interval. - ping_every (int, default:
15) — OP_PING heartbeat interval to prevent socket timeout.
def clear(): -> NoneClears the current activity without disconnecting.
def disconnect(): -> NoneCloses the IPC socket and marks the client as disconnected.
rpc.User # cached_property, populated after handshakeA lightweight User model.
Attributes:
- id (int) — Discord user ID.
- username (str) — Username.
- name (str) — Global display name.
- avatar (str) — CDN URL (animated GIF detection supported).
- bot (bool) — Whether the user is a bot.
- premium_type (int) — Discord Nitro tier.
import discordrpc
rpc = discordrpc.RPC(app_id=123456789)
print(rpc.User.name)
print(f"@{rpc.User.username}")
rpc.run()rpc.App # cached_property, lazy-loaded from Discord APIAn Application model. The HTTP request is lazy-loaded on first access.
Attributes:
- id (int) — Application ID.
- name (str) — Application name.
- description (str) — Application description.
- icon (str) — CDN URL to the application icon.
- verified (bool) — Whether the application is verified.
- public (bool) — Whether the bot is public.
from discordrpc import button
button(text: str, url: str) -> dictCreates a Discord-compatible button payload (max 2 buttons).
Parameters:
- text (str) — Button label.
- url (str) — Must start with
http://orhttps://. RaisesInvalidURLotherwise.
import discordrpc
from discordrpc import button
rpc = discordrpc.RPC(app_id=123456789)
rpc.set_activity(
state="Made by Senophyx",
details="Discord-RPC",
buttons=[
button("Repository", "https://github.com/Senophyx/discord-rpc"),
button("Discord", "https://discord.gg/qpT2AeYZRN"),
]
)
rpc.run()from discordrpc import utilstimestamp -> intReturns the current time in epoch timestamp.
def date_to_timestamp(date: str) -> intConverts %d/%m/%Y-%H:%M:%S format to epoch timestamp.
def use_local_time() -> dictReturns a ts_start payload starting from midnight today.
def progress_bar(current: int, duration: int) -> dictReturns ts_start and ts_end based on progress. Raises ProgressbarError if current > duration.
def get_app_info(app_id: int) -> dictFetch application info from Discord API without initializing RPC.
from discordrpc import ActivityActivity.Playing(0)Activity.Streaming(1) — disabled for RPCActivity.Listening(2)Activity.Watching(3)Activity.Custom(4) — disabled for RPCActivity.Competing(5)
from discordrpc import StatusDisplayStatusDisplay.Name(0)StatusDisplay.State(1)StatusDisplay.Details(2)
All exceptions extend RPCException.
| Exception | Description |
|---|---|
RPCException |
Base exception |
Error(message) |
Generic user error |
DiscordNotOpened() |
Discord not found/running |
ActivityError() |
Invalid activity payload |
InvalidURL() |
URL not starting with http/https |
InvalidID() |
Invalid Application ID |
ButtonError(message) |
Button limit exceeded |
ProgressbarError(message) |
Invalid progress values |
InvalidActivityType(message) |
act_type not a valid Activity |
ActivityTypeDisabled() |
Streaming/Custom blocked by Discord |
- "Discord is closed" — Ensure desktop app is running. On Linux, check
$XDG_RUNTIME_DIR/tmp/discord-ipc-*. ActivityTypeDisabled— UsePlaying,Listening,Watching, orCompetinginstead.- Buttons don't show — Max 2 buttons, URLs must start with
http://orhttps://. - No images appear — Upload assets to Discord Developer Portal Art Assets section.
- App exits on disconnect — Set
exit_on_disconnect=False. - Silence logs — Pass
output=False.
Q: Do I need a bot token?
A: No. Only an Application ID.
Q: Can I update presence from a server?
A: No. This is client-side IPC, Discord must run on the same machine.
Q: Can I use Streaming or Custom activity?
A: No, those types are disabled and raise ActivityTypeDisabled.
MIT License
Copyright (c) 2021-2025 Senophyx