Skip to content

Permissions

A bundle declares every capability it wants in the permissions list in its manifest. Nothing outside that list is available at runtime. The user sees the list and the reasons at install time and must approve it before the bundle runs.

Shape of a permission

jsonc
{
  "scope": "sdk.audio",
  "reason": "Visualizes sound with an FFT",
  "value": "https://api.example.com/*"
}
FieldRequiredDescription
scopeyesThe capability. Either an SDK namespace (sdk.<name>) or a network family (network.http, network.ws, network.font).
reasonyesA short explanation shown to the user next to the capability. Must not be empty.
valueonly for network.*A host or URL pattern to allow. Required for network scopes, ignored for sdk.* scopes.

SDK scopes

Each sdk.* scope unlocks one namespace on window.DesktopOverlaysAPI. If you do not request a scope, that namespace is undefined in your code. This means the capability surface of your bundle is derived from your manifest.

ScopeUnlocksWhat it gives you
sdk.audioDesktopOverlaysAPI.audioSystem audio FFT frames for visualizers.
sdk.mediaDesktopOverlaysAPI.mediaThe Windows now-playing track info and album art.
sdk.windowsDesktopOverlaysAPI.windowsThe list of open windows and the desktop state.
sdk.appDesktopOverlaysAPI.appThe current foreground app, fullscreen, display, and desktop state.
sdk.notificationsDesktopOverlaysAPI.notificationsThe Windows notifications from the Action Center.
sdk.sizeDesktopOverlaysAPI.sizeRead and set the overlay size.
sdk.optionsDesktopOverlaysAPI.optionsRead the user's option values and react to changes.
sdk.contentDesktopOverlaysAPI.contentSend messages between the bundle's own surfaces.

The options panel works whether or not you request sdk.options. The scope only controls whether your code can read the values through the SDK. See the API reference for the full method list of each namespace.

Network scopes

Network scopes allow your bundle to reach a remote host. Each entry allows one host or URL pattern, given in value. Wildcards are supported. You can list more than one entry of the same family, and they are combined.

ScopeUse it for
network.httpfetch and XMLHttpRequest calls to an HTTP(S) host.
network.wsWebSocket connections.
network.fontLoading a web font, for example from Google Fonts.

Example, allowing a lyrics API and Google Fonts:

jsonc
"permissions": [
  { "scope": "network.http", "value": "https://lrclib.net/*",            "reason": "Fetches synced lyrics" },
  { "scope": "network.font", "value": "https://fonts.googleapis.com/*",  "reason": "Loads the font stylesheet" },
  { "scope": "network.font", "value": "https://fonts.gstatic.com/*",     "reason": "Loads the font files" }
]

Your bundle's own files are always reachable and do not need a network permission. Network scopes are only for remote origins. For more on how requests are allowed or blocked, see Assets and networking.

Before a bundle is installed, whether from the Steam Workshop or any other source, the app parses permissions and shows the user a consent screen. Each row lists:

  • A human-readable label for the capability, written by the app, such as "System audio", "Open windows", or "Network: api.example.com".
  • The reason you wrote in the manifest.
  • For network scopes, the host from value.

If the user approves, the install continues. If they decline, nothing is installed. The set of permissions the user approved is stored with the bundle, and that approved set, not the manifest, is what the runtime enforces. If a later update changes the manifest to request new capabilities, the consent screen is shown again before the update applies.

A note on reasons

The reason text is yours, and the app cannot verify that it is accurate. To keep the user informed regardless, the app always shows its own label for the real capability next to your reason. Write honest reasons. A misleading reason still shows the true capability label, so it only costs you trust.