---
source: https://qlik.dev/embed/nebula/quickstart/build-a-simple-web-app/
last_updated: 2026-03-18T16:49:43Z
---

# Build a simple web app

> **Note:** Where possible, use [qlik-embed](https://qlik.dev/embed/qlik-embed/) rather than this framework.\
> For more information, review the [embedding Qlik Analytics using qlik-embed web components tutorial](https://qlik.dev/embed/qlik-embed/quickstart/qlik-embed-webcomponent-quickstart).

> **Third-party cookies:** This tutorial leverages cookies for auth, which are blocked by some browser vendors.
> Please use an OAuth solution where possible, which doesn't leverage cookies.

This tutorial goes through all the steps necessary for you to create a simple
web app from scratch that'll integrate with your Qlik Cloud tenant.
You'll learn about concepts such as:

- How to use [web integrations (CORS/domain allowlisting)](https://help.qlik.com/en-US/cloud-services/Subsystems/Hub/Content/Sense_Hub/Admin/mc-adminster-web-integrations.htm).
- How to do REST calls (headers, query parameters, and more).
- How to set up WebSockets towards the Qlik Associative Engine.

If you're just interested in the code produced in this tutorial, skip to the
[Summary](#summary) section.

## Requirements

This tutorial requires you to have the following things accessible:

- [Node.js](https://nodejs.org/en/download) (version 10 or newer)
- A terminal (for example [Git Bash on Windows](https://gitforwindows.org/),
  or Terminal.app on Mac).
- OpenSSL (installed through Git Bash, and by default on Mac).
- A modern web browser, for example, Google Chrome.
- A text editor or IDE of your choice, for example, Visual Studio Code.
- An existing [web integration](https://help.qlik.com/en-US/cloud-services/Subsystems/Hub/Content/Sense_Hub/Admin/mc-adminster-web-integrations.htm),
  or possibility to get one created in your tenant.

## Bootstrapping the project

To avoid making this tutorial too advanced, you'll only work with plain HTML,
CSS, JavaScript, and the [enigma.js](https://qlik.dev/toolkits/enigma-js)
library, which simplifies communication with the Qlik Associative Engine through
WebSockets.

But before you can start writing any code, you need to prepare the project.
There are three steps:

- Create the necessary project (folders and files) structure.
- Start a local web server.
- Create or retrieve a web integration configuration from your tenant.

### Project structure

First of all, start your preferred terminal and create the project folder.

```bash
# move to a folder where you want to store the project:
cd ~

# new folder to contain the project files:
mkdir simple-web-app
```

But what good is a folder without any content? Continue by creating
an index page and an app JavaScript file that serves as the basis for
the logic needed to communicate with your tenant.

Create an `index.html` file using your favorite editor and save the file in the
project folder.

`embed:./snippets/build-a-simple-web-app/index.html`

Next, create the `app.js` file. Just put an
[IIFE expression](https://developer.mozilla.org/en-US/docs/Glossary/IIFE)
in that file for now. You'll fill it out with more content further into this tutorial.

`embed:./snippets/build-a-simple-web-app/app.js#L1,74`

Next up, learn how to start the HTTPS web server needed for communication
with your tenant.

### Starting the web server

To serve your web app locally, you'll need an HTTPS web server. The web integration
that you'll set up later requires HTTPS, which means that you can't just open
up your web app files using the `file://` protocol.

In this tutorial, you'll use [`http-server`](https://github.com/http-party/http-server),
a package available through the npm package manager that comes with your Node.js
installation. This is a simple command-line web server that also support HTTPS.

Open up your terminal and enter the following commands. Ignore typing the lines
starting with `#` as they're just comments for each command. The `npx` command comes
as part of your npm installation and allows you to execute command-line tools available
on npm without having to install them globally.

```bash
# move to the folder created during the `Project structure` section:
cd ~/simple-web-app

# create a certificate needed for the HTTPS server. Note that this command
# may prompt you for additional information. Enter the information needed
# and continue:
openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem
# if this command fails, you may have to install openssl manually first.

# start the HTTPS server using the certificates generated before.
# -S means to use HTTPS and the certificates generated by openssl, -c -1 disabled caching:
npx http-server -S -c -1
```

> **Note:** If you're using Google Chrome and get an error about invalid certificate, you
> may need to navigate to `chrome://flags/#allow-insecure-localhost` in a
> browser tab and enable that flag.

If these commands run successfully, you should now have an HTTPS web server running.
Note the URL shown in the command-line window as you'll need it in the next step
when configuring the web integration.

### Create or retrieve web integration

To allow third-party domains to communicate with your tenant, you need to
set up a [web integration](https://qlik.dev/authenticate/jwt/implement-jwt-authorization). This process
requires tenant administrator privileges.

Once you've created or retrieved the web integration ID, you should have everything
you need to start communicating with your tenant in your web app.

In the next section, you'll learn more about the business logic needed in your
web app to communicate with your tenant.

## Building the web app

In the previous section, you learned how to set up your developer environment,
including retrieving the necessary web integration ID. In this section, you'll
learn:

- How to configure your HTTP requests with the required headers.
- How to detect if your web app visitor is signed in and trigger the
  single-sign on, if needed.
- How to open up WebSocket connections to the Qlik Associative Engine using [enigma.js](https://qlik.dev/toolkits/enigma-js).

### Configure HTTP requests

When communicating with a tenant, you're required to supply the web integration
you've configured for your web app with each request. This reduces the risk of
abuse, and at the same time avoids having to maintain a global whitelist of domains
for each tenant.

Next, you'll add some code to your `app.js` file that helps you to configure
requests towards your tenant.

> **Note:** `fetch` is a web standards API for making REST calls, see full
> [documentation on this API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch).

`embed:./snippets/build-a-simple-web-app/app.js#L1-18,74`

This function is used throughout the rest of this tutorial to simplify
doing REST API calls. `fetch` has to be configured for CORS or your web app
might be blocked by the browser and/or web server. Note that your web integration
ID is sent as a header.

### Ensure your user is signed in to your tenant

In this step, you'll fetch the user metadata, and trigger the single-sign on
flow if your user isn't signed in to your tenant.

Preceding `})();` in your `app.js` file, add the following code:

`embed:./snippets/build-a-simple-web-app/app.js#L20-32`

Save the `app.js` file, and refresh your browser. You should now see a
`Hello, <your name>` message once you've signed in.

> **Note:** If you get sent to the hub after logging in, it's likely that your web
> integration is misconfigured. Confirm, for example, that you're using
> the correct web integration ID, and that the origin your solution
> runs on is allowlisted.

Next up, you'll fetch the CSRF token,
which is required as a header in all non-`GET` requests; for WebSockets it's
defined as a query parameter instead (since you can't set headers on WebSockets
in browser environments).

Preceding `})();` in your `app.js` file, add the following code.

`embed:./snippets/build-a-simple-web-app/app.js#L34-37,71-73`

> **Note:** This uses the `request` function created earlier.
> The `false` parameter ensures access to the basic response object instead of the JSON body,

> allowing you to access the headers in this case.

### Open an app using enigma.js

In the previous step, you stored the `csrfToken` value, which is needed when opening
WebSockets. The next thing now is to open a session towards an app using enigma.js.
The use case is simplified here so feel free to play around with the code to fit
your needs once you got it to present the app title in your web app.

After the `const csrfToken = ...` row in your `app.js` file, add the following
code.

`embed:./snippets/build-a-simple-web-app/app.js#L39-45`

> **Note:** If your web app is displaying the `No apps available` text, it means that the user
> you're signed in as doesn't have any apps available to them yet. Head over to
> the hub and create or import an app then continue this tutorial.

Once you have the app list, you can continue by creating the enigma.js session.

After the `if`-clause you added from the previous step, add the following
code in your `app.js` file.

`embed:./snippets/build-a-simple-web-app/app.js#L47-62`

In the URL, note that you're referring to the `appId`, `webIntegrationId`, and
`csrfToken` values. These are all required parameters for a valid WebSocket connection.
Next up is to actually open the WebSocket, and the app, and finally display the
app title in your web app.

After the `const session = ...` row, add the following code to your `app.js` file.

`embed:./snippets/build-a-simple-web-app/app.js#L63-70`

This concludes this section. You should now have your signed-in user name together
with an app title presented in your web app.

## Summary

This tutorial hopefully taught you how to create a basic web app from scratch that
communicates with your tenant, and all the steps needed to configure web integrations,
HTTP requests, and WebSockets.

The following files have been created as part of this tutorial.

`index.html`

`embed:./snippets/build-a-simple-web-app/index.html`

`app.js`

`embed:./snippets/build-a-simple-web-app/app.js`
