Command Palette

Search for a command to run...

Metadata

Document every required and optional field in a Nowly presence metadata.json file.

Required Fields

Every presence needs:

FieldTypeDescriptionDefault
name*stringDisplay name of the service or platform.-
author*objectMain author displayed first in the library and OG images.-
description*objectShort localized descriptions keyed by locale.-
url*string[]Supported domains or URL patterns for matching pages.-
color*stringBrand color in hex format, used by UI and embeds.-
category*stringOne of streaming, music, video, social, gaming, tools, ai, learning, creator, or other.-

Example

{
  "name": "YouTube",
  "author": {
    "name": "Nowly Developer",
    "github": "example"
  },
  "url": ["youtube.com", "www.youtube.com"],
  "color": "#FF0033",
  "category": "streaming",
  "description": {
    "en-US": "Watch and share videos on YouTube."
  }
}

Author and Contributors

  • author - Main maintainer, displayed first in the library and OG images.
  • contributors - Additional people who helped with the presence.

GitHub usernames (the github key) are used to resolve avatars.

Descriptions and Features

  • description - Short marketplace copy, keyed by locale.
  • longDescription - Expanded description for detail pages.
  • features - Localized list of supported behavior (e.g., button support, media keys).

Discord native support

Some platforms already appear on Discord when the user links their account (Spotify is the usual example). Set this optional flag so the library can explain that Nowly is still useful without that link.

FieldTypeDescriptionDefault
discordNativebooleanTrue when Discord already shows this platform if the user links their account. Optional. Defaults to false.-
{
  "name": "Spotify",
  "discordNative": true
}

This only shows an info note on the library page and in the extension (store and installed presence details). It does not block install.

URL Matching

  • url - Supported domains or URL patterns for matching pages.
  • regExp - Regex-based matching for complex URL patterns.

Use regExp only when simple url matching is not enough. Prefer explicit domain lists.

Execution Context

Two optional fields control how and when your presence script runs in the browser.

FieldTypeDescriptionDefault
world"main" | "isolated"Execution world. Defaults to isolated.-
runAt"document_start" | "document_end" | "document_idle"When the script is injected. Defaults to document_idle.-
iframebooleanOpt in to building and injecting iframe.ts into nested frames.-
iFrameRegExpstringRegex matched against nested frame URLs. Required when iframe is true.-

By default a presence runs in the isolated world: it shares the page DOM but not the page's JavaScript context. This is the safe default and works for almost every presence.

Set "world": "main" when your presence needs the page context, specifically:

  • reading page globals (e.g. a player object the site exposes on window);
  • making a same-origin authenticated fetch that must carry the user's session cookies (e.g. a site's internal metadata API).
{
  "name": "Netflix",
  "url": ["netflix.com", "www.netflix.com"],
  "world": "main",
  "color": "#E50914",
  "category": "streaming",
  "description": {
    "en-US": "Watch movies and series on Netflix."
  }
}

A fetch from the isolated world is not treated as a first-party request, so authenticated calls fail silently. If your presence relies on the site's logged-in API, you must set "world": "main".

The declaration lives entirely in metadata.json - the extension reads it at registration time. No changes to the extension are needed to add a new page-context presence.

Nested frames

Set "iframe": true and add "iFrameRegExp" when the presence needs a separate iframe.ts script. The regular expression is evaluated against each nested frame URL. The main presence.ts receives data sent by the frame through presence.on("iFrameData", ...).

Category

Allowed categories are streaming, music, video, social, gaming, tools, ai, learning, creator, and other.