Tutorial | Set Up an App With the CLI

This tutorial demonstrates how to use the Wix CLI to build an app named Business Buddy. The app creates a chatbot connected to an AI that appears on a site owner’s dashboard. The AI answers questions about products in the site's store.

The app is built from:

  • A front end consisting of two dashboard pages:
    • Products: A page that allows the site owner to select a product from the site's store and chat with the AI about it.
    • Settings: A page that allows the site owner to give instructions as to how the AI behaves.
  • A backend consisting of the following:
    • Server: An Express/Node.js server that responds to product chat requests by calling the OpenAI API and to settings requests by calling the mock database.
    • Database: A mock database that holds the AI behavior settings for users.

The app demonstrates how to:

  • Build dashboard pages using the Wix Design System, the Wix Dashboard SDK, and CSS.
  • Work with apps built by Wix such as Stores using the Wix Javascript SDK.
  • Work with external services, such as OpenAI.
  • Work with CORS on a server.
  • Authenticate and handle requests sent from the Wix dashboard to a server.

Project steps

We'll use the following steps to build the Business Buddy app:

  1. Initialize the app.
  2. Create the dashboard pages.
  3. Run a local development server.
  4. Install dependencies.
  5. Design the Products page.
  6. Set up calls to Wix SDKs.
  7. Set up communication with the backend.
  8. Design the Settings page.
  9. Prepare to receive backend requests.
  10. Build and deploy the app.

The end result will look like this:

You can see the finished app code in this GitHub repo.

If you want to run the app code from the repo you'll need to do some setup first.

Setup instructions
  • Create an App ID
    1. Create a new app in the Custom Apps page in your Wix Studio workspace.
    2. Go to the app's dashboard and copy its App ID.
    3. Replace the value of the appId property in the wix.config.json file with the App ID from your new app.
    4. Replace the value of the wix.run URL in the server.ts whitelist to use the App ID from your new app.
  • Request permissions
    1. Go to your app's page in the Custom Apps page.
    2. Click Permissions in the left sidebar.
    3. Click Add Permissions.
    4. Enter Read Products in the Search by name or ID field.
    5. Check the permission scope's checkbox under Choose Permission Scopes.
    6. Click Save.
  • Configure your OpenAI API key
    1. Create an OpenAI platform account.
    2. Create an OpenAI API key.
    3. In the backend project, create an environment variable named OPENAI_API_KEY and set its value to your API key.
  • Configure your app secret
    1. Go the Custom Apps page.
    2. Select your app from the list of apps.
    3. Click OAuth in the sidebar.
    4. Find, show, and copy your app's secret key.
    5. In the backend project, create an environment variable named WIX_APP_SECRET and set its value to your app secret.
  • Optionally configure a port for your server (defaults to 8090)
    1. In the backend project, create an environment variable named PORT and set its value to your desired port number.

Before you begin

Before getting started, make sure that:

Step 1 | Initialize the app

We use the Wix CLI to initialize our app. In the process of initializing our app, the Wix CLI automatically:

  • Creates a new app in the Custom Apps page of your Wix Studio workspace.
  • Sets up a new folder for your app in your local file system. The folder includes:
    • A src folder containing initial boilerplate code for an app with a dashboard page.
    • A package.json file containing your app dependencies.
  • Creates a local git repository for your app.
  • Prompts you to set up a development site for testing your app.

To initialize the app:

  1. Open a terminal and navigate to the folder where you want to create your app.

  2. Run the following command:

    Copy

    If prompted, press y to install the package.

  3. Select Create a new Wix App.

  4. Select Create a basic app.

  5. Enter a name for your app. Let’s name our app Business Buddy.

  6. Back in the terminal, press Enter to select the default folder name (business-buddy) for your app in your local file system.

You now have a new app, a new folder in your local file system, and a local git repository for developing and testing your app.

Step 2 | Create the dashboard pages

In the app, we want the dashboard pages to appear in the dashboard like this:

To create this structure, we use the CLI's generate command to generate dashboard page extensions. This places dashboard page files in subfolders of the dashboard/pages folder.

Create dashboard page files

  1. Run the following command and follow the prompts to create a dashboard page extension:

    Copy
  2. When prompted for a page route, type product. The route is the path that is appended to the dashboard base URL to access the dashboard page. Learn more about page routes.

  3. When prompted for a page name, enter Products.

    Upon completion, the extension files will be created in your local app files under the chosen route with the following structure:

    Copy

    For more information about these files, see Dashboard Page Extension Files and Code.

    Each dashboard page is defined by a page.json file and a page.tsx file. The page.json file defines the page metadata and the page.tsx file defines the page UI and functionality.

    Each file pair exists in a folder that determines the route to a page.

  4. Repeat the above steps but create a page with route settings, and page name Settings.

Step 3 | Run a local development server

Now that you’ve initialized the app, you can run a local development server to see the app in action, and view local changes as you develop it. The local development environment runs the app and its initial boilerplate code on the development site that you chose during app creation.

To run a local development server:

  1. Run the following command:

    Copy
  2. The CLI prompts you to choose a development site (test site), which you’ll use throughout this tutorial to run and test your app. You can choose an existing Wix site as your development site, or create a new one. Let’s Create a new Development Site. The newly created development site is automatically named something like Dev Site 5x2043, and can be found in your Wix account’s list of sites.

  3. Follow the prompt to open the development site on your default browser. If the browser doesn’t open, install your app on your test site manually and skip the next step.

  4. Click Agree & Add to install your app on your development site.

  5. Press 1 to open the local environment in your browser. Your development site’s dashboard opens, and you can see your newly created app’s dashboard pages in the left sidebar. We add the content of our app’s dashboard pages in step 5.

Your app is now running on your development site. As you develop your app, any changes made to your app’s code are reflected in real time on your development site.

If your changes don’t show up, try refreshing the page, or closing and reopening the development site.

Step 4 | Install dependencies

Before we start coding our app, we need to install some npm packages. In your terminal, run the following commands:

Copy

The purpose of each of these packages will become clear as we progress.

Step 5 | Design the Products page

In our app, we want the Products page to look like this:

This design is consistent with the rest of the pages in the dashboard. To create it, we’ll use the React components provided by the Wix Design System.

The Products page is built from:

  • Two main React components.
  • One wrapper component for initializing React context providers.
  • CSS styling.

The Products page UI is defined in several files in the dashboard folder as follows:

  • /pages/products/page.tsx: The header and the top cell that it used for selecting the product to chat about.
  • /pages/products/ProductChat.tsx: The bottom cell that displays the selected product and the chat.
  • /pages/products/ProductChat.module.css: CSS for the ProductChat component.
  • /withProviders.tsx: A QueryClientProvider and WixStyleReactProvider wrapper. QueryClientProvider allows fetching, caching, synchronizing, and updating server state. WixStyleReactProvider provides styling according to Wix's design system.

Let's take a look at the code used to build the page's UI. We'll take a look at the code for the page's functionality a bit later.

page.tsx

Notice how the code uses components from the Wix Design System to build the page. Other than that, it's a standard React component. For more information about each component, see AutoComplete, Card, TableActionCell, Divider, Layout, and Page.

Note: At this point, we're showing the code with a hardcoded, dummy product object just to demonstrate how the page will look once a product is selected. We'll add real products to the page later in the tutorial.

Copy

ProductChat.tsx

Here again, the code uses Wix Design System components to build the component UI. For more information about each component, see Text, Box, Card, Input, and Loader.

Copy

ProductChat.module.css

We’ll use the following CSS to define the width of the input element for the ProductChat component:

Copy

withProviders.tsx

Finally, here is the code for the QueryClientProvider wrapper.

Copy

Step 6 | Set up calls to Wix React SDKs

In our app, on the Products page, users can choose a product from the site's Store.

To work with the Stores app on a user's site, we use the Wix Dashboard SDK and the Wix SDK. We already showed how to set up your dashboard page extensions with the Dashboard SDK in the previous section. In this section, we'll use the SDK to retrieve site data to display in the app.

Permissions

Before getting started making calls with the SDK, you need to request the proper permissions.

You can find out which permissions your app needs by checking the API reference for the functions you call. Our app queries store products, so it needs the Read Products permission.

You can add permissions in your app's dashboard by selecting Permissions from the sidebar.

Get products

After setting up permissions, our app can retrieve a list of products from the site's store.

In your Products page code add the following imports:

Copy

These imports give us access to the functionality we need for retrieving products.

Once we import everything, we'll add the following hooks to our ProductsPage component:

  1. We’ll use the products module directly to access its queryProducts() function to access store products.

    Copy
  2. Next, we use the React useQuery() hook to query for products whose names start with a query string. This string will be set based on the product selected in our AutoComplete component. We also make sure to handle any errors.

    Copy
  3. Finally, let’s replace our dummy current product with the proper type now that we have it.

    Copy

Populate products

Now that we have access to a list of the site’s products, we can use them to populate the AutoComplete component and define what happens when a user selects a product.

  1. First, we set the AutoComplete component's status.

    Copy
  2. Then, we set the AutoComplete component's options to the products we got from the query by mapping them to a list of options objects with id and value properties.

    Copy
  3. Next, we set up the AutoComplete component's onSelect function to set the component's current product.

    Copy

    While we're at it, we also set the AutoComplete component's onChange function to set the search query and clear the current product.

    Copy
  4. Finally, we set the AutoComplete component's value to the current product if there is one.

    Copy

Step 7 | Set up communication with the backend

In our app, the Products and Settings dashboard pages will need to communicate with an app backend to work with the OpenAI API and to store user settings.

In general, you communicate with a backend server from a Wix App the same way you would in any other type of app.

You do, however, need to pay special attention to:

  • Authenticate that requests to your server are coming from your app and not a malicious user.
  • Differentiate between requests from the various instances of your app installed on different sites.

Later, we'll see how to do all that on the server. For now, let's focus on what we need to do on the front end.

Instance ID

Each time an app is installed on a site a unique instance ID is assigned. You can use the instance ID to authenticate requests sent from an app and to know which instance of the app is sending the request. The instance ID is added as a query param to your app’s dashboard pages.

Let's see how we add code to send requests to the server using the instance ID. In our app, we've placed this code in a file named utils.ts in the dashboard folder.


  1. First, we create a function to get the instance ID from the page's URL.

    Copy
  2. Next, we create a function to fetch data from the server using the instance ID to authorize the request. Notice how we call the getAppInstance() function described above to create the authorization header.

    Copy

    import.meta.env.VITE_API_BASE_URL accesses the environment variable VITE_API_BASE_URL provided by Vite. So, ${import.meta.env.VITE_API_BASE_URL}/${relativePath} dynamically constructs a full URL by combining the base URL defined in VITE_API_BASE_URL with the relativePath passed to the function.

Fetching data

Now that we've set up the infrastructure to make secure requests to the server, we can use the ProductChat component to send and receive chat messages.

To add backend requests to ProductChat, we do the following:

  1. First, in ProductChat.tsx we import the utility function described above.

    Copy
  2. Then, we add a function to submit messages, send them to the server, and update the state with the response. Notice how this function calls fetchWithWixInstance() to post a new message to the server.

    Copy
  3. Finally, we call submitMessage() when the send icon is clicked.

    Copy

    And we call submitMessage() again when enter is pressed in the Input component.

    Copy

You can see the complete code for the Products page in our GitHub repo.

Step 8 | Design the Settings page

In our app, the Settings page is defined in the dashboard/pages/settings/page.tsx as follows:

Copy

As usual, the code uses Wix Design System components to build the component UI. For more information about each component, see Button, Card, FormField, InputArea, Loader, and Page.

react-query

In this code, we import useMutation and useQuery from react-query:

  • useQuery is used to fetch data from the server and handle caching. In the code below, useQuery fetches the current behaviorDirective from the server and stores it in data.

    Copy
  • useMutation is used to update data on the server. In the code below, useMutation sends a new behaviorDirective to the server via a POST request:

    Copy

Page component

This component renders a page where we can configure a behavior directive. It includes the following elements:

  • Page Header: Displays the title "Behavior Settings".
  • Card Component: Encapsulates the settings form.
    • Card Header: Displays the title "Behavior Directive" and a "Save" button.
      • Save Button: When clicked, useMutation sends the new directive to the server by calling mutation.mutate. It shows a loader instead while the mutation is in progress.
    • Card Subheader: Adds the subtitle "Give Business Buddy directives on how to answer your questions".
    • Card Content: Contains a form field with the label "Directive".
      • InputArea: A text area where users can input the behavior directive. It has a placeholder text, a character counter, and is resizable. The input value is managed by the behaviorDirective state.

Adding a toast

When a user changes the behavior setting on the Settings page, we want to show a toast at the top of the dashboard page.

To show toasts, update dashboard components based on state changes, and open and close dashboard modals, we use the Wix Dashboard React SDK.

  1. First, we need to import the dashboard module from the Dashboard SDK.

    Copy
  2. Finally, we call the showToast() function of the dashboard module and provide a message and type. In our app, we want to show the toast when a behavior setting has been successfully changed, so we call showToast() in the onSuccess of the mutation used by the Save button.

    Copy

Step 9 | Prepare to receive backend requests

In our app, the backend server must receive requests for chat messages, and for storing and retrieving settings values. Each of these operations must be performed by calling an endpoint exposed on the server.

In this implementation, we use a simple Express server. You're free to use any type of server for your app's backend.

When an app server receives a request to an endpoint, it needs to:

  • Authenticate that the request is from your app and not a malicious user.
  • Know which instance of your app has sent the request.

You'll also need to set up CORS to make sure your server allows the requests from your app.

CORS

To set up CORS properly, we need to add headers that allow access from certain origins and with certain HTTP methods.

In our case, we whitelist localhost for testing purposes and the URL for our app frontend on the Wix App CDN.

The URL of an app on the CDN is in the following format:

Copy

You can find your app's App ID on your app's dashboard.

This is how we whitelist the URLs on our server using Express:

Copy

Authentication

Now that we've dealt with CORS issues, the next thing to do is to authenticate the requests coming into our server.

To authenticate requests, we first need our app's secret key from your app's dashboard. We get the key from the OAuth page in our app's dashboard. Then we add the key to an environment variable named WIX_APP_SECRET.

Now that we have the key, we can write code to authorize the request. In our case, we write this code in a file on our server named utils.ts.

To add authentication logic, we do the following:

  1. First, we create the authorizeWixRequest() function. This function reads the authorization header sent from our app frontend and checks it using the parseInstance() function described below.

    Copy
  2. Next, we create the parseInstance() function to parse the received app instance and check it against our app's secret key using the validateInstance() function described below.

    Copy
  3. Then we create the validateInstance() function to authenticate the instance against our app secret.

    Copy
  4. To use this authentication code, we call the authorizeWixRequest() function and pass it an incoming request. For example, when we receive a request for a product chat we authorize the request before continuing.

    Copy

Multiple instances

In our app, the backend server must store settings data for each app instance. We use the instance ID to associate a particular setting value with a particular instance of our app. We can do this by storing the instance ID alongside each setting value in a simple key-value store.

The authorizeWixRequest() function we created in the previous section returns the parsed instance information, including an instanceId. We can pass that information to the key-value store when we process a request, such as a /settings POST, as you can see here.

Copy

Then, in the key-value store, we can store the value of the instanceId as the key and the setting text as the value.

Copy

Step 10 | Build and deploy the app

After testing your app and seeing that it works as expected, you can create a public preview of your app, build your app, create and manage app versions, and deploy your app. For more information on these tasks, see Build and Deploy an App with the CLI

Summary

After completing this tutorial, you have created a dashboard AI chatbot that integrates with a custom backend and Wix site data. At this point, you have all you need to know to develop an app. Feel free to play around with the example app some more, or get started on writing your own app.

Did this help?