Get Started · Unomi 3.1
Getting Started with Apache Unomi 3.1
From zero to a running Customer Data Platform — with multi-tenancy and API keys.
Prerequisites
What you need for Unomi 3.1
- Docker (recommended path) — or Java 17+ for a manual install
- Elasticsearch 9.x (e.g. 9.4.3) or OpenSearch 3.x
- After startup you create a tenant and use its public / private API keys for API calls
Overview
What is Apache Unomi?
Apache Unomi is a REST server that manages user profiles and events. It integrates personalization and profile management into any system — CMS, CRM, mobile apps, custom platforms, or AI agents.
- Tracks users via cookies or custom identifiers and builds rich profiles over time
- Multi-tenancy (Unomi 3.1) — isolate profiles, events, segments, rules, and schemas per tenant
- Built-in rule engine, dynamic segmentation, and privacy / GDPR APIs
- OSGi plugin architecture on Apache Karaf — Elasticsearch or OpenSearch backend
- Reference implementation of the OASIS CDP specification
Privacy as a First-Class Feature
Unomi’s privacy REST API lets you build user-facing UIs where visitors can manage their profile, control tracking, view collected data, anonymize past data, or fully delete their profile. Built for a world where GDPR and privacy legislation matter.
Quick Start
Run Unomi 3.1 with Docker
The fastest way to try Apache Unomi. Only Docker is required. Choose Elasticsearch or OpenSearch.
Create a docker-compose.yml
Pick one backend. Image tag matches the current stable release (3.1.0).
Option A — Elasticsearch 9.4.3
version: '3.8'
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:9.4.3
environment:
- discovery.type=single-node
- xpack.security.enabled=false
ports:
- 9200:9200
unomi:
image: apache/unomi:3.1.0
environment:
- UNOMI_ELASTICSEARCH_ADDRESSES=elasticsearch:9200
- UNOMI_THIRDPARTY_PROVIDER1_IPADDRESSES=0.0.0.0/0,::1,127.0.0.1
ports:
- 8181:8181
- 9443:9443
- 8102:8102
depends_on:
- elasticsearch
Option B — OpenSearch 3.x
version: '3.8'
services:
opensearch-node1:
image: opensearchproject/opensearch:3
environment:
- cluster.name=opensearch-cluster
- node.name=opensearch-node1
- discovery.type=single-node
- bootstrap.memory_lock=true
- "OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m"
- OPENSEARCH_INITIAL_ADMIN_PASSWORD=${OPENSEARCH_INITIAL_ADMIN_PASSWORD:-admin}
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: 65536
hard: 65536
volumes:
- opensearch-data1:/usr/share/opensearch/data
ports:
- 9200:9200
- 9600:9600
unomi:
image: apache/unomi:3.1.0
environment:
- UNOMI_DISTRIBUTION=unomi-distribution-opensearch
- UNOMI_OPENSEARCH_ADDRESSES=opensearch-node1:9200
- UNOMI_OPENSEARCH_USERNAME=admin
- UNOMI_OPENSEARCH_PASSWORD=${OPENSEARCH_INITIAL_ADMIN_PASSWORD:-admin}
- UNOMI_HEALTHCHECK_PROVIDERS=cluster,opensearch,unomi,persistence
ports:
- 8181:8181
- 9443:9443
- 8102:8102
depends_on:
- opensearch-node1
volumes:
opensearch-data1:
Start the environment
docker compose up
Wait for startup to complete (usually 1–2 minutes).
Create a tenant (required in 3.1)
System admin credentials create tenants. Creation stores hashed keys only (maskedKey in the response) — regenerate each key once and save plainTextKey immediately.
curl -X POST http://localhost:8181/cxs/tenants \
--user karaf:karaf \
-H "Content-Type: application/json" \
-d '{
"requestedId": "default",
"properties": {
"name": "Default Tenant",
"description": "Default tenant for quick start"
}
}'
# One-time plaintext secrets (replaces any existing key of that type)
curl -X POST 'http://localhost:8181/cxs/tenants/default/apikeys?type=PUBLIC' \
--user karaf:karaf
curl -X POST 'http://localhost:8181/cxs/tenants/default/apikeys?type=PRIVATE' \
--user karaf:karaf
- PUBLIC
plainTextKey— use asX-Unomi-Api-Keyon/cxs/context.jsonand/cxs/eventcollector - PRIVATE
plainTextKey— basic authdefault:<private-key>for admin APIs (scopes, rules, schemas, …)
Verify cluster & request context
Cluster (system admin):
curl -k https://localhost:9443/cxs/cluster -u karaf:karaf
Create a scope before context or events (schema validation rejects unknown scopes):
curl -X POST http://localhost:8181/cxs/scopes \
-u "default:YOUR_PRIVATE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"itemId": "default",
"itemType": "scope",
"metadata": { "id": "default", "name": "Default scope" }
}'
First context request (public API key required):
curl -X POST "http://localhost:8181/cxs/context.json?sessionId=1234" \
-H "Content-Type: application/json" \
-H "X-Unomi-Api-Key: YOUR_PUBLIC_API_KEY" \
-d '{
"source": {
"itemId": "homepage",
"itemType": "page",
"scope": "default"
}
}'
Default system credentials: karaf / karaf. Certificate warnings on port 9443 are expected in development.
Production note: This configuration is for development only. See the production security guide before deploying.
Manual install? Java 17+, Elasticsearch 9.4.3 or OpenSearch 3.x — follow the manual quick start (same tenant + API key steps).
Upgrading from 2.x? See Migrating to Unomi 3 and optional V2 compatibility mode.
Unomi 3.1 authentication
How API access works
| Audience | Credential | Typical use |
|---|---|---|
| System admin | karaf:karaf (basic) |
Create / list tenants, cluster ops |
| Tenant admin | tenantId:privateApiKey (basic) |
Scopes, rules, schemas, searches |
| Public apps / trackers | X-Unomi-Api-Key: <public> |
/cxs/context.json, /cxs/eventcollector |
Details: Multi-tenancy in Unomi 3 · Manual — Multi-tenancy
What’s Next?