Back to rankings

Phineas/lanyard

Elixirdiscord.gg/lanyard

🏷️   Expose your Discord presence and activities to a RESTful API and WebSocket in less than 10 seconds

discorddiscord-rpcelixir
Star Growth
Stars
1.4k
Forks
185
Weekly Growth
Issues
2
5001k
Jan 2023Mar 2024May 2025Jul 2026
README
Lanyard Logo

🏷️ Expose your Discord presence and activities to a RESTful API and WebSocket in less than 10 seconds

Lanyard is a service that makes it super easy to export your live Discord presence to an API endpoint (api.lanyard.rest/v1/users/:your_id) and to a WebSocket (see below) for you to use wherever you want - for example, I use this to display what I'm listening to on Spotify on my personal website. It also acts as a globally-accessible realtime KV store which you can update from the Lanyard Discord bot or from the Lanyard API.

You can use Lanyard's API without deploying anything yourself - but if you want to self host it, you have the option to, though it'll require a tiny bit of configuration.

Get started in < 10 seconds

Just join this Discord server and your presence will start showing up when you GET api.lanyard.rest/v1/users/:your_id. It's that easy.

Table of Contents

Community Projects

The Lanyard community has worked on some pretty cool projects that allows you to extend the functionality of Lanyard. PR to add a project!

lanyard-web - Landing page and API documentation concept for Lanyard API with a sleek UI.
lanyard-profile-readme - Utilize Lanyard to display your Discord Presence in your GitHub Profile
vue-lanyard - Lanyard API plugin for Vue. Supports REST and WebSocket methods
react-use-lanyard - React hook for Lanyard - supports REST & WebSocket
use-lanyard - Another React hook for Lanyard that uses SWR
lanyard-visualizer - Beautifully display your Discord presence on a website
js-lanyard - Use Lanyard in your Web App.
go-lanyard - Lanyard API wrapper for GoLang - supports REST & WebSocket
use-lanyard - Lanyard with Composition API for Vue. Supports REST and WebSocket methods
use-listen-along - Mock the discord 'Listen Along' feature within a react hook powered by the Lanyard API.
lanyard-graphql - A GraphQL port of the Lanyard API.
sk-lanyard - SvelteKit integration with Lanyard, supports REST & WebSocket.
svelte-lanyard - A Lanyard API wrapper for Svelte. Supports REST & WebSocket.
denyard - Lanyard API wrapper for Deno - Supports REST & WebSocket.
lanyard-ui - Lanyard visualizer focused on the KV aspect
discord-status-actions - Updates a file to include your discord status using the Lanyard API.
discordstatus-website - Display your Discord status on your own website with premade CSS, and JS
osu-nowplaying - A small tool to scrape the info of the map you're curently playing on osu!lazer and dump into a file for obs to read.
landart - A featureful API wrapper for Lanyard & Lanyard KV written in Dart.
lanyard.py - Modern and fully asynchronous wrapper for Lanyard API written in Python 3.12+.
lanyard-mcp-server - Exposing Lanyard API in MCP - with Docker support

API Docs

Getting a user's presence data

GET https://api.lanyard.rest/v1/users/:user_id

Example response:

{
  "success": true,
  "data": {
    "active_on_discord_mobile": false,
    "active_on_discord_desktop": true,
    "listening_to_spotify": true,
    // Lanyard KV
    "kv": {
      "location": "Los Angeles, CA"
    },
    // Below is a custom crafted "spotify" object, which will be null if listening_to_spotify is false
    "spotify": {
      "track_id": "3kdlVcMVsSkbsUy8eQcBjI",
      "timestamps": {
        "start": 1615529820677,
        "end": 1615530068733
      },
      "song": "Let Go",
      "artist": "Ark Patrol; Veronika Redd",
      "album_art_url": "https://i.scdn.co/image/ab67616d0000b27364840995fe43bb2ec73a241d",
      "album": "Let Go"
    },
    "discord_user": {
      "username": "Phineas",
      "public_flags": 131584,
      "id": "94490510688792576",
      "discriminator": "0001",
      "avatar": "a_7484f82375f47a487f41650f36d30318"
    },
    "discord_status": "online",
    // activities contains the plain Discord activities array that gets sent down with presences
    "activities": [
      {
        "type": 2,
        "timestamps": {
          "start": 1615529820677,
          "end": 1615530068733
        },
        "sync_id": "3kdlVcMVsSkbsUy8eQcBjI",
        "state": "Ark Patrol; Veronika Redd",
        "session_id": "140ecdfb976bdbf29d4452d492e551c7",
        "party": {
          "id": "spotify:94490510688792576"
        },
        "name": "Spotify",
        "id": "spotify:1",
        "flags": 48,
        "details": "Let Go",
        "created_at": 1615529838051,
        "assets": {
          "large_text": "Let Go",
          "large_image": "spotify:ab67616d0000b27364840995fe43bb2ec73a241d"
        }
      },
      {
        "type": 0,
        "timestamps": {
          "start": 1615438153941
        },
        "state": "Workspace: lanyard",
        "name": "Visual Studio Code",
        "id": "66b84f5317e9de6c",
        "details": "Editing README.md",
        "created_at": 1615529838050,
        "assets": {
          "small_text": "Visual Studio Code",
          "small_image": "565945770067623946",
          "large_text": "Editing a MARKDOWN file",
          "large_image": "565945077491433494"
        },
        "application_id": "383226320970055681"
      }
    ]
  }
}

KV

Lanyard KV is a a dynamic, real-time key->value store which is added to the Lanyard user API response. When a KV pair is updated, a PRESENCE_UPDATE for the user will also be emitted through the Lanyard socket.

Use cases

  • Configuration values for your website
  • Configuration values for Lanyard 3rd party projects
  • Dynamic data for your website/profile (e.g. current location)

Limits

  1. Keys and values can only be strings
  2. Values can be 30,000 characters maximum
  3. Keys must be alphanumeric (a-zA-Z0-9) and 255 characters max length
  4. Your user can have a maximum of 512 key->value pairs linked

Getting an API Key

DM the Lanyard bot (Lanyard#5766) with .apikey to get your API key.

When making Lanyard KV API requests, set an Authorization header with the API key you received from the Lanyard bot as the value.

Setting a key->value pair

Discord

.set <key> <value>

HTTP

PUT https://api.lanyard.rest/v1/users/:user_id/kv/:key The value will be set to the body of the request. The body can be any type of data, but it will be string-encoded when set in Lanyard KV.

Setting multiple key->value pairs

Discord

Not yet implemented

HTTP

PATCH https://api.lanyard.rest/v1/users/:user_id/kv The user's KV store will be merged with the body of the request. Conflicting keys will be overwritten. The body must be keyvalue pair object with a maximum depth of 1.

Deleting a key

Discord

.del <key>

HTTP

DELETE https://api.lanyard.rest/v1/users/:user_id/kv/:key

Socket Docs

The websocket is available at wss://api.lanyard.rest/socket. If you would like to use compression, please specify ?compression=zlib_json at the end of the URL.

Once connected, you will receive Opcode 1: Hello which will contain heartbeat_interval in the data field. You should set a repeating interval for the time specified in heartbeat_interval which should send Opcode 3: Heartbeat on the interval.

You should send Opcode 2: Initialize immediately after receiving Opcode 1.

Example of Opcode 2: Initialize:

{
  op: 2,
  d: {
    // subscribe_to_ids should be an array of user IDs you want to subscribe to presences from
    // if Lanyard doesn't monitor an ID specified, it won't be included in INIT_STATE
    subscribe_to_ids: ["94490510688792576", "156114103033790464"]
  }
}

Subscribing to multiple user presences

To subscribe to multiple presences, send subscribe_to_ids in the data object with a string[] list of user IDs to subscribe to. Then, INIT_STATE's data object will contain a user_id->presence map. You can find examples below.

Subscribing to a single user presence

If you just want to subscribe to one user, you can send subscribe_to_id instead with a string of a single user ID to subscribe to. Then, the INIT_STATE's data will just contain the presence object for the user you've subscribed to instead of a user_id->presence map.

Subscribing to every user presence

If you want to subscribe to every presence being monitored by Lanyard, you can specify subscribe_to_all with (bool) true in the data object, and you will then receive a user_id->presence map with every user presence in INIT_STATE, and their respective PRESENCE_UPDATES when they happen.

Once Op 2 is sent, you should immediately receive an INIT_STATE event payload if connected successfully. If not, you will be disconnected with an error (see below).

Unsubscribing from a user presence

If you no longer want to receive PRESENCE_UPDATEs for a user you've subscribed to, send Opcode 4: Unsubscribe with unsubscribe_from_id set to the string user ID you want to stop receiving updates for. Unlike Op 2, this does not send anything back - you'll simply stop receiving that user's presence updates.

Example of Opcode 4: Unsubscribe:

{
  op: 4,
  d: {
    // unsubscribe_from_id should be a single user ID (string) you no longer want to receive updates for
    unsubscribe_from_id: "94490510688792576"
  }
}

To unsubscribe from multiple users at once, send unsubscribe_from_ids with a string[] list of user IDs to stop receiving updates for. Any IDs you aren't subscribed to (or that aren't monitored) are simply ignored.

Example of Opcode 4: Unsubscribe from multiple:

{
  op: 4,
  d: {
    unsubscribe_from_ids: ["94490510688792576", "156114103033790464"]
  }
}

If you subscribed to every presence with subscribe_to_all, you can unsubscribe from all of them at once by sending Opcode 4: Unsubscribe with unsubscribe_from_all set to (bool) true. This removes you from the global subscriber list (so you won't receive updates for newly monitored users either) and stops updates for every user you're currently subscribed to.

Example of Opcode 4: Unsubscribe from all:

{
  op: 4,
  d: {
    unsubscribe_from_all: true
  }
}

List of Opcodes

Opcode Name Description Client Send/Recv
0 Event This is the default opcode when receiving core events from Lanyard, like INIT_STATE Receive
1 Hello Lanyard sends this when clients initially connect, and it includes the heartbeat interval Receive Only
2 Initialize Sent by the client after Opcode 1 to subscribe to presences - its data should contain subscribe_to_ids (array of IDs), subscribe_to_id (single ID), or subscribe_to_all (bool) Send only
3 Heartbeat Clients should send Opcode 3 every 30 seconds (or whatever the Hello Opcode says to heartbeat at) Send only
4 Unsubscribe Sent by the client to unsubscribe from presences - its data should contain unsubscribe_from_ids (array of IDs), unsubscribe_from_id (single ID), or unsubscribe_from_all (bool) Send only

Events

Events are received on Opcode 0: Event - the event type will be part of the root message object under the t key.

Example Event Message Objects

INIT_STATE

{
  op: 0,
  seq: 1,
  t: "INIT_STATE",
  d: {
    "94490510688792576": {
      // Full Lanyard presence (see API docs above for example)
    }
  }
}

PRESENCE_UPDATE

{
  op: 0,
  seq: 2,
  t: "PRESENCE_UPDATE",
  d: {
    // Full Lanyard presence
  }
}

Error Codes

Lanyard can disconnect clients for multiple reasons, usually to do with messages being badly formatted. Please refer to your WebSocket client to see how you should handle errors - they do not get received as regular messages.

Types of Errors

Name Code Data
Invalid/Unknown Opcode 4004 unknown_opcode
Opcode Requires Data 4005 requires_data_object
Invalid Payload 4006 invalid_payload

Lanyard quicklinks allow you to easily access resources from Discord, such as profile pictures.

User Icons

https://api.lanyard.rest/<id>.<file_type> Where id is the Discord user ID. file_type can be one of: png, gif, webp, jpg, or jpeg

Self-host with Docker

Build the Docker image by cloning this repo and running:

# The latest version is already on the docker hub, you can skip this step unless you would like to run a modified version.
docker build -t phineas/lanyard:latest .

If you don't already have a redis server you'll need to run one, here's the docker command to run one:

docker run -d --name lanyard-redis -v docker_mount_location_on_host:/data redis

And run Lanyard API server using:

docker run --rm -it -p 4001:4001 -e REDIS_HOST=redis -e BOT_TOKEN=<token> --link lanyard-redis:redis phineas/lanyard:latest

You'll be able to access the API using port 4001.

You also need to create a Discord bot and use its token above.

Create a bot here: https://discord.com/developers/applications

Make sure you enable these settings in your bot settings:

  • Privileged Gateway Intents > PRESENCE INTENT
  • Privileged Gateway Intents > SERVER MEMBERS INTENT

If you'd like to run Lanyard with docker-compose, here's an example:

version: "3.8"

services:
  redis:
    image: redis
    restart: always
    container_name: lanyard_redis
  lanyard:
    image: phineas/lanyard:latest
    restart: always
    container_name: lanyard
    depends_on:
      - redis
    ports:
      - 4001:4001
    environment:
      BOT_TOKEN: <token>
      REDIS_HOST: redis

Note, that you're hosting a http server, not https. You'll need to use a reverse proxy such as traefik if you want to secure your API endpoint.

Showcase

Below is a curated selection of websites using Lanyard right now, check them out! Some of them will only show an activity when they're active.

Related repositories
AstrBotDevs/AstrBot

AI Agent Assistant & development framework that integrates lots of IM platforms, LLMs, plugins and AI feature, and can be your openclaw alternative. ✨

PythonPyPIGNU Affero General Public License v3.0aichatbot
astrbot.app
37.8k2.7k
tqdm/tqdm

:zap: A Fast, Extensible Progress Bar for Python and CLI

PythonPyPIOtherprogressbarprogressmeter
tqdm.github.io
31.2k1.5k
discordjs/discord.js

A powerful JavaScript library for interacting with the Discord API

TypeScriptnpmApache License 2.0discord-apidiscord
discord.js.org
26.8k4.1k
TranslucentTB/TranslucentTB

A lightweight utility that makes the Windows taskbar translucent/transparent.

C++GNU General Public License v3.0taskbarwindows
translucenttb.github.io
19.9k1.2k
lss233/kirara-ai

🤖 可 DIY 的 多模态 AI 聊天机器人 | 🚀 快速接入 微信、 QQ、Telegram、等聊天平台 | 🦈支持DeepSeek、Grok、Claude、Ollama、Gemini、OpenAI | 工作流系统、网页搜索、AI画图、人设调教、虚拟女仆、语音对话 |

PythonPyPIGNU Affero General Public License v3.0chatgptopenai
kirara-docs.app.lss233.com
18.9k1.8k
elizaOS/eliza

Open source agentic operating system

TypeScriptnpmMIT Licenseagentagentic
elizaos.ai
18.8k5.6k
langbot-app/LangBot

Production-grade platform for building agentic IM bots - 生产级多平台智能机器人开发平台/ Agent、知识库编排、插件系统 / Bots for Discord / Slack / LINE / Telegram / WeChat(企业微信, 企微智能机器人, 公众号) / 飞书 / 钉钉 / QQ / Matrix e.g. Integrated with ChatGPT(GPT), DeepSeek, Dify, n8n, Langflow, Coze, Claude, Gemini, GLM, Ollama, SiliconFlow, Moonshot, openclaw / hermes agent, deerflow

PythonPyPIApache License 2.0qqopenai
langbot.app
17k1.5k
Rapptz/discord.py

An API wrapper for Discord written in Python.

PythonPyPIMIT Licensediscorddiscord-api
discordpy.rtfd.org/en/latest
16.1k3.9k
OpenRCT2/OpenRCT2

An open source re-implementation of RollerCoaster Tycoon 2 🎢

C++GNU General Public License v3.0c-plus-plusgame
openrct2.io
16k1.9k
lss233/chatgpt-mirai-qq-bot

🤖 可 DIY 的 多模态 AI 聊天机器人 | 🚀 快速接入 微信、 QQ、Telegram、等聊天平台 | 🦈支持DeepSeek、Grok、Claude、Ollama、Gemini、OpenAI | 工作流系统、网页搜索、AI画图、人设调教、虚拟女仆、语音对话 |

PythonPyPIGNU Affero General Public License v3.0chatgptopenai
kirara-docs.app.lss233.com
14.4k1.6k
Vendicated/Vencord

The cutest Discord modification

TypeScriptnpmGNU General Public License v3.0discordmod
vencord.dev
13.7k2.4k
Tyrrrz/DiscordChatExporter

Saves Discord chat logs to a file

C#MIT Licensediscordchat
github.com/Tyrrrz/DiscordChatExporter/releases
11.6k994