A modern, type-safe Svelte 5 library for seamless Discord Lanyard API integration with real-time WebSocket and REST support.
# pnpm
pnpm add sveltekit-lanyard
# bun
bun add sveltekit-lanyard
<script lang="ts">
import { useLanyard } from 'sveltekit-lanyard';
const lanyard = useLanyard({
connectionType: 'rest',
userId: '769702535124090904'
});
</script>
{#if lanyard.loading}
<p>Loading presence...</p>
{:else if lanyard.data}
<p>{lanyard.data.discord_user.username} is {lanyard.data.discord_status}</p>
{/if}
<script lang="ts">
import { useLanyard } from 'sveltekit-lanyard';
const lanyard = useLanyard({
connectionType: 'ws',
subscriptionScope: {
subscribe_to_id: '769702535124090904'
}
});
</script>
{#if lanyard.connected && lanyard.data}
<p>{lanyard.data.discord_user.username} is {lanyard.data.discord_status}</p>
{/if}
The REST API is ideal for simple use cases where you want to fetch presence data on-demand or at intervals.
<script lang="ts">
import { useLanyard } from 'sveltekit-lanyard';
const lanyard = useLanyard({
connectionType: 'rest',
userId: '94490510688792576'
});
</script>
<div class="presence-card">
{#if lanyard.loading}
<div class="loading">
<p>Loading presence data...</p>
</div>
{:else if lanyard.error}
<div class="error">
<p>Error: {lanyard.error.message}</p>
<button onclick={() => lanyard.refetch()}>Retry</button>
</div>
{:else if lanyard.data}
<div class="user-info">
<img
src="https://cdn.discordapp.com/avatars/{lanyard.data.discord_user.id}/{lanyard.data
.discord_user.avatar}.png"
alt="Avatar"
/>
<h2>{lanyard.data.discord_user.username}</h2>
<span class="status status-{lanyard.data.discord_status}">
{lanyard.data.discord_status}
</span>
</div>
<button onclick={() => lanyard.refetch()}>Refresh</button>
{/if}
</div>
<script lang="ts">
import { useLanyard } from 'sveltekit-lanyard';
const lanyard = useLanyard({
connectionType: 'rest',
userId: '94490510688792576'
});
// Refetch every 30 seconds
$effect(() => {
const interval = setInterval(() => {
lanyard.refetch();
}, 30000);
return () => clearInterval(interval);
});
</script>
The WebSocket API provides real-time updates whenever a user's presence changes on Discord.
<script lang="ts">
import { useLanyard } from 'sveltekit-lanyard';
const lanyard = useLanyard({
connectionType: 'ws',
subscriptionScope: {
subscribe_to_id: '94490510688792576'
}
});
</script>
<div class="presence-realtime">
{#if !lanyard.connected}
<p>Connecting to WebSocket...</p>
{:else if lanyard.error}
<p class="error">{lanyard.error}</p>
{:else if lanyard.data}
<div class="user">
<h2>{lanyard.data.discord_user.username}</h2>
<p>Status: {lanyard.data.discord_status}</p>
{#if lanyard.lastUpdate}
<p class="timestamp">
Last update: {new Date(lanyard.lastUpdate.d.timestamp).toLocaleString()}
</p>
{/if}
</div>
{/if}
</div>
<script lang="ts">
import { useLanyard } from 'sveltekit-lanyard';
const lanyard = useLanyard({
connectionType: 'ws',
subscriptionScope: {
subscribe_to_ids: ['94490510688792576', '162619778399240192', '261304190928461824']
}
});
</script>
{#if lanyard.connected && lanyard.data}
<div class="users-grid">
{#each Object.values(lanyard.data) as user}
<div class="user-card">
<h3>{user.discord_user.username}</h3>
<span class="status-{user.discord_status}">
{user.discord_status}
</span>
{#if user.listening_to_spotify}
<div class="spotify-mini">
🎵 Listening to {user.spotify.song}
</div>
{/if}
</div>
{/each}
</div>
{/if}
<script lang="ts">
import { useLanyard } from 'sveltekit-lanyard';
const lanyard = useLanyard({
connectionType: 'ws',
subscriptionScope: {
subscribe_to_all: true
}
});
</script>
useLanyard(options)The main function to initialize a Lanyard connection.
{
connectionType: 'rest';
userId: string; // Discord user ID (Snowflake)
polling?: boolean; // Enable automatic polling (default: false)
pollingInterval?: number; // Polling interval in ms (default: 5000)
apiUrl?: string; // Custom REST API URL (default: 'https://api.lanyard.rest/v1')
}
REST Options:
connectionType - Must be 'rest' for REST modeuserId - Discord user ID (Snowflake)polling - Optional. Enable automatic polling to refresh data at intervals (default: false)pollingInterval - Optional. Polling interval in milliseconds (default: 5000, only applies when polling is true)apiUrl - Optional. Custom REST API base URL for self-hosted Lanyard instances (default: 'https://api.lanyard.rest/v1'){
connectionType: 'ws';
subscriptionScope:
| { subscribe_to_id: string } // Single user
| { subscribe_to_ids: string[] } // Multiple users (array of user IDs)
| { subscribe_to_all: true } // All users
maxReconnectAttempts?: number; // Max reconnection attempts (default: 3)
reconnectDelay?: number; // Delay between reconnects in ms (default: 1000)
wsUrl?: string; // Custom WebSocket URL (default: 'wss://api.lanyard.rest/socket')
}
WebSocket Options:
connectionType - Must be 'ws' for WebSocket modesubscriptionScope - Subscription configuration:subscribe_to_id - Single user ID to subscribe tosubscribe_to_ids - Array of user IDs to subscribe tosubscribe_to_all - Subscribe to all users (requires special access)maxReconnectAttempts - Optional. Maximum number of automatic reconnection attempts (default: 3)reconnectDelay - Optional. Delay in milliseconds between reconnection attempts (default: 1000)wsUrl - Optional. Custom WebSocket URL for self-hosted Lanyard instances (default: 'wss://api.lanyard.rest/socket'){
data: LanyardPresenceData | null;
error: { message: string; code: string } | null;
loading: boolean;
refetch: () => Promise<void>;
}
Properties:
data - The user's presence data, or null if not loadederror - Error object if request failed, or nullloading - true during initial load or hydrationrefetch() - Function to manually refresh the data{
data: LanyardPresenceData | Record<string, LanyardPresenceData> | null;
error: string | null;
connected: boolean;
initState: InitStatePayload | null;
lastUpdate: PresenceUpdatePayload | null;
}
Properties:
data - Presence data (single user object or multi-user record)error - Error message if connection failed, or nullconnected - true when WebSocket is connectedinitState - Initial state received from WebSocket on connectionlastUpdate - The most recent presence update eventEnable automatic polling to keep REST data fresh without manual intervention:
<script lang="ts">
import { useLanyard } from 'sveltekit-lanyard';
const lanyard = useLanyard({
connectionType: 'rest',
userId: '94490510688792576',
polling: true, // Enable automatic polling
pollingInterval: 3000 // Poll every 3 seconds (default: 5000ms)
});
</script>
<div>
{#if lanyard.data}
<p>{lanyard.data.discord_user.username} is {lanyard.data.discord_status}</p>
<p class="info">Data automatically refreshes every 3 seconds</p>
{/if}
<!-- Manual refresh is still available -->
<button onclick={() => lanyard.refetch()}>Refresh Now</button>
</div>
WebSocket connections automatically attempt to reconnect when disconnected:
<script lang="ts">
import { useLanyard } from 'sveltekit-lanyard';
const lanyard = useLanyard({
connectionType: 'ws',
subscriptionScope: {
subscribe_to_id: '94490510688792576'
},
maxReconnectAttempts: 5, // Try up to 5 times (default: 3)
reconnectDelay: 2000 // Wait 2 seconds between attempts (default: 1000ms)
});
</script>
<div>
{#if lanyard.connected}
<span class="badge badge-success">Connected</span>
{:else if lanyard.error}
<span class="badge badge-error">Connection Error</span>
<p>Attempting to reconnect...</p>
{:else}
<span class="badge badge-warning">Connecting...</span>
{/if}
</div>
Default URLs:
https://api.lanyard.rest/v1wss://api.lanyard.rest/socketimport type {
LanyardPresenceData,
LanyardRestApi,
LanyardWebSocketApi,
LanyardClient,
LanyardGeneric
} from 'sveltekit-lanyard';
type LanyardPresenceData = {
active_on_discord_mobile: boolean;
active_on_discord_desktop: boolean;
active_on_discord_embedded: boolean;
active_on_discord_web: boolean;
listening_to_spotify: boolean;
spotify?: {
track_id: string;
song: string;
artist: string;
album: string;
album_art_url: string;
timestamps: {
start: number;
end: number;
};
};
discord_user: {
id: string;
username: string;
avatar: string;
discriminator: string;
bot: boolean;
global_name: string | null;
avatar_decoration_data: any | null;
display_name: string | null;
public_flags: number;
};
discord_status: 'online' | 'dnd' | 'idle' | 'offline';
activities: Activity[];
kv: Record<string, string>;
};
Discord activity object following Discord API types.
type Activity = {
name: string;
type: number;
state?: string;
details?: string;
timestamps?: {
start?: number;
end?: number;
};
assets?: {
large_image?: string;
large_text?: string;
small_image?: string;
small_text?: string;
};
// ... and more Discord activity properties
};
You can check out a few examples in /examples
A: Lanyard is a service that exposes Discord presence data through a simple API. You need to join the Lanyard Discord server to use it with your Discord account.
A: Enable Developer Mode in Discord settings, then right-click a user and select "Copy ID".
A: Both modes expose an error property. For REST, you can retry with refetch(). WebSocket automatically attempts to reconnect based on your maxReconnectAttempts setting.
MIT © Mufaro