Platform-Specific Plugins
Write Plexcord plugins that run only on specific platforms. Learn the .web, .discordDesktop, and .plextron conventions and platform detection APIs.
Platform-Specific Plugins
Discord runs in multiple environments: the desktop Electron app, the web browser, and Plextron (Plexcord's custom Electron fork). Some plugins only make sense on specific platforms, or need different behavior per platform.
The Three Platforms
| Platform | Identifier | Description |
|---|---|---|
| Discord Desktop | IS_DISCORD_DESKTOP | Official Discord desktop app (Electron) |
| Web | IS_WEB | Discord in a browser (Chrome, Firefox, etc.) |
| Plextron | IS_PLEXTRON | Plexcord's own Electron app |
Runtime Detection
Import the platform constants from @utils/constants:
import { IS_DISCORD_DESKTOP, IS_WEB, IS_PLEXTRON } from "@utils/constants";
export default definePlugin({
name: "MyPlugin",
description: "Works on all platforms but does extra stuff on desktop",
authors: [{ name: "You", id: 0n }],
start() {
if (IS_DISCORD_DESKTOP) {
this.setupDesktopFeatures();
}
if (IS_WEB) {
this.setupWebFeatures();
}
if (IS_PLEXTRON) {
this.setupPlextronFeatures();
}
},
setupDesktopFeatures() {
// Access Node.js APIs, file system, etc.
},
setupWebFeatures() {
// Web-only: localStorage, service workers, etc.
},
setupPlextronFeatures() {
// Plextron-specific APIs
}
});File Name Conventions
Plexcord uses file naming to indicate platform support. The naming convention is:
| File Name | Platform |
|---|---|
index.ts | All platforms |
index.web.ts | Web browser only |
index.discordDesktop.ts | Discord desktop only |
index.plextron.ts | Plextron only |
Example: Platform-specific entry points
src/plugins/myPlugin/
├── index.ts ← All platforms (imports the right one)
├── index.web.ts ← Web-specific implementation
└── index.discordDesktop.ts ← Desktop-specific implementationThe bundler automatically picks the right file for each platform at build time.
Desktop-Only Features
Discord Desktop (Electron) has access to Node.js APIs that aren't available in the browser:
import { IS_DISCORD_DESKTOP } from "@utils/constants";
export default definePlugin({
name: "FileManager",
description: "Manage files (desktop only)",
authors: [{ name: "You", id: 0n }],
start() {
if (!IS_DISCORD_DESKTOP) {
console.warn("[FileManager] This plugin requires Discord Desktop");
return;
}
// Now safe to use desktop-only features
this.initFileSystem();
},
initFileSystem() {
// Access Electron's ipcRenderer, shell, etc.
const { ipcRenderer } = require("electron");
ipcRenderer.on("file-selected", this.onFileSelected.bind(this));
},
stop() {
if (!IS_DISCORD_DESKTOP) return;
const { ipcRenderer } = require("electron");
ipcRenderer.removeAllListeners("file-selected");
}
});Available Desktop APIs
electron: Full Electron API (IPC, shell, dialog, etc.)fs,path,os: Node.js built-in modules- Native file system access
- System notifications via Electron
- Window management
Web-Only Features
When running in a browser, you have access to browser-specific APIs:
import { IS_WEB } from "@utils/constants";
export default definePlugin({
name: "WebClipboard",
description: "Enhanced clipboard for web Discord",
authors: [{ name: "You", id: 0n }],
start() {
if (!IS_WEB) return;
this.setupClipboardAPI();
},
async setupClipboardAPI() {
// Modern Clipboard API (browser only)
if ("clipboard" in navigator) {
console.log("[WebClipboard] Clipboard API available");
}
// Service Worker registration (browser only)
if ("serviceWorker" in navigator) {
// Register service worker if needed
}
}
});Disabling a Plugin on Specific Platforms
The cleanest way to create a platform-exclusive plugin is to return early in start():
import { IS_DISCORD_DESKTOP } from "@utils/constants";
export default definePlugin({
name: "DesktopOnly",
description: "Only works on Discord Desktop; no-op on web",
authors: [{ name: "You", id: 0n }],
start() {
if (!IS_DISCORD_DESKTOP) return; // Early exit on wrong platform
// All code below only runs on desktop
this.init();
},
stop() {
if (!IS_DISCORD_DESKTOP) return;
this.cleanup();
}
});Cross-Platform Plugin Design
Strategy: Abstract platform differences
import { IS_DISCORD_DESKTOP, IS_WEB } from "@utils/constants";
interface StorageBackend {
get(key: string): Promise<string | null>;
set(key: string, value: string): Promise<void>;
}
// Desktop: Use Node's file system
const desktopStorage: StorageBackend = {
async get(key) { /* read from file */ },
async set(key, value) { /* write to file */ }
};
// Web: Use localStorage
const webStorage: StorageBackend = {
async get(key) { return localStorage.getItem(key); },
async set(key, value) { localStorage.setItem(key, value); }
};
const storage: StorageBackend = IS_DISCORD_DESKTOP ? desktopStorage : webStorage;
export default definePlugin({
name: "CrossPlatformStorage",
description: "Stores data using the best method per platform",
authors: [{ name: "You", id: 0n }],
async start() {
await storage.set("lastSeen", new Date().toISOString());
const lastSeen = await storage.get("lastSeen");
console.log("[CrossPlatformStorage] Last seen:", lastSeen);
}
});Platform Quick Reference
import { IS_DISCORD_DESKTOP, IS_WEB, IS_PLEXTRON } from "@utils/constants";
// Check platform
IS_DISCORD_DESKTOP // true on Discord's Electron app
IS_WEB // true in browser
IS_PLEXTRON // true on Plextron
// Mutually exclusive: only one is true at a time