GhostySDK Reference

The GhostySDK is a JavaScript API automatically injected into every plugin's runtime by the Ghosty host application. It provides structured access to storage, user context, notifications, navigation, and permission management.

You access the SDK through the global ghosty object, which is available as soon as the onInit lifecycle hook fires.

import { ghosty } from "@ghosty/sdk";
 
// All SDK methods are available after onInit
ghosty.storage.get("key");
ghosty.user.displayName;
ghosty.notifications.toast("Hello!");
TypeScript types

Install @ghosty/sdk as a dev dependency to get full TypeScript types and autocomplete. The package contains type declarations only; the actual runtime is injected by the host.

ghosty.storage

The storage API provides a persistent key-value store scoped to your plugin. Data persists across sessions and device syncs if the user has sync enabled.

Required permissions: storage.read, storage.write, storage.watch (depending on the method).

GETghosty.storage.get(key)

Retrieve a value by key. Returns null if the key does not exist.

Parameters

NameTypeRequiredDescription
keystringYesThe storage key to retrieve.
POSTghosty.storage.set(key, value)

Store a value under the given key. Overwrites any existing value.

Parameters

NameTypeRequiredDescription
keystringYesThe storage key.
valuestring | number | boolean | objectYesThe value to store. Objects are serialised as JSON. Max 64 KB.
DELETEghosty.storage.delete(key)

Remove a key and its value from storage.

Parameters

NameTypeRequiredDescription
keystringYesThe storage key to delete.
GETghosty.storage.keys()

List all keys currently in storage. Returns an array of strings.

POSTghosty.storage.watch(key, callback)

Subscribe to changes on a specific key. The callback fires whenever the value is updated or deleted, including from other devices.

Parameters

NameTypeRequiredDescription
keystringYesThe key to watch.
callback(value: unknown) => voidYesCalled with the new value on change. Receives null on deletion.

Storage example

import { ghosty } from "@ghosty/sdk";
 
// Save user preference
await ghosty.storage.set("theme", "dark");
 
// Read it back
const theme = await ghosty.storage.get("theme");
console.log(theme); // "dark"
 
// Watch for changes from other devices
ghosty.storage.watch("theme", (newValue) => {
  applyTheme(newValue as string);
});
 
// List all keys
const allKeys = await ghosty.storage.keys();
console.log(allKeys); // ["theme"]
 
// Clean up
await ghosty.storage.delete("theme");

ghosty.user

The user API provides read-only access to the currently signed-in user's profile and preferences. All fields are populated after onInit completes.

Required permissions: user.profile, user.preferences, user.id (depending on the property).

PropertyTypePermissionDescription
displayNamestring | nulluser.profileThe user's chosen display name.
avatarUrlstring | nulluser.profileURL of the user's avatar image.
localestringuser.preferencesBCP 47 locale string (e.g. en-US).
timezonestringuser.preferencesIANA timezone (e.g. America/New_York).
theme"light" | "dark" | "system"user.preferencesCurrent theme preference.
idstringuser.idAnonymous unique identifier.

User example

import { ghosty } from "@ghosty/sdk";
 
function renderGreeting(container: HTMLElement): void {
  const name = ghosty.user.displayName ?? "there";
  const hour = new Date().getHours();
  let greeting = "Good evening";
  if (hour < 12) greeting = "Good morning";
  else if (hour < 18) greeting = "Good afternoon";
 
  container.innerHTML = `<h2>${greeting}, ${name}!</h2>`;
}

ghosty.notifications

The notifications API lets your plugin display toast messages inside the Ghosty app and, with additional permissions, send OS-level system notifications.

Required permissions: notifications.show, notifications.system, notifications.badge.

POSTghosty.notifications.toast(message, options?)

Display an in-app toast notification. Toasts auto-dismiss after the configured duration.

Parameters

NameTypeRequiredDescription
messagestringYesThe notification text. Max 200 characters.
options.durationnumberNoDuration in milliseconds before auto-dismiss. Default: 4000.
options.variant'info' | 'success' | 'warning' | 'error'NoVisual style. Default: 'info'.
options.action{ label: string; onClick: () => void }NoOptional action button.
POSTghosty.notifications.system(title, body, options?)

Send an OS-level system notification. Requires the notifications.system permission.

Parameters

NameTypeRequiredDescription
titlestringYesNotification title. Max 100 characters.
bodystringYesNotification body. Max 300 characters.
options.iconstringNoURL to a custom notification icon.
POSTghosty.notifications.setBadge(count)

Set the badge count displayed on the plugin's icon. Set to 0 to clear.

Parameters

NameTypeRequiredDescription
countnumberYesBadge count. Must be a non-negative integer.

Notifications example

import { ghosty } from "@ghosty/sdk";
 
// Simple toast
ghosty.notifications.toast("Settings saved successfully!", {
  variant: "success",
  duration: 3000,
});
 
// Toast with action button
ghosty.notifications.toast("New update available", {
  variant: "info",
  action: {
    label: "View",
    onClick: () => ghosty.navigate.fullscreen(),
  },
});
 
// System notification (requires notifications.system permission)
await ghosty.notifications.system(
  "Task Due",
  "Your task 'Review PR #42' is due in 30 minutes.",
);
 
// Badge count
ghosty.notifications.setBadge(3);

ghosty.navigate

The navigation API controls transitions between views and opens external URLs.

Required permissions: navigation.open_url, navigation.deep_link, navigation.fullscreen.

POSTghosty.navigate.openUrl(url)

Open a URL in the user's default browser. Must be an HTTPS URL.

Parameters

NameTypeRequiredDescription
urlstringYesThe HTTPS URL to open.
POSTghosty.navigate.fullscreen()

Transition from widget view to fullscreen view. Only available for plugins that declare a fullscreen view.

POSTghosty.navigate.widget()

Return from fullscreen view to the dashboard (widget view).

POSTghosty.navigate.deepLink(target)

Navigate to another plugin or built-in Ghosty screen.

Parameters

NameTypeRequiredDescription
targetstringYesDeep link URI (e.g. 'ghosty://plugin/weather-widget' or 'ghosty://settings').

ghosty.permissions

The permissions API allows runtime permission checks and dynamic permission requests.

GETghosty.permissions.has(permission)

Check whether a specific permission has been granted. Returns a boolean.

Parameters

NameTypeRequiredDescription
permissionstringYesThe permission key (e.g. 'storage.read').
POSTghosty.permissions.request(permissions)

Prompt the user to grant additional permissions. Returns true if all were granted.

Parameters

NameTypeRequiredDescription
permissionsstring[]YesArray of permission keys to request.
Progressive permission requests

Use ghosty.permissions.request() for features that need extra permissions. This way, users only see the permission prompt when they actively engage with the feature, resulting in higher grant rates.

Error handling

All async SDK methods can throw the following error types:

ErrorDescription
PermissionDeniedErrorThe required permission has not been granted or was revoked.
StorageQuotaExceededErrorThe plugin has exceeded its storage limits.
NetworkErrorAn outbound request failed (timeout, DNS, or domain not in allowlist).
SandboxErrorA sandbox policy violation occurred (e.g. CSP blocked an inline script).
TimeoutErrorA lifecycle hook or SDK call exceeded the configured timeout.

Always use try/catch and provide meaningful fallback behaviour:

import { ghosty, PermissionDeniedError, StorageQuotaExceededError } from "@ghosty/sdk";
 
try {
  await ghosty.storage.set("large-data", payload);
} catch (error) {
  if (error instanceof StorageQuotaExceededError) {
    ghosty.notifications.toast("Storage full. Please delete unused data.", {
      variant: "warning",
    });
  } else if (error instanceof PermissionDeniedError) {
    ghosty.notifications.toast("Storage access denied.", { variant: "error" });
  } else {
    throw error;
  }
}