Skip to main content
Step 1

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

Step 2 (alternative)

Manual Installation

Prefer running Unomi directly on your machine? Follow these steps.

Prerequisites

  • Java 17 or later — set JAVA_HOME accordingly. OpenJDK distributions work fine.
  • Elasticsearch 7.17.xDownload 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

Step 3

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

Step 4

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

Step 5

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 manual

REST API Reference

Explore every endpoint for profiles, events, segments, rules, and more.

Browse the API

Integrations

See how organizations use Unomi with CMS, CRM, e-commerce, and other platforms.

View integrations

Get Help

Stuck? The community is friendly and responsive on the mailing list and Slack.

Join the community

Debugging 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>