The author selected The Mozilla Foundation to receive a donation as part of the Write for DOnations program.
After deploying a website, you will want to add analytics scripts to your site to learn about the pages that drive the most traffic and track the number of visitors, goal conversions, and page views. Umami is an open-source web analytics software that runs on PostgreSQL and Next.js API routes.
Umami allows you to track events, referring pages, session durations, view counts, and unique visitor counts for your pages. On a single Umami instance, you can track an unlimited number of websites and create multiple users so different people can track their websites from a single deployment.
In this guide, you will clone Umami to your local computer, create PostgreSQL tables, set up connection pooling, and deploy Umami to App Platform.
Before you begin this guide you’ll need the following:
psql
, installed on your local machine. You can install psql
by following the steps in the Connecting to a managed PostgreSQL section of the How To Connect to a Managed Database guide.The Umami repository on GitHub contains the files and scripts needed to run Umami. Forking this repository allows you to deploy Umami to App platform, and use an SQL script contained in it to set up tables in the PostgreSQL database.
In this step, you will fork the repository and clone it to your local computer with git
.
To fork the repository, go to the Umami repository on GitHub and click the Fork button at the top right corner of the page. Your copy of the repository will be at https://github.com/your\_github\_username/umami
.
In your forked repository, click the Code button, copy the HTTPS link, and clone the forked repository to your local computer with the following command:
- git clone https://github.com/your_github_username/umami.git
The git clone
command creates a copy of a repository on your computer. You will see an output similar to the following after running the command:
OutputCloning into 'umami'...
remote: Enumerating objects: 6352, done.
remote: Counting objects: 100% (270/270), done.
remote: Compressing objects: 100% (159/159), done.
remote: Total 6352 (delta 131), reused 219 (delta 103), pack-reused 6082
Receiving objects: 100% (6352/6352), 2.57 MiB | 519.00 KiB/s, done.
Resolving deltas: 100% (4388/4388), done.
Checking out files: 100% (355/355), done.
Move into the repository’s directory:
- cd umami
Now that you have forked the Umami repository and cloned it to your local machine, you will set up the umami
database on PostgreSQL and create its tables.
umami
Database, Setting Up Tables, and Starting a Connection PoolIn this step, you will create and initialize an umami
database in your cluster. This database is where Umami will store data from your websites.
To create the umami
database in your cluster, open the Cloud Control Panel in your DigitalOcean account and select Databases from the side menu. Choose the database cluster you created from the list of clusters. Navigate to the Users and Databases tab and scroll down to Databases. Type umami
in the textbox and click Save to create the umami
database.
Now that you have created the umami
database, you can build the tables Umami will need to run. To complete this, you will need the connection string to connect to your umami
database.
On the Cloud Control Panel, switch to the Overview tab. Look for the Connection Details section on the right of the page. In the dropdown where Connection Parameters is written, select Connection String. Select the umami
database from the dropdown beside where Database/Pool is written. Afterward, click Copy to copy the connection string to the clipboard.
The SQL script at sql/schema.postgresql.sql
creates all the tables that Umami needs and sets up the indices in all these tables. It also sets up an admin account for Umami with the username admin
and password umami
.
Warning: The admin user on Umami can create and delete accounts. It is strongly advised to change these default credentials after deployment to prevent unauthorized access to your Umami instance. You can change the default credentials in Step 3.
Run the following command from the umami
directory you entered to create the tables:
- psql 'your_connection_string' -f sql/schema.postgresql.sql
psql
uses the connection string to connect to your database and the -f
flag runs the SQL script at sql/schema.postgresql.sql
against the database.
When you run the command successfully, you will have the following output:
Outputpsql:sql/schema.postgresql.sql:1: NOTICE: table "event" does not exist, skipping
DROP TABLE
psql:sql/schema.postgresql.sql:2: NOTICE: table "pageview" does not exist, skipping
DROP TABLE
psql:sql/schema.postgresql.sql:3: NOTICE: table "session" does not exist, skipping
DROP TABLE
psql:sql/schema.postgresql.sql:4: NOTICE: table "website" does not exist, skipping
DROP TABLE
psql:sql/schema.postgresql.sql:5: NOTICE: table "account" does not exist, skipping
DROP TABLE
CREATE TABLE
CREATE TABLE
CREATE TABLE
CREATE TABLE
CREATE TABLE
CREATE INDEX
CREATE INDEX
CREATE INDEX
CREATE INDEX
CREATE INDEX
CREATE INDEX
CREATE INDEX
CREATE INDEX
CREATE INDEX
CREATE INDEX
CREATE INDEX
INSERT 0 1
You have successfully created the umami
database and the tables in it. You will now create a connection pool for the umami
database.
PostgreSQL was built to have persistent connections. The Next.js API routes that Umami runs on, however, are not able to share database connections across requests. To support the short-lived connections that will be made from the API route and prevent errors, you will create a connection pool for your cluster.
A connection pool is an application that allows you to reuse database connections across multiple requests by making a number of persistent connections to the database and forwarding client requests through those connections. When more requests are made than connections are available, subsequent requests are queued until there is a free connection.
To enable connection pooling for your managed database, go to your Cloud Control Panel. Click Databases on the side menu then select the database you created. Go to the Connection Pools tab and click Create a Connection Pool. A modal will open. Set the pool name as umami-pool, select the umami database, and set the pool size to 11
. Click Create Pool to create the connection pool.
You can change the size of the connection pool later to support more traffic. Refer to How to Manage Connection Pools to learn more about when to adjust and how to select a pool size.
Requests from Umami will not be made directly to the database but to the connection pool. You will therefore need the connection string of the connection pool. This connection string is one of the environment variables that will be needed when deploying the app to the App Platform. To get the connection string, go to the Connection Pools tab and click Connection details. When the modal opens, click the Connection parameters dropdown, select Connection String, and click Copy to copy the connection string.
The connection pool’s connection string is one of the environment variables you will need when deploying to the App Platform since database requests will be made to the connection pool.
Now that you have set up connection pooling on your database, you will deploy Umami to the App Platform.
In this step, you will deploy Umami to App Platform. Umami runs on a web application written in Next.js, and App Platform will deploy it from your fork of Umami. Visit the App Platform section of the Control Panel and click Launch Your App to begin.
You will be presented with a list of options for the source of your code. Choose GitHub as the source. If this is your first time deploying to App Platform from a GitHub repository, you will be asked to connect App Platform to your GitHub account.
Choose the repository where you want to deploy your app. Select your_github_username/umami
as the source repository from the dropdown. Leave the branch as master
, keep Autodeploy code changes checked, then click Next.
App Platform will automatically detect a Dockerfile in the repository and set the necessary settings. You will now add the environment variables that Umami requires.
Umami requires two environment variables to work:
DATABASE_URL
: the connection string for your PostgreSQL database.HASH_SALT
: a random string used to generate unique values for the application.Click Edit next to Environment Variables to add these environment variables.
For Umami to work well with your connection pool, you will need to modify the connection pool connection string you got from the Cloud Control Panel by appending &pgbouncer=true
to the end. The value of DATABASE_URL
should look like:
postgres://sammy:your_password@host-domain:25061/umami?sslmode=require&pgbouncer=true
Click the + button and set a HASH_SALT
environment variable as a random string. Tick the Encrypt checkbox next to HASH_SALT
so the value of HASH_SALT
will be encrypted while saving.
Click Next to continue setting up the app.
Pick a name for your Umami instance and select the region where to deploy your app. The region closest to you is automatically selected to minimize connection latency. Click Next to proceed.
Select the Basic plan, or the Pro plan should you require a larger size for your project, and click Launch Your App to finalize the deployment.
The app build will now begin. Once the build completes, the URL where your app will be accessible will display under the app’s name.
Open the URL to visit your analytics dashboard.
You can log in with the default credentials:
Secure your instance by clicking Settings on the header. Navigate to Profile on the sidebar and click Change password. Enter the previous password—umami
and pick a new password for signing in to the admin
account.
To get the tracking script for a website, log in to your Umami Dashboard. Select Settings on the navigation bar at the top of the screen. Click the Add website button. When the modal opens, select a name for the website and enter the domain where the website is located.
After adding the website, you will find it in the list of websites in the settings. Click the first button under the website to show the tracking script.
When you click the button, a modal will open with the tracking script in a <script>
tag. Paste the code snippet shown in the <head>
tag of your website’s pages to start getting data from the website. When a visitor visits your web pages, the script automatically sends data to Umami.
You have now successfully deployed your instance of Umami Analytics. You can now track page views, session durations, and other metrics from all your websites. You can refer to Umami’s documentation to learn how to track events. If you want to have Umami available from a custom domain, you can refer to How to Manage Domains in App Platform to learn how.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
I’ve continually gotten a build error when attempting to deploy via the App Platform:
Build Error: Out of Memory
I’ve tried a 512MB, 1GB and 2GB instance using the base plan but continue to encounter the same error. Any further suggestion or recommendations? What are the anticipated technical requirements for Umami deployment?
Full logs for reference:
[2022-02-17 21:51:05] => Initializing build [2022-02-17 21:51:05] => Retrieving source code to /.app_platform_workspace [2022-02-17 21:51:05] => Selecting branch “master” [2022-02-17 21:51:08] => Checking out commit “2575cbfc11c0c59c3b241cab51bad2f9e1b0b62f” [2022-02-17 21:51:09] => Got source_dir: / [2022-02-17 21:51:09] => Using workspace root /.app_platform_workspace [2022-02-17 21:51:09] => Got dockerfile_path: Dockerfile [2022-02-17 21:51:09] [2022-02-17 21:51:10] => Building app using Dockerfile [2022-02-17 21:51:10] => Injecting app environment variables: [2022-02-17 21:51:10] DATABASE_URL HASH_SALT [2022-02-17 21:51:10] => Using Dockerfile: /.app_platform_workspace/Dockerfile [2022-02-17 21:51:10] => Using build context /.app_platform_workspace// [2022-02-17 21:51:10] [2022-02-17 21:51:11] INFO[0000] Resolved base name node:12.18-alpine to build [2022-02-17 21:51:11] INFO[0000] Resolved base name node:12.18-alpine to production [2022-02-17 21:51:11] INFO[0000] Using dockerignore file: /.app_platform_workspace/.dockerignore [2022-02-17 21:51:11] INFO[0000] Retrieving image manifest node:12.18-alpine
[2022-02-17 21:51:11] INFO[0000] Retrieving image library/node:12.18-alpine from registry mirror <registry-uri-1> [2022-02-17 21:51:12] INFO[0001] Retrieving image manifest node:12.18-alpine
[2022-02-17 21:51:12] INFO[0001] Returning cached image manifest
[2022-02-17 21:51:12] INFO[0001] Retrieving image manifest node:12.18-alpine
[2022-02-17 21:51:12] INFO[0001] Returning cached image manifest
[2022-02-17 21:51:12] INFO[0001] Retrieving image manifest node:12.18-alpine
[2022-02-17 21:51:12] INFO[0001] Returning cached image manifest
[2022-02-17 21:51:12] INFO[0001] Built cross stage deps: map[0:[/build/prod_node_modules /build/node_modules/.prisma/ /build/yarn.lock /build/package.json /build/.next /build/public]] [2022-02-17 21:51:12] INFO[0001] Retrieving image manifest node:12.18-alpine
[2022-02-17 21:51:12] INFO[0001] Returning cached image manifest
[2022-02-17 21:51:12] INFO[0001] Retrieving image manifest node:12.18-alpine
[2022-02-17 21:51:12] INFO[0001] Returning cached image manifest
[2022-02-17 21:51:12] INFO[0001] Executing 0 build triggers
[2022-02-17 21:51:12] INFO[0001] Checking for cached layer <registry-uri-2> [2022-02-17 21:51:13] INFO[0002] Using caching version of cmd: RUN yarn config set --home enableTelemetry 0 [2022-02-17 21:51:13] INFO[0002] Checking for cached layer <registry-uri-3> [2022-02-17 21:51:13] INFO[0002] No cached layer found for cmd RUN yarn install --production --frozen-lockfile [2022-02-17 21:51:13] INFO[0002] Unpacking rootfs as cmd COPY package.json yarn.lock /build/ requires it. [2022-02-17 21:51:18] INFO[0008] ARG BASE_PATH
[2022-02-17 21:51:18] INFO[0008] No files changed in this command, skipping snapshotting. [2022-02-17 21:51:18] INFO[0008] ARG DATABASE_TYPE
[2022-02-17 21:51:18] INFO[0008] No files changed in this command, skipping snapshotting. [2022-02-17 21:51:18] INFO[0008] ENV BASE_PATH=$BASE_PATH
[2022-02-17 21:51:18] INFO[0008] No files changed in this command, skipping snapshotting. [2022-02-17 21:51:18] INFO[0008] ENV DATABASE_URL “postgresql://umami:umami@db:5432/umami” DATABASE_TYPE=$DATABASE_TYPE [2022-02-17 21:51:18] INFO[0008] No files changed in this command, skipping snapshotting. [2022-02-17 21:51:18] INFO[0008] WORKDIR /build
[2022-02-17 21:51:18] INFO[0008] cmd: workdir
[2022-02-17 21:51:18] INFO[0008] Changed working directory to /build
[2022-02-17 21:51:18] INFO[0008] Creating directory /build
[2022-02-17 21:51:18] INFO[0008] Taking snapshot of files…
[2022-02-17 21:51:18] INFO[0008] RUN yarn config set --home enableTelemetry 0 [2022-02-17 21:51:18] INFO[0008] Found cached layer, extracting to filesystem [2022-02-17 21:51:19] INFO[0008] COPY package.json yarn.lock /build/
[2022-02-17 21:51:19] INFO[0008] Taking snapshot of files…
[2022-02-17 21:51:19] INFO[0008] RUN yarn install --production --frozen-lockfile [2022-02-17 21:51:19] INFO[0008] Taking snapshot of full filesystem…
[2022-02-17 21:51:23] INFO[0012] cmd: /bin/sh
[2022-02-17 21:51:23] INFO[0012] args: [-c yarn install --production --frozen-lockfile] [2022-02-17 21:51:23] INFO[0012] Running: [/bin/sh -c yarn install --production --frozen-lockfile] [2022-02-17 21:51:24] yarn install v1.22.4 [2022-02-17 21:51:24] [1/4] Resolving packages… [2022-02-17 21:51:25] [2/4] Fetching packages… [2022-02-17 21:52:02] info There appears to be trouble with your network connection. Retrying… [2022-02-17 21:53:31] info fsevents@2.3.2: The platform “linux” is incompatible with this module. [2022-02-17 21:53:31] info “fsevents@2.3.2” is an optional dependency and failed compatibility check. Excluding it from installation. [2022-02-17 21:53:31] [3/4] Linking dependencies… [2022-02-17 21:53:31] warning “eslint-config-next > @typescript-eslint/parser > @typescript-eslint/typescript-estree > tsutils@3.21.0” has unmet peer dependency “typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta”. [2022-02-17 21:53:31] warning Workspaces can only be enabled in private projects. [2022-02-17 21:53:31] warning Workspaces can only be enabled in private projects. [2022-02-17 21:53:49] [4/4] Building fresh packages… [2022-02-17 21:54:02] Done in 158.06s. [2022-02-17 21:54:02] INFO[0171] Taking snapshot of full filesystem…
[2022-02-17 21:56:31] INFO[0320] RUN cp -R node_modules/ prod_node_modules/
[2022-02-17 21:56:31] INFO[0320] cmd: /bin/sh
[2022-02-17 21:56:31] INFO[0320] args: [-c cp -R node_modules/ prod_node_modules/] [2022-02-17 21:56:31] INFO[0320] Running: [/bin/sh -c cp -R node_modules/ prod_node_modules/] [2022-02-17 21:56:32] INFO[0321] Pushing layer <registry-uri-4> to cache now [2022-02-17 21:56:32] INFO[0321] Pushing image to <registry-uri-5> []