---
title: Sidekick API
description: >-
  Use the Sidekick API to start a Sidekick conversation for the merchant with a
  prompt your app provides.
api_version: v2.0
source_url:
  html: >-
    https://shopify.dev/docs/api/app-home/latest/apis/user-interface-and-interactions/sidekick-api
  md: >-
    https://shopify.dev/docs/api/app-home/latest/apis/user-interface-and-interactions/sidekick-api.md
api_name: app-home
---

# Sidekick API

**Info:**

App Bridge isn't versioned with Polaris. App Bridge APIs and web components are identical in every App Home reference version.

Use the Sidekick API in embedded apps in the Shopify admin to start a Sidekick conversation for the merchant with a prompt your app provides. Call `shopify.sidekick.launch()` to open the Sidekick panel and send the prompt as the merchant's message.

You can also check whether Sidekick is available, open the panel without sending a prompt, and listen for panel visibility changes.

### Use cases

* **Ask Sidekick from a report**: Add an **Ask Sidekick** button next to a report so the merchant can ask Sidekick to summarize or explain the data shown in your app.
* **Setup help**: Start a conversation that helps the merchant with a step in your app's setup flow.
* **In-app explanations**: Help merchants understand campaign performance, churn, or other data shown in your app.

### Methods

| Method | Type | Description |
| - | - | - |
| `launch` | `LaunchFunction` | Opens Sidekick and sends a message as the merchant's prompt. |
| `isEnabled` | `IsEnabledFunction` | Checks whether Sidekick is available to the app on this store. |
| `isOpen` | `IsOpenFunction` | Checks whether the Sidekick panel is open. |
| `open` | `OpenFunction` | Opens the Sidekick panel without sending a prompt. |

There is no `close` method. Closing Sidekick is the merchant's decision.

#### `LaunchFunction`

| Parameter | Type | Description |
| - | - | - |
| `request` | `{message: string} \| string` | The prompt to send to Sidekick as the merchant's message. A string is shorthand for `{message}`. |

**Returns:** `Promise<{id: string}>`. Resolves with the new conversation ID.

The `message` field is required, must be non-empty after trimming, and can be at most 5,500 characters. Leading and trailing whitespace is trimmed. `launch` ignores any other field, and doesn't treat it as an error. Hidden context or instructions, scenario, conversation IDs, and features aren't supported.

#### `IsEnabledFunction`

Checks whether Sidekick is available to the app on this store.

**Returns:** `Promise<boolean>`

If the API isn't available, then `shopify.sidekick` methods reject. The `shopify.sidekick` object can still exist on the global, so feature-detect by calling `isEnabled()` and treating a rejection as unavailable:

```js
const available = await shopify.sidekick?.isEnabled().catch(() => false);
```

Always check `isEnabled()` before you show a launch entry point or call any other method, and render the entry point only when it resolves `true`. The API isn't available in the Shopify mobile app yet, or on stores where Sidekick isn't available.

#### `IsOpenFunction`

Checks whether the Sidekick panel is open.

**Returns:** `Promise<boolean>`

#### `OpenFunction`

Opens the Sidekick panel without sending a prompt.

**Returns:** `Promise<void>`

### Events

App Bridge dispatches `shopify:sidekick:visibilitychange` on `window` when the Sidekick panel opens or closes.

| Property | Type | Description |
| - | - | - |
| `event.detail.visibilityState` | `'visible' \| 'hidden'` | Whether the Sidekick panel is open or hidden. |

### Requirements and availability

The Sidekick API is available to apps embedded in the web Shopify admin that load App Bridge from `https://cdn.shopify.com/shopifycloud/app-bridge.js`. The API isn't available inside the Shopify mobile app or when Sidekick isn't available on the store.

The `@shopify/app-bridge-types` package doesn't include `shopify.sidekick` yet.

A launched conversation can use only your app's tools from its [Sidekick app extensions](https://shopify.dev/docs/apps/build/sidekick), not other apps' tools. Prompts that ask to act across several apps or move data into another app are refused. If the merchant has turned your app off in Sidekick, then Shopify rejects `launch`.

### Prompt guidelines

Before Shopify sends anything, Shopify screens the prompt. The check fails closed. If screening can't complete, then Shopify rejects the launch. The screening step adds latency, so `launch` is slower than typing into Sidekick. Shopify rate limits launches for each merchant, for each app, and across apps. Call `launch` in response to a merchant action, such as a button click. Don't call `launch` on page load or on a timer.

Allowed prompts include questions, reads, searches, summaries, explanations, drafts, content fixes on named resources, and changes inside your own app. Content fixes can include titles, descriptions, SEO fields, alt text, tags, metafields, and translations on specific products, collections, pages, or blog posts.

Shopify refuses prompts that:

* Are harmful or contain a URL or link.
* Try to steer Sidekick, such as asking it to ignore rules, prefer your app, hide things from the merchant, claim the merchant already approved something, or impersonate Shopify or Sidekick.
* Try to harvest store, customer, or financial data for the app.
* Ask for a risky store change, such as deleting or bulk-editing resources, moving money or changing prices, acting on orders, changing permissions, publishing themes or domains, changing settings, or sending marketing.
* Ask to act across several apps or move data into another app.

Sidekick shows the merchant that the conversation was started by your app. Sidekick never applies a store change from a launched prompt on its own. It proposes the change and only makes it after the merchant asks in their own message.

### Errors

Shopify throws the following errors before sending anything. Each `Error.message` starts with `sidekick.launch:`.

| Error message | Cause |
| - | - |
| `sidekick.launch: message is required and must be a non-empty string.` | No usable `message`. |
| `sidekick.launch: message must be at most 5500 characters.` | The prompt is too long. |
| `sidekick.launch: the calling app could not be identified.` | Shopify couldn't identify the calling app. |
| `sidekick.launch: the calling app is turned off in Sidekick.` | The merchant turned your app off in Sidekick. |
| `sidekick.launch: whether the calling app is turned on in Sidekick could not be determined.` | Shopify couldn't read the merchant's Sidekick app settings. Try again later. |
| `sidekick.launch: message was rejected.` | The prompt didn't pass screening. The reason isn't disclosed. |
| `sidekick.launch: the prompt safety check could not be completed.` | Screening errored or was rate limited. |
| `sidekick.launch: Sidekick is unavailable for maintenance.` | Sidekick is in maintenance. |

Errors without the `sidekick.launch:` prefix happen after screening, while Shopify creates or sends the conversation. Shopify might already have sent the prompt, so don't retry those errors automatically.

### Examples

* #### Launch a conversation

  ##### Description

  Launch a Sidekick conversation from a merchant action. The button only appears when \`isEnabled()\` resolves \`true\`. Shopify sends the prompt as the merchant's message, and the Sidekick panel opens.

  ##### js

  ```js
  const button = document.getElementById('ask-sidekick');
  const available = await shopify.sidekick?.isEnabled().catch(() => false);

  button.hidden = !available;

  if (available) {
    button.addEventListener('click', async () => {
      const conversation = await shopify.sidekick.launch({
        message: 'Summarize my subscription churn for last month',
      });

      console.log('Started Sidekick conversation', conversation.id);
    });
  }
  ```

* #### Check availability

  ##### Description

  Check whether Sidekick is available before showing your launch entry point. Treat a rejected \`isEnabled()\` call as unavailable.

  ##### js

  ```js
  const button = document.getElementById('ask-sidekick');
  const available = await shopify.sidekick?.isEnabled().catch(() => false);

  button.hidden = !available;

  if (available) {
    button.addEventListener('click', () => {
      shopify.sidekick.launch(
        'Which of my email campaigns performed best last month?',
      );
    });
  }
  ```

* #### Handle rejections

  ##### Description

  Handle launch rejections after checking \`isEnabled()\`. Errors that start with \`sidekick.launch:\` happen before Shopify sends anything.

  ##### js

  ```js
  const button = document.getElementById('ask-sidekick');
  const available = await shopify.sidekick?.isEnabled().catch(() => false);

  button.hidden = !available;

  if (available) {
    button.addEventListener('click', async () => {
      try {
        await shopify.sidekick.launch({
          message: 'Summarize my subscription churn for last month',
        });
      } catch (error) {
        const message = error instanceof Error ? error.message : String(error);

        if (message.startsWith('sidekick.launch:')) {
          shopify.toast.show(message, {isError: true});
          return;
        }

        shopify.toast.show('Sidekick could not start the conversation.', {
          isError: true,
        });
      }
    });
  }
  ```

* #### Open Sidekick and listen for visibility changes

  ##### Description

  Check \`isEnabled()\`, then open the Sidekick panel without sending a prompt and listen for \`shopify:sidekick:visibilitychange\` events.

  ##### js

  ```js
  const button = document.getElementById('open-sidekick');
  const status = document.getElementById('sidekick-status');
  const available = await shopify.sidekick?.isEnabled().catch(() => false);

  button.hidden = !available;

  if (available) {
    window.addEventListener('shopify:sidekick:visibilitychange', (event) => {
      status.textContent =
        event.detail.visibilityState === 'visible'
          ? 'Sidekick is open'
          : 'Sidekick is hidden';
    });

    button.addEventListener('click', async () => {
      await shopify.sidekick.open();
    });
  }
  ```

* #### Use Sidekick with React

  ##### Description

  Use \`useAppBridge\` to render a button when Sidekick is available.

  ##### jsx

  ```jsx
  import {useEffect, useState} from 'react';
  import {useAppBridge} from '@shopify/app-bridge-react';

  export function AskSidekickButton() {
    const shopify = useAppBridge();
    const [available, setAvailable] = useState(false);

    useEffect(() => {
      let mounted = true;

      shopify.sidekick?.isEnabled()
        .then((enabled) => {
          if (mounted) setAvailable(enabled);
        })
        .catch(() => {
          if (mounted) setAvailable(false);
        });

      return () => {
        mounted = false;
      };
    }, [shopify]);

    if (!available) return null;

    return (
      <button
        onClick={() =>
          shopify.sidekick.launch(
            'Which of my email campaigns performed best last month?',
          )
        }
      >
        Ask Sidekick
      </button>
    );
  }
  ```

***
