Tutorials
Getting Started with Apache Unomi 3
From zero to a running CDP in minutes. Pick the path that suits you.
In this guide
Quick Start with Docker
The fastest way to get Unomi running. You only need Docker installed.
Create docker-compose.yml
Create a new directory and add a docker-compose.yml file with the following content:
version: '3.8'
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.10.2
environment:
- discovery.type=single-node
ports:
- 9200:9200
unomi:
image: apache/unomi:3.0.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
links:
- elasticsearch
depends_on:
- elasticsearch
Start the environment
From the same directory, run:
docker compose up
Verify the cluster
Open your browser and navigate to:
https://localhost:9443/cxs/cluster
Default credentials: karaf / karaf. Accept the self-signed certificate warning — it is expected in development mode.
You can also verify Elasticsearch is running:
curl http://localhost:9200/_cat/health?format=json
Manual Installation
Prefer running Unomi directly on your machine? Follow these steps.
Prerequisites
- Java 17 or later — set
JAVA_HOMEaccordingly. OpenJDK distributions work fine. - Elasticsearch 7.17.x — Download 7.17.5
1. Configure & start Elasticsearch
After extracting Elasticsearch, edit config/elasticsearch.yml:
cluster.name: contextElasticSearch
Then start it:
bin/elasticsearch
2. Download & start Apache Unomi
Download the latest binary from the download page, extract it, then:
# Start Apache Karaf
./bin/karaf
# In the Karaf shell, start Unomi
karaf@root()> unomi:start
Wait until you see the service initialization messages:
Initializing profile service endpoint...
Initializing cluster service endpoint...
3. Verify
Open https://localhost:9443/cxs/cluster (credentials: karaf/karaf).
Request your first context:
http://localhost:8181/cxs/context.json?sessionId=1234
ssh -p 8102 karaf@localhost (password: karaf) for useful commands like profile-list, event-tail, and rule-list.
Your First API Calls
With Unomi running, let’s explore the REST API using curl.
Read the current context
The /cxs/context.json endpoint is the primary public-facing endpoint. It returns the current visitor’s profile, session, segments, and scores:
curl -X POST http://localhost:8181/cxs/context.json?sessionId=1234 \
-H "Content-Type: application/json" \
--data-raw '{
"source": {
"itemId": "homepage",
"itemType": "page",
"scope": "example"
},
"requiredProfileProperties": ["*"],
"requiredSessionProperties": ["*"],
"requireSegments": true,
"requireScores": true
}'
Create a scope
Events in Unomi must be associated with a scope. Create one before sending events:
curl -X POST http://localhost:8181/cxs/scopes \
-u karaf:karaf \
-H "Content-Type: application/json" \
--data-raw '{
"itemId": "my-website",
"itemType": "scope",
"metadata": {
"id": "my-website",
"name": "My Website Scope"
}
}'
Send a custom event
Before sending a custom event, register a JSON Schema to validate it (required since Unomi 2.x):
curl -X POST http://localhost:8181/cxs/jsonSchema \
-u karaf:karaf \
-H "Content-Type: application/json" \
--data-raw '{
"$id": "https://unomi.apache.org/schemas/json/events/contactInfoSubmitted/1-0-0",
"$schema": "https://json-schema.org/draft/2019-09/schema",
"self": {
"vendor": "org.apache.unomi",
"name": "contactInfoSubmitted",
"format": "jsonschema",
"target": "events",
"version": "1-0-0"
},
"title": "contactInfoSubmittedEvent",
"type": "object",
"allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/event/1-0-0" }],
"properties": {
"source": { "$ref": "https://unomi.apache.org/schemas/json/item/1-0-0" },
"target": { "$ref": "https://unomi.apache.org/schemas/json/item/1-0-0" },
"properties": {
"type": "object",
"properties": {
"firstName": { "type": ["null", "string"] },
"lastName": { "type": ["null", "string"] },
"email": { "type": ["null", "string"] }
}
}
},
"unevaluatedProperties": false
}'
Now send the event via the event collector (the public endpoint for submitting events):
curl -X POST http://localhost:8181/cxs/eventcollector \
-H "Content-Type: application/json" \
--data-raw '{
"sessionId": "1234",
"events": [{
"eventType": "contactInfoSubmitted",
"scope": "my-website",
"source": {
"itemType": "site",
"scope": "my-website",
"itemId": "mysite"
},
"target": {
"itemType": "form",
"scope": "my-website",
"itemId": "contactForm"
},
"properties": {
"firstName": "Jane",
"lastName": "Doe",
"email": "jane.doe@example.com"
}
}]
}'
Search events
Retrieve events matching a condition:
curl -X POST http://localhost:8181/cxs/events/search \
-u karaf:karaf \
-H "Content-Type: application/json" \
--data-raw '{
"offset": 0,
"limit": 20,
"sortby": "timeStamp:desc",
"condition": {
"type": "eventPropertyCondition",
"parameterValues": {
"propertyName": "properties.firstName",
"comparisonOperator": "equals",
"propertyValue": "Jane"
}
}
}'
View a profile
Use the profile UUID (from the context-profile-id cookie or event response) to look up profile details:
curl http://localhost:8181/cxs/profiles/PROFILE_UUID \
-u karaf:karaf
event-tail watches events in real time, event-list shows recent events, profile-list lists recently modified profiles, profile-view PROFILE_UUID shows profile details.
Web Tracking Tutorial
Integrate the built-in Unomi web tracker into any web page to automatically collect page views and enable personalization.
Add the tracker to your page
Include the tracker script and initialize it:
<!-- Load the Unomi web tracker -->
<script src="/tracker/unomi-web-tracker.min.js"></script>
<script>
(function () {
var conf = {
"scope": "my-website",
"site": {
"siteInfo": { "siteID": "my-website" }
},
"page": {
"pageInfo": {
"pageID": "home",
"pageName": document.title,
"pagePath": document.location.pathname,
"destinationURL": document.location.origin + document.location.pathname,
"language": "en",
"categories": [],
"tags": []
},
"attributes": {},
"consentTypes": []
},
"events:": [],
"wemInitConfig": {
"contextServerUrl": document.location.origin,
"timeoutInMilliseconds": "1500",
"contextServerCookieName": "context-profile-id",
"activateWem": true,
"trackerSessionIdCookieName": "my-website-session-id",
"trackerProfileIdCookieName": "my-website-profile-id"
}
};
// Generate a new session if needed
if (unomiWebTracker.getCookie(conf.wemInitConfig.trackerSessionIdCookieName) == null) {
unomiWebTracker.setCookie(conf.wemInitConfig.trackerSessionIdCookieName, unomiWebTracker.generateGuid(), 1);
}
unomiWebTracker.initTracker(conf);
unomiWebTracker._registerCallback(function() {
console.log("Unomi context loaded:", unomiWebTracker.getLoadedContext());
}, 'My callback');
unomiWebTracker.startTracker();
})();
</script>
Using the tracker as an NPM package
For JavaScript/TypeScript projects, install the tracker from npm:
npm install apache-unomi-tracker
# or
yarn add apache-unomi-tracker
Then import and use it:
import { useTracker } from "apache-unomi-tracker";
const unomiWebTracker = useTracker();
// ... configure and start as shown above
Rules & Personalization
Rules let Unomi react to events in real time — updating profiles, triggering actions, or integrating with external systems.
Create a rule that counts page views
This rule increments a pageViewCount property on the visitor’s profile every time a view event is received:
curl -X POST http://localhost:8181/cxs/rules \
-u karaf:karaf \
-H "Content-Type: application/json" \
--data-raw '{
"metadata": {
"id": "viewEventRule",
"name": "View event rule",
"description": "Increments pageViewCount on each page view"
},
"condition": {
"type": "eventTypeCondition",
"parameterValues": {
"eventTypeId": "view"
}
},
"actions": [{
"type": "incrementPropertyAction",
"parameterValues": {
"propertyName": "pageViewCount"
}
}]
}'
After creating this rule, reload your tracked page a few times, then check the profile with profile-view PROFILE_UUID in the SSH console to see the counter increase.
Map event data to a profile
This rule listens for the contactInfoSubmitted event (from Step 3) and copies its properties to the profile:
curl -X POST http://localhost:8181/cxs/rules \
-u karaf:karaf \
-H "Content-Type: application/json" \
--data-raw '{
"metadata": {
"id": "setContactInfo",
"name": "Copy contact info to profile",
"description": "Maps firstName, lastName, email from event to profile"
},
"condition": {
"type": "eventTypeCondition",
"parameterValues": {
"eventTypeId": "contactInfoSubmitted"
}
},
"actions": [
{
"type": "setPropertyAction",
"parameterValues": {
"setPropertyName": "properties(firstName)",
"setPropertyValue": "eventProperty::properties(firstName)",
"setPropertyStrategy": "alwaysSet"
}
},
{
"type": "setPropertyAction",
"parameterValues": {
"setPropertyName": "properties(lastName)",
"setPropertyValue": "eventProperty::properties(lastName)",
"setPropertyStrategy": "alwaysSet"
}
},
{
"type": "setPropertyAction",
"parameterValues": {
"setPropertyName": "properties(email)",
"setPropertyValue": "eventProperty::properties(email)",
"setPropertyStrategy": "alwaysSet"
}
}
]
}'
Personalize content based on a profile property
Using the web tracker, you can register personalization rules that show different content based on profile data. For example, show a special message after 5 page views:
<div id="variant1" style="display:none">
Welcome back! You've visited this page over 5 times.
</div>
<div id="variant2" style="display:none">
Welcome! Keep exploring to unlock personalized content.
</div>
<script>
var variants = {
"var1": { content: "variant1" },
"var2": { content: "variant2" }
};
unomiWebTracker.registerPersonalizationObject({
"id": "pageViewPersonalization",
"strategy": "matching-first",
"strategyOptions": { "fallback": "var2" },
"contents": [{
"id": "var1",
"filters": [{
"condition": {
"type": "profilePropertyCondition",
"parameterValues": {
"propertyName": "properties.pageViewCount",
"comparisonOperator": "greaterThan",
"propertyValueInteger": 5
}
}
}]
}, {
"id": "var2"
}]
}, variants, false, function (successfulFilters, selectedFilter) {
if (selectedFilter) {
document.getElementById(selectedFilter.content).style.display = '';
}
});
</script>
The personalization engine evaluates conditions server-side against the visitor’s profile and returns which variant to display, keeping your business logic private.
Next Steps
You now have a working Unomi environment with event tracking, profile management, rules, and personalization. Here’s where to go next.
Full Documentation
Dive deeper into segmentation, scoring, conditions, and actions in the comprehensive manual.
Read the manualREST API Reference
Explore every endpoint for profiles, events, segments, rules, and more.
Browse the APIIntegrations
See how organizations use Unomi with CMS, CRM, e-commerce, and other platforms.
View integrationsGet Help
Stuck? The community is friendly and responsive on the mailing list and Slack.
Join the communityDebugging Tip
Enable debug logging via the Karaf SSH console to see detailed event validation and rule execution logs:
# Connect to Karaf SSH console
ssh -p 8102 karaf@localhost
# Enable schema validation debug logs
karaf@root()> log:set DEBUG org.apache.unomi.schema.impl.SchemaServiceImpl
# Watch logs in real-time
karaf@root()> log:tail
Useful commands: event-tail, event-list, rule-list, rule-tail, profile-list, profile-view <ID>