> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cskn.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# App settings

> Let owners control how your app appears on their profile, from inside your app.

These are the **owner's** settings for your app on their profile: what it is called there, whether it appears at all, who may open it, and removing it. They are not your app's internal preferences.

If you use @cskn/ui, drop in [`<AppSettings />`](/ui/settings-panels#appsettings). Otherwise `useAppSettings` gives you the same behavior to render in your own design.

```tsx theme={null}
import { useAppSettings } from '@cskn/sdk';

function VisibilitySettings() {
  const s = useAppSettings();

  return (
    <section>
      <input
        value={s.values.displayName}
        placeholder={s.app?.name}
        onChange={(e) => s.setDisplayName(e.target.value)}
      />
      <select value={s.values.visibility} onChange={(e) => s.setVisibility(e.target.value as any)}>
        <option value="public">Everyone</option>
        <option value="followers">Followers</option>
        <option value="private">Only people I choose</option>
      </select>
      {s.pageUrl && <a href={s.pageUrl}>{s.pageUrl}</a>}
      <button onClick={s.save} disabled={!s.isDirty || s.isSaving}>Save</button>
    </section>
  );
}
```

## Values

<ResponseField name="displayName" type="string">Name on the owner's page. Empty means the app's own name.</ResponseField>
<ResponseField name="description" type="string">The owner's description. Empty means the app's own.</ResponseField>
<ResponseField name="visibility" type="'public' | 'followers' | 'private'">Who may open the app on the owner's page.</ResponseField>
<ResponseField name="showInPortfolio" type="boolean">When `false`, the app and its widgets are hidden from the profile.</ResponseField>
<ResponseField name="allowComments" type="boolean">Whether visitors may comment.</ResponseField>
<ResponseField name="grantedUsers" type="string[]">User ids allowed in while `visibility` is `private`.</ResponseField>

## State

<ResponseField name="values / isDirty" type="AppSettingsValues / boolean">The owner's draft, and whether it has unsaved edits.</ResponseField>
<ResponseField name="app" type="{ name, description, icon } | null">Your app's own identity, for headings and placeholders.</ResponseField>
<ResponseField name="pageUrl" type="string | null">The app's address on the owner's page, `https://<username>.cskn.my/<slug>`.</ResponseField>
<ResponseField name="activated" type="boolean">`false` when the app is not on the owner's profile, in which case none of this applies.</ResponseField>
<ResponseField name="grantedUsers" type="GrantedUser[]">Profiles for `values.grantedUsers`, in order.</ResponseField>

## Actions

| Action | Notes |
| - | - |
| `setDisplayName`, `setDescription`, `setVisibility`, `setShowInPortfolio`, `setAllowComments` | Edit the draft. |
| `addGrantedUser(username)` | Looks the user up, then adds them to the draft. Resolves `'added'`, `'not-found'`, `'duplicate'` or `'failed'`. |
| `removeGrantedUser(userId)` | Removes from the draft. |
| `save()` | Sends **only the fields the owner changed**, so it never overwrites edits made elsewhere, or settings your screen does not show. `saveError` is `'not-activated'` or `'failed'`. |
| `deactivate()` | Removes the app from the profile. Resolves `true` on success. Only the store can add it back. |

Saving also refreshes the widget catalog and the profile's widgets, because visibility decides who sees them.

Lower level: `useAppSettingsQuery`, `getAppSettings`, `saveAppSettings`, `lookupUserByUsername`, `deactivateApp`, `APP_VISIBILITIES`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.