Command Palette

Search for a command to run...

Presence API

Use the Nowly Presence API to update Discord Rich Presence from a website integration.

Creating a Presence

Presence is a global injected by the Nowly runtime - you don't need to import it.

Every presence starts with a Presence instance:

const presence = new Presence()

UpdateData Event

Use UpdateData to refresh activity:

presence.on("UpdateData", async () => {
  await presence.setActivity({
    details: "Watching a video",
  })
})

setActivity

setActivity sends the current Discord activity. Common fields include:

FieldTypeDescriptionDefault
detailsUrlstringOptional public HTTPS link for details (SDK 1.7.0+).-
stateUrlstringOptional public HTTPS link for state (SDK 1.7.0+).-
namestringOptional activity name. Defaults to the presence name.-
statusDisplayType0 | 1 | 2Field shown in Discord's compact status: 0 = name (default), 1 = state, 2 = details.-
detailsstringPrimary activity line shown in Discord.-
statestringSecondary activity line shown below details.-
startTimestampnumberUnix timestamp for elapsed activity progress.-
endTimestampnumberUnix timestamp for remaining activity progress.-
largeImageKeystringMain image asset key, usually Assets.Logo or Assets.Thumbnail (globals provided by the runtime).-
largeImageTextstringTooltip for the large image.-
smallImageKeystringOptional small image asset key.-
smallImageTextstringTooltip for the small image.-
typenumberDiscord activity type from PresenceType.-
buttonsarrayOptional Discord activity buttons.-

Discord rejects Rich Presence payloads when largeImageText or smallImageText contains fewer than two characters. Nowly trims these optional tooltips and omits them when the result is shorter than two characters; the image remains available.

detailsUrl / stateUrl

SDK 1.7.0+ adds optional string fields detailsUrl and stateUrl to make the corresponding activity lines clickable, independently of buttons. Both the extension and native host must support them; older runtimes ignore them. The activity name is not affected.

Use verified public HTTPS URLs, without credentials and no longer than 2048 characters. Links without corresponding text or with invalid URLs are omitted. Keep content identifiers such as YouTube's v query parameter, but never expose access tokens, private chats, secret links, or information hidden by privacy settings. Omit a link when its destination is unknown.

await presence.setActivity({
  details: "Video title",
  detailsUrl: "https://www.youtube.com/watch?v=VIDEO_ID",
  state: "Channel name",
  stateUrl: "https://www.youtube.com/@channel",
})

statusDisplayType

statusDisplayType chooses the text shown in Discord's compact status. It does not change the activity card's name, details, or state.

  • 0 (default): name
  • 1: state
  • 2: details

For example, show the video title in the compact status while keeping the activity name and channel in the card:

await presence.setActivity({
  name: "Video service",
  details: "Video title",
  state: "Channel name",
  statusDisplayType: 2,
})

Use an SDK version that includes this field and update both the Nowly extension and native host. Older runtime versions ignore the field and keep the default status display.

clearActivity

Call clearActivity when there is nothing worth showing:

presence.clearActivity()

PresenceType

PresenceType is a named export from @nowly/sdk:

import { PresenceType } from "@nowly/sdk"

It maps to Discord activity types: Playing, Streaming, Listening, Watching, and Competing.

getSetting

Read a typed per-presence setting after Presence.Settings. The value is the user's saved setting, or the definition default:

const showButtons = await presence.getSetting<boolean>("showButtons")

UpdateData also receives ctx.settings with the same map. Both update when the user changes settings in the side panel.

Logging

Use presence.info and presence.error for debug messages during development.