discord-rpc

An Python wrapper for Discord RPC API. Allow you to make own custom RPC.

Install

  • PyPI
pip install discord-rpc

Quick example

import discordrpc

rpc = discordrpc.RPC(app_id=12345678910)

rpc.set_activity(
      state="A super simple rpc",
      details="simple RPC"
    )

# Required if you only run Discord RPC on this file or current instance.
rpc.run()

rpc.run() is only used if you are only running Discord RPC on the current file/instance. If there are other programs/tasks on the current instance, rpc.run() does not need to be used.

See documentation here.
More examples here.

Changelog

7.0

Breaking :

  • utils.timestamp is now a function, not a variable. Update timestamp to timestamp() in your code.
  • subscribe() and unsubscribe() now raise DiscordNotOpened when Discord is closed and exit_if_discord_close=True (the default), instead of returning None. Catch it or pass exit_if_discord_close=False to keep the old behavior.
  • set_activity() now raises ActivityError when state or details is outside 2 to 128 characters, and ButtonError when a button has no label, a label over 32 characters, a URL over 512 characters, is a plain URL string, or is combined with join_secret, spectate_secret, or match_secret.
  • Event callbacks now run on their own thread instead of the IPC reader thread, so callbacks for events that arrive close together can run at the same time.
  • Application.public is now None when Discord does not report it, instead of False.

Added :

  • Unix pipe connect now also tries the Flatpak Discord socket at $XDG_RUNTIME_DIR/app/com.discordapp.Discord/discord-ipc-N by @orowith2os in #71

Fixed :

  • disconnect() now clears is_running, subscriptions, and callbacks even when the pipe was already disconnected
  • Unix pipe connect now falls back cleanly on any socket error, and closing no longer raises when Discord already closed the socket
  • run() no longer hangs forever when the heartbeat PING fails or Discord closes the connection
  • subscribe() and unsubscribe() now attempt to reconnect when the pipe is disconnected, and subscribe() after a reconnect subscribes again on Discord’s side
  • unsubscribe() now returns False (instead of None) when the event is not subscribed
  • Unsubscribing from the last event no longer closes the connection and wipes the presence
  • Windows: a second set_activity(), the run() heartbeat, unsubscribe(), and disconnect() no longer hang while the reader waits for data
  • Windows: connect now tries all 10 Discord pipes even when exit_if_discord_close=True
  • An invalid application ID now raises InvalidID
  • Calling set_activity(), subscribe(), or unsubscribe() inside an event callback no longer times out
  • Calling disconnect() from another thread, such as an event callback, now also stops run()
  • The handshake now gives up after 30 seconds with an RPCException, instead of waiting forever
  • clear() now returns the result of set_activity() instead of None
  • status_type now accepts the plain int value
  • rpc.User read before the handshake no longer stays empty after connecting
  • progress_bar() now raises ProgressbarError when current is negative or duration is zero or negative
  • AssetManager() no longer raises TypeError when constructed without an asset list
  • IPC reader now marks the pipe as disconnected on EOF or an empty OP_CLOSE frame
  • Fixed rpc-all-in-one.py and rpc-with-timestamp.py examples

Changed :

  • date_to_timestamp() now uses datetime.timestamp() instead of time.mktime()
  • get_app_info() and get_assets() now share a single fetch helper
  • ButtonError and ProgressbarError no longer define redundant constructors

6.5

Added :

  • Cross-platform event subscriptions with Event enum and @rpc.on() decorator by @SuperZombi in #66
  • AssetManager with RPC.assets property and .get() / .names for fetching application assets by @SuperZombi in #60
  • Asset object support in set_activity(). Pass rpc.assets.get("key") directly as large_image / small_image
  • utils.get_assets(app_id) to fetch assets without initializing RPC
  • RPC.connected read-only property by @SuperZombi in #63
  • User.avatar_decoration and Application.cover CDN URLs by @SuperZombi in #67
  • InvalidEvent and InvalidEventType exceptions, utils.required_url(), and examples/rpc-events.py

Changed :

  • IPC reads now preserve the opcode and route responses by nonce through a single background reader
  • Windows imports are now loaded only on Windows, no more msvcrt or win32pipe needed
  • URL validation now checks the scheme and host, and set_activity() validates button URLs client-side
  • Bumped GitHub Actions versions by @SuperZombi in #62
  • Docs and changelog links now point to DOCS.md and CHANGELOG.md on GitHub

Fixed :

  • Invalid method annotations in _send() and _request() that prevented importing the package
  • Unread PONG responses no longer corrupt subsequent requests, and incoming PING is answered with PONG
  • Handshake no longer requires a nonce
  • Failed subscriptions no longer register callbacks locally
  • Reader thread stops after the last unsubscribe and is cleaned up during disconnect

6.0

Added :

  • name parameter to RPC.set_activity(), falls back to the application name by @SuperZombi in #58
  • ping_every parameter to RPC.run() for configurable heartbeat interval
  • External URL image support for large_image and small_image

Changed :

  • User and App are now lazy-loaded @cached_property by @SuperZombi in #58
  • RPC.get_app_info() removed, use the rpc.App property directly
  • Button() renamed to button() for PEP8 compliance
  • Shared pipe logic extracted into _BasePipe class
  • TRY_RECONNECTING global converted to instance attribute self.try_reconnecting

Fixed :

  • Socket timeout prevention: heartbeat is now sent every 15 seconds by default in RPC.run()
  • Log handler duplication across multiple RPC instances, and logging.basicConfig() removed
  • SyntaxError on some Python versions caused by global variable declaration order
  • UnixPipe._recv() data truncation on large payloads
  • self.connected now reflects the real pipe connection result
  • Broken button arguments in print-rpc-output.py example

5.6

  • Fix importlib.metadata.PackageNotFoundError by @deeffest in #56
  • Add Application info fetching (rpc.get_app_info()) by @SuperZombi & @Senophyx in #57
  • Refactor: cleanup unused parameter comments and rename ProgressBar to progress_bar by @Senophyx
  • Fix typing and license metadata on pyproject.toml by @Senophyx
  • Replace all-contributors with contrib.rocks by @Senophyx
  • Update docs links and styling by @Senophyx

5.5

  • PEP 621: Migrating from setup.py to pyproject.toml by in #0ffaca5
  • feat: rewrite Button, added new ActivityType class, fix minor issues by @SuperZombi in #49
  • Add new types and params by @SuperZombi in #50
  • Add some missing types by @jannuary in #53

5.1

Updates :

rpc.set_activity(act_type=0)
  • Added more detailed information in the output.

5.0

Critical updates & changes :

  • Inputting id is no longer in RPC.set_id. Replaced with inputing inside RPC class.

Before:

rpc = discordrpc.RPC.set_id(app_id=1234567890)

After:

rpc = discordrpc.RPC(app_id=1234567890)

Updates :

  • Removing many functions. List:

    • RPC.set_id
    • RPC._connect
    • RPC._write
    • RPC._recv
    • RPC._recv_exact
    • And many more…
  • Package logging is used again as output.

  • Removing timestamp argument and added ts_start and ts_end on set_activity() as a replacement for the timestamp argument.

  • Added debug parameter on RPC class if you want to print more outputs.

  • timestamp variable is moved to discordrpc.utils. So if you want to import timestamp variable, use

    from discordrpc.utils import timestamp
  • button on discordrpc.button changed to Button.

  • added date_to_timestamp function on discordrpc.utils. with format %d/%m/%Y-%H:%M:%S or day/month/year-hour:minute:second Example :

    date_to_timestamp('14/06/2025-00:00:00')

4.0

Critical update :

  • Changing DiscordRPC folder (when you import the package) to discordrpc. Before :
import DiscordRPC

After :

import discordrpc

Updates :

  • No longer using logging package.
  • GCAR or get_current_application_running removed because it can’t be cross-platform (I spent days just looking for this solution lmao).
  • setLoggerEnabled() function removed.
  • Set_ID changed to set_id.
  • output() function changed to show_output variable, Example.
  • Shorten the code in presence.py (not that much though).

3.0

New & Updates :

  • Added GCAR method. GCAR : Get Current Application Running. Basically, you can switch your rpc status (state/details) automatically to the application you’re running

2.0

New & Updates :

  • Added button (Example here)
  • RPC output (Example here)
  • RPC still running even though “large_text” and “small_text” are not set
  • The message when RPC is running successfully is now working fine, and an error will appear if the RPC is not set properly