> Documentation index: [Saleor](/llms.txt) · [This section](/developer/llms.txt)
> Source: https://docs.saleor.io/developer/extending/apps/extending-dashboard-with-apps

# Extending Dashboard with Apps

<a id="key-concepts"></a>

## Key concepts

App extensions allow applications to alter the dashboard's interface by contributing custom buttons, menu items, screens, widgets, and modal overlays. It's a convenient way to add new features and capabilities without maintaining a custom dashboard application fork.

All contributed views are embedded inside an `<iframe>` to protect against XSS attacks.

warning

Saleor Dashboard design assumes apps can never impersonate native Saleor UI. It's expected that Dashboard will render additional labels like "Apps: ..." to ensure a user is aware this content is external.

<a id="relation-to-saleor-dashboard-and-custom-dashboard"></a>

## Relation to Saleor dashboard and custom Dashboard

While these API, just like any other Saleor APIs, can be used with a fully custom Dashboard, the API is mainly designed to be consumed by the official Saleor Dashboard.

This document contains assumptions of how the UI can handle such APIs

<a id="manifest"></a>

## Manifest

A single App can provide multiple extensions. You can add each extension by specifying it in the App's manifest. The example manifest below defines two extensions, one providing a custom product action that opens a modal overlay and the second one providing an alternative product creation page:

```json
{
  ...
  "extensions": [
      {
        "label": "Create with Sample app",
        "mount": "PRODUCT_DETAILS_MORE_ACTIONS",
        "target": "POPUP",
        "permissions": [
            "MANAGE_PRODUCTS"
        ],
        "url": "https://example.com/extension/"
      },
      {
        "label": "Create with App and redirect",
        "mount": "PRODUCT_OVERVIEW_CREATE",
        "target": "APP_PAGE",
        "permissions": [
            "MANAGE_PRODUCTS"
        ],
        "url": "/extension/redirect"
      }
    ]
}
```

-   `label`: The name which will be displayed in the dashboard.
-   `mount`: The place where the extension will be mounted.
-   `target`: The method of presenting the interface (defaults to `POPUP`). See `target` section below
-   `permissions`: An array of [permissions](/developer/permissions.md#app-permissions) required for a user to access the extension.
-   `url`: The URL of the view to display. You can skip the domain and protocol when `target` is set to `APP_PAGE`, or when your manifest defines an `appUrl`. When `target` is set to `POPUP`, the `url` will be used to render an `<iframe>`.
-   `options` depending on the target, additional properties to control the behavior.
-   `identifier` (optional, from 3.23.19): A stable, app-defined identifier used to reference a specific extension programmatically. See [Extension identifier](#extension-identifier).

<a id="extension-identifier"></a>

### Extension identifier

From Saleor 3.23.19, an extension can declare an optional `identifier` — a stable, app-defined string that lets other parts of your app reference that specific extension instead of relying on its label or position.

-   It must be **unique per app** (an app cannot reuse the same `identifier` for two of its extensions), but the same value may be used by different apps.
-   Blank or whitespace-only values are treated as not provided.
-   It is exposed on the [`AppExtension`](/api-reference/apps/objects/app-extension.md) GraphQL type via the `identifier` field.

The main use case is opening a `POPUP` extension from a `WIDGET` of the same app: the widget dispatches the [`OpenPopup` App Bridge action](/developer/extending/apps/developing-apps/app-sdk/app-bridge.md#opening-a-popup-extension) with `extensionIdentifier` set to the popup's `identifier`.

<a id="target-types"></a>

## Target types

App extensions provide four different types of targets, that control the behavior and rendering in the Dashboard. If target is not set, `POPUP` will be used as a default.

<a id="popup-target"></a>

### `POPUP` target

This target is meant to render an app iframe on the modal view. The provided `url` will be used to render app's page. This UI renders medium-sized frame

This target doesn't provide any `options`

<a id="app_page-target"></a>

### `APP_PAGE` target

The `APP_PAGE` target works as a redirection from the mount location to the `apps/` section in the Dashboard. This section renders the app in the biggest possible frame.

This target doesn't provide any `options`

<a id="new_tab-target-from-322"></a>

### `NEW_TAB` target (from 3.22)

The `NEW_TAB` target is meant to open the provided url in the new browser tab. This can be helpful, for example, to connect 3-rd party services with Dashboard.

There are following options available

```json
"options": {
  "newTabTarget": {
    "method": "GET" // or "POST"
  }
}
```

If not provided, the default value `GET` will be used by Dashboard.

-   `GET` will open the URL similar to user opening the link in the new tab. Dashboard will append query params: `saleorApiUrl` and context fields (see "Context" below)
-   `POST` will open the URL using POST method. This is similar to submitting the HTML form by the user. The `body` will contain following fields:
    -   `saleorApiUrl` - the URL of the saleor (starting with https, ending with `/graphql/`)
    -   `appId` - ID of the app object
    -   `accessToken` - short-living token that is intersection of app and logged user permissions
    -   context fields — see below

warning

`accessToken` is short-living and can't be refreshed outside the Dashboard. You can likely communicate with Saleor during the request, but do not try to pass it to the frontend.

To ensure seamless and safe user interaction with the UI, use App Page

<a id="widget-target-from-322"></a>

### `WIDGET` target (from 3.22)

The `WIDGET` target stands for statically mounted iframes in various places around the dashboard. It will mount the frame similar to `APP_PAGE` and `POPUP`, but usually much smaller.

On `*_DETAILS_WIDGETS` mounts (for example, the product details sidebar), widgets are stacked in a scrollable column. An app can report its content height via the `widgetResize` App Bridge action so each iframe grows or shrinks with the UI instead of staying in a fixed box — see [Sizing sidebar widgets](/developer/extending/apps/developing-apps/app-sdk/app-bridge.md#sizing-sidebar-widgets) (`@saleor/app-sdk` 1.9+).

Similar to `NEW_TAB` there are options allowing to choose the request method

```json
"options": {
  "widgetTarget": {
    "method": "GET" // or "POST"
  }
}
```

If not provided, `GET` is the default choice for Dashboard.

-   `GET` will open the URL similar to user opening the link in the new tab. Dashboard will append query params: `saleorApiUrl` and context fields (see "Context" below). Additional fields will be passed to the iframe, similar to `APP_PAGE` and `POPUP`, to help it render the UI (theme, feature flags, etc.)
-   `POST` will open the URL using POST method. This is similar to submitting the HTML form by the user. The `body` will contain the following fields:
-   `saleorApiUrl` - the URL of the saleor (starting with https, ending with `/graphql/`)
-   `appId` - ID of the app object
-   `accessToken` - short-living token that is intersection of app and logged user permissions. This token will be refreshed by the Dashboard in the background.
-   context fields — see below

<a id="home-page-widgets-from-323"></a>

#### Home page widgets (from 3.23)

The `HOMEPAGE_WIDGETS` mount lets apps render widgets directly on the Dashboard home page. It uses the `WIDGET` target, but instead of `widgetTarget` it is configured with the `homeWidgetTarget` option:

```json
"options": {
  "homeWidgetTarget": {
    "method": "GET", // or "POST"
    "fullscreen": false
  }
}
```

-   `method` works the same as for other widgets. If not provided, `GET` is the default choice for Dashboard.
-   `fullscreen` controls how the widget is laid out on the home page. When `false` (the default), the widget is rendered inside the home page grid alongside other widgets. When `true`, the widget takes the full available width.

Requires Dashboard 3.23.12+ and `@saleor/app-sdk` 1.10+.

<a id="command-palette-actions-from-32321"></a>

## Command palette actions (from 3.23.21)

The `SEARCH_ACTION` mount surfaces an app action in the Dashboard command palette (`Cmd+K` / `Ctrl+K`), so users can run it by typing instead of hunting for a button.

It supports the `POPUP`, `APP_PAGE` and `NEW_TAB` targets (not `WIDGET`). When the action is run from an entity page, the app receives that entity's context — the same context the entity's "more actions" extensions get.

```json
{
  "label": "Recalculate taxes",
  "mount": "SEARCH_ACTION",
  "target": "POPUP",
  "permissions": ["MANAGE_ORDERS"],
  "url": "/actions/recalculate-taxes",
  "options": {
    "views": ["ORDER_DETAILS", "ORDER_LIST"],
    "aliases": ["taxes", "avatax"]
  }
}
```

<a id="optionsviews"></a>

### `options.views`

Scopes the action to specific Dashboard views. When omitted, the action is available everywhere. When provided, the list must contain at least one view.

Detail views resolve a single entity id as context; list views are surfaced without an id.

Available views: `PRODUCT_LIST`, `PRODUCT_DETAILS`, `ORDER_LIST`, `ORDER_DETAILS`, `DRAFT_ORDER_LIST`, `DRAFT_ORDER_DETAILS`, `CUSTOMER_LIST`, `CUSTOMER_DETAILS`, `COLLECTION_LIST`, `COLLECTION_DETAILS`, `CATEGORY_LIST`, `CATEGORY_DETAILS`, `GIFT_CARD_LIST`, `GIFT_CARD_DETAILS`, `VOUCHER_LIST`, `VOUCHER_DETAILS`, `DISCOUNT_LIST`, `DISCOUNT_DETAILS`, `PAGE_LIST`, `PAGE_DETAILS`, `PAGE_TYPE_LIST`, `PAGE_TYPE_DETAILS`, `MENU_LIST`, `MENU_DETAILS`, `CHANNEL_DETAILS`.

`CHANNEL_DETAILS` requires Dashboard 3.23.28+; the extension is then opened with `channelId` holding the channel's global id.

<a id="optionsaliases"></a>

### `options.aliases`

Extra terms the command palette matches the action against, for example `["taxes", "avatax"]`. They are searchable but never displayed, which lets users find an action by the vendor or domain name instead of its exact label.

Requires Dashboard 3.23.28+.

info

Manifest typings for `SEARCH_ACTION` are available in `@saleor/app-sdk` 1.13+ (`options.aliases` in 1.14+, `CHANNEL_DETAILS` in 1.15+).

<a id="context"></a>

## Context

Context fields are specific to the mount extension is being attached to. For example, on `CATEGORY_DETAILS_MORE_ACTIONS`, the context field will be `categoryId`.

Context fields can be a `string`, usually an ID of the Saleor object, or a list of strings, usually when multiple Saleor items are selected by the user.

For example

-   Order details page context will be `{orderId: "AABBCC"}`
-   Product list page context will be `{productIds: ["XXYYZZ", "BBCCDD"]}`

Dashboard will provide contextual values depending on the mounting point. In the future more data can be passed to the context.

<a id="context-in-get-operations"></a>

### Context in GET operations

`GET` type operations, like rendering WIDGET using `options.widget.method: "GET"`, or `POPUP` will provide context fields as query params in URL. Other data like `theme` or feature flags will be also provided.

You can access all the fields with JavaScript, like this:

```javascript
const searchParams = new URLSearchParams(window.location.search);

console.log(
    Array.from(searchParams.entries())
)
```

<a id="context-in-post-operations"></a>

### Context in POST operations

`POST` type operations like target `WIDGET` or `NEW_TAB` with `POST` method, will provide context values within request body.

Since requests origin from the browser, they will be type of a form data. Your backend framework should provide a way to parse it.

warning

Contrary to JSON, form data can have duplicated keys. For example:

```text
["productIds", "product-1"],
["productIds", "product-2"],
```

Your backend body parser should be able to merge such fields

<a id="possible-mounting-places"></a>

## Possible mounting places

Saleor requires extensions to define a mounting place. The table below explains all mounting locations currently supported by Saleor.

| Mount | Description | Supported targets | Available from |
| --- | --- | --- | --- |
| HOMEPAGE\_WIDGETS | A widget on the Dashboard home page. | `WIDGET` | 3.23 |
| SEARCH\_ACTION | Dashboard command palette (`Cmd+K`). See [Command palette actions](#command-palette-actions-from-32321). | `POPUP`, `APP_PAGE`, `NEW_TAB` | 3.23.21 |
| CATEGORY\_OVERVIEW\_CREATE | Category's list page under the create button. | `POPUP`, `APP_PAGE`, `NEW_TAB` | 3.22 |
| CATEGORY\_OVERVIEW\_MORE\_ACTIONS | Category's list page under the more action button. | `POPUP`, `APP_PAGE`, `NEW_TAB` | 3.22 |
| CATEGORY\_DETAILS\_MORE\_ACTIONS | Category's detail page under the more action button. | `POPUP`, `APP_PAGE`, `NEW_TAB` | 3.22 |
| COLLECTION\_OVERVIEW\_CREATE | Collection's list page under the create button. | `POPUP`, `APP_PAGE`, `NEW_TAB` | 3.22 |
| COLLECTION\_OVERVIEW\_MORE\_ACTIONS | Collection's list page under the more action button. | `POPUP`, `APP_PAGE`, `NEW_TAB` | 3.22 |
| COLLECTION\_DETAILS\_MORE\_ACTIONS | Collection's detail page under the more action button. | `POPUP`, `APP_PAGE`, `NEW_TAB` | 3.22 |
| COLLECTION\_DETAILS\_WIDGETS | A widget on collection's detail page. | `POPUP`, `APP_PAGE`, `NEW_TAB`, `WIDGET` | 3.22 |
| GIFT\_CARD\_OVERVIEW\_CREATE | gift card's list page under the create button. | `POPUP`, `APP_PAGE`, `NEW_TAB` | 3.22 |
| GIFT\_CARD\_OVERVIEW\_MORE\_ACTIONS | gift card's list page under the more action button. | `POPUP`, `APP_PAGE`, `NEW_TAB` | 3.22 |
| GIFT\_CARD\_DETAILS\_MORE\_ACTIONS | gift card's detail page under the more action button. | `POPUP`, `APP_PAGE`, `NEW_TAB` | 3.22 |
| GIFT\_CARD\_DETAILS\_WIDGETS | A widget on gift card's detail page. | `POPUP`, `APP_PAGE`, `NEW_TAB`, `WIDGET` | 3.22 |
| CUSTOMER\_OVERVIEW\_CREATE | customer's list page under the create button. | `POPUP`, `APP_PAGE`, `NEW_TAB` |  |
| CUSTOMER\_OVERVIEW\_MORE\_ACTIONS | customer's list page under the more action button. | `POPUP`, `APP_PAGE`, `NEW_TAB` |  |
| CUSTOMER\_DETAILS\_MORE\_ACTIONS | customer's detail page under the more action button. | `POPUP`, `APP_PAGE`, `NEW_TAB` |  |
| CUSTOMER\_DETAILS\_WIDGETS | A widget on customer's detail page. | `POPUP`, `APP_PAGE`, `NEW_TAB`, `WIDGET` | 3.22 |
| PRODUCT\_OVERVIEW\_CREATE | Product's list page under the create button. | `POPUP`, `APP_PAGE`, `NEW_TAB` |  |
| PRODUCT\_OVERVIEW\_MORE\_ACTIONS | Product's list page under the more action button. | `POPUP`, `APP_PAGE`, `NEW_TAB` |  |
| PRODUCT\_DETAILS\_MORE\_ACTIONS | Product's detail page under the more action button. | `POPUP`, `APP_PAGE`, `NEW_TAB` |  |
| PRODUCT\_DETAILS\_WIDGETS | A widget on product's detail page. | `POPUP`, `APP_PAGE`, `NEW_TAB`, `WIDGET` | 3.22 |
| NAVIGATION\_CATALOG | Catalogs section in the navigation bar. | `POPUP`, `APP_PAGE`, `NEW_TAB` |  |
| NAVIGATION\_ORDERS | Orders section in the navigation bar. | `POPUP`, `APP_PAGE`, `NEW_TAB` |  |
| NAVIGATION\_CUSTOMERS | Customers section in the navigation bar. | `POPUP`, `APP_PAGE`, `NEW_TAB` |  |
| NAVIGATION\_DISCOUNTS | Discounts section in the navigation bar. | `POPUP`, `APP_PAGE`, `NEW_TAB` |  |
| NAVIGATION\_TRANSLATIONS | Translations section in the navigation bar. | `POPUP`, `APP_PAGE`, `NEW_TAB` |  |
| NAVIGATION\_PAGES | Models section in the navigation bar. | `POPUP`, `APP_PAGE`, `NEW_TAB` |  |
| ORDER\_DETAILS\_MORE\_ACTIONS | Order's detail page under the more action button. | `POPUP`, `APP_PAGE`, `NEW_TAB` |  |
| ORDER\_OVERVIEW\_CREATE | Order's list page under the create button. | `POPUP`, `APP_PAGE`, `NEW_TAB` |  |
| ORDER\_OVERVIEW\_MORE\_ACTIONS | Order's list page under the more action button. | `POPUP`, `APP_PAGE`, `NEW_TAB` |  |
| ORDER\_DETAILS\_WIDGETS | A widget on order's detail page. | `POPUP`, `APP_PAGE`, `NEW_TAB`, `WIDGET` | 3.22 |
| DRAFT\_ORDER\_DETAILS\_MORE\_ACTIONS | Draft order's detail page under the more action button. | `POPUP`, `APP_PAGE`, `NEW_TAB` | 3.22 |
| DRAFT\_ORDER\_OVERVIEW\_CREATE | Draft order's list page under the create button. | `POPUP`, `APP_PAGE`, `NEW_TAB` | 3.22 |
| DRAFT\_ORDER\_OVERVIEW\_MORE\_ACTIONS | Draft order's list page under the more action button. | `POPUP`, `APP_PAGE`, `NEW_TAB` | 3.22 |
| DRAFT\_ORDER\_DETAILS\_WIDGETS | A widget on draft order's detail page. | `POPUP`, `APP_PAGE`, `NEW_TAB`, `WIDGET` | 3.22 |
| DISCOUNT\_DETAILS\_MORE\_ACTIONS | Discount's detail page under the more action button. | `POPUP`, `APP_PAGE`, `NEW_TAB` | 3.22 |
| DISCOUNT\_OVERVIEW\_CREATE | Discount's list page under the create button. | `POPUP`, `APP_PAGE`, `NEW_TAB` | 3.22 |
| DISCOUNT\_OVERVIEW\_MORE\_ACTIONS | Discount's list page under the more action button. | `POPUP`, `APP_PAGE`, `NEW_TAB` | 3.22 |
| VOUCHER\_DETAILS\_MORE\_ACTIONS | Voucher's detail page under the more action button. | `POPUP`, `APP_PAGE`, `NEW_TAB` | 3.22 |
| VOUCHER\_OVERVIEW\_CREATE | Voucher's list page under the create button. | `POPUP`, `APP_PAGE`, `NEW_TAB` | 3.22 |
| VOUCHER\_OVERVIEW\_MORE\_ACTIONS | Voucher's list page under the more action button. | `POPUP`, `APP_PAGE`, `NEW_TAB` | 3.22 |
| VOUCHER\_DETAILS\_WIDGETS | A widget on voucher's detail page. | `POPUP`, `APP_PAGE`, `NEW_TAB` , `WIDGET` | 3.22 |
| PAGE\_DETAILS\_MORE\_ACTIONS | Page's detail page under the more action button. | `POPUP`, `APP_PAGE`, `NEW_TAB` | 3.22 |
| PAGE\_OVERVIEW\_CREATE | Page's list page under the create button. | `POPUP`, `APP_PAGE`, `NEW_TAB` | 3.22 |
| PAGE\_OVERVIEW\_MORE\_ACTIONS | Page's list page under the more action button. | `POPUP`, `APP_PAGE`, `NEW_TAB` | 3.22 |
| PAGE\_TYPE\_OVERVIEW\_CREATE | Page type's list page under the create button. | `POPUP`, `APP_PAGE`, `NEW_TAB` | 3.22 |
| PAGE\_TYPE\_OVERVIEW\_MORE\_ACTIONS | Page type's list page under the more action button. | `POPUP`, `APP_PAGE`, `NEW_TAB` | 3.22 |
| PAGE\_TYPE\_DETAILS\_MORE\_ACTIONS | Page type's detail page under the more action button. | `POPUP`, `APP_PAGE`, `NEW_TAB` | 3.22 |
| MENU\_OVERVIEW\_CREATE | Structure's list page under the create button. | `POPUP`, `APP_PAGE`, `NEW_TAB` | 3.22 |
| MENU\_OVERVIEW\_MORE\_ACTIONS | Structure's list page under the more action button. | `POPUP`, `APP_PAGE`, `NEW_TAB` | 3.22 |
| MENU\_DETAILS\_MORE\_ACTIONS | Structure's detail page under the more action button. | `POPUP`, `APP_PAGE`, `NEW_TAB` | 3.22 |

<a id="more-resources"></a>

## More resources

-   [app-template](https://github.com/saleor/saleor-app-template): minimal starter boilerplate, containing extensions example implementation
