The functionality described in this CEL analytics guide is deprecated. All new Cumulocity installations will use the Apama CEP engine. Software AG will terminate support for using CEL (Esper) in Cumulocity IoT on 31 Dec 2020 following its deprecation in 2018.

For further information on using Apama's Event Processing Language in Cumulocity refer to the Streaming Analytics guide.

For details on migration, refer to Migrating from CEL (Esper) to Apama in the Streaming analytics guide.

About this guide

The CEL analytics guide consists of the following sections:


Using the Cumulocity real-time event processing, you can add your own logic to your IoT solution. This includes data analytics logic but it is not limited to it. To define new analytics, you can use the Cumulocity Event Language. The language allows analyzing incoming data. It is using a powerful pattern and time window based query language. You can create, update and delete your data in real-time.

Typical real-time analytics use cases include:

In the following sections, we describe the basics for understanding how the Cumulocity Event Language works and how you can create your own analytics or other server-side business logic and automation.

CEP application variants

In Cumulocity, there are two deployment scenarios for using CEP rules:

For details on application subscription refer to Administration > Managing tenants > Subscribing to applications in the User guide.

Using Cumulocity Event Language (CEL)

Cumulocity Event Language has a syntax similar to SQL language. In SQL a statement is run against a logically fixed database, produces a result and completes the task. In Cumulocity, a statement is continuously running against a stream of input data (input events) and is continuously calculating its output (output events).

As an example, the following statement continuously retrieves new temperature sensor readings ranging above a particular temperature:

select *
from MeasurementCreated e
where getNumber(e, "c8y_TemperatureMeasurement.T.value") > 100

Here, MeasurementCreated is a stream containing an event for each measurement that is created in the system. Selecting a subset of these events is done using where, similar to SQL. getNumber() is a function to read out a numeric value from an event. In this example, “e” is the “MeasurementCreated” event and the property is “c8y_TemperatureMeasurement”. “T.value”, is a value in degrees Celsius of a temperature sensor (see the sensor library).

How can I create derived data from CEL?

There are special streams provided by the system to perform predefined operations (such as data storage or sending data by email). One stream is CreateAlarm, which can be used to store an alarm in Cumulocity. Assume that an alarm should be generated immediately if the temperature of a sensor exceeds a defined value. This is done with the following statement:

insert into CreateAlarm
 e.measurement.time as time,
 e.measurement.source.value as source,
 "c8y_TemperatureAlert" as type,
 "Temperature too high" as text,
 "ACTIVE" as status,
 "CRITICAL" as severity
from MeasurementCreated e
where getNumber(e, "c8y_TemperatureMeasurement.T.value") > 100

Technically, this statement produces a new “AlarmCreated” event each time a temperature sensor reads more than 100 degrees Celsius and puts it into the “CreateAlarm” output stream. The property names in the selected clause have to match the properties of “AlarmCreated” (see the Cumulocity Event Language reference).

How can I control devices from CEL?

Remote control in CEL is just another type of derived data. Remote operations are targeted to a specific device. The following example illustrates switching a relay based on temperature readings:

insert into CreateOperation
"PENDING" as status,
<<heating ID>> as deviceId,
"c8y_Relay.relayState", "CLOSED"
} as fragments
from MeasurementCreated e
where getNumber(e, "c8y_TemperatureMeasurement.T.value") > 100

The syntax of the fragments part is a list of pairs of property names and values surrounded by curly braces: {?key1?, ?value1?, ?key2?, ?value2?, …}.

How can I query data from CEL?

It may be required to query information from the Cumulocity database as part of the ongoing event processing. This is supported by a set of querying methods. Here is an example that shows how to summarize total sales for vending machines every hour. The sales report data created after a purchase is retrieved from the Cumulocity database.

create window hour)  
    event com.cumulocity.model.event.Event,
    customer com.cumulocity.model.ManagedObject

insert into SalesReport
    e.event as event,
    findOneManagedObjectParent(e.event.source.value) as customer
from EventCreated as e

insert into CreateMeasurement
        "total", count(*),
from SalesReport as sales_report
group by

Above we create a batch window first, which keeps data for one hour in order to calculate a total in this time frame. We store the prepared data into this window: Incoming events along with the parent managed object of the event source. This corresponds to the data model of our vending application: Sales reports are represented as events in Cumulocity with a vending machine as source. Customers are represented as parent managed objects of vending machines.

The collection of sales reports is calculated through “insert into CreateMeasurement…” using a SQL-like syntax and is stored as a measurement. The difference to SQL is: In SQL, you calculate a result over a fixed, current content of a database. In Cumulocity Event Language, statements run endlessly and the process time has to be limited by the time window.

Event streams

In the Cumulocity Event Language data flows in streams. You can create events in streams and listen to events created in streams.

Predefined streams

There are some predefined streams to interact with several Cumulocity APIs. For each input stream, Cumulocity will automatically create a new event when the respective API call was made. If a measurement was created via REST API there will be a new event in the MeasurementCreated stream. For interacting with the Cumulocity backend you can create an event on the respective output stream and Cumulocity will automatically execute either the database query or create the API calls necessary for sending mails, sms, or similar. To create a new alarm in the database you can create a new event in the CreateAlarm stream.

API Input streams Output streams Description
Inventory ManagedObjectCreated
This group of events represents creation, modification or deletion of a single ManagedObject.
Events EventCreated
This group of events represents creation or deletion of a single Event.
Measurements MeasurementCreated
This group of events represents creation or deletion of a single Measurement.
Device control OperationCreated
This group of events represents creation or modification of a single Operation.
Alarms AlarmCreated
This group of events represents creation or modification of a single Alarm.
Emails (not used) SendEmail
This group of events represents sending of an email.
SMS (not used) SendSms This group of events represents sending of a SMS.
HTTP ResponseReceived SendReqeust This group of events represents sending http requests to external services.
Export (not used) SendExport This group of events represents generating emails with exported data.

Look at the data model to see how the events for each stream are structured.

Creating events in a stream

Creating an event is done by the keywords insert into and select. First, you need to specify the “insert into” followed by the stream name for which stream you want to create an event. After that you can use the “select” clause to specify the parameters of the event. A parameter gets specified by the following syntax: value as parameter. You can specify multiple parameters by separating them by commas. The order of the parameters does not matter. Please notice that streams can have mandatory parameters you need to specify in the “select” clause.

Listening to events in a stream

The most common way to trigger the creation of an event in a stream is when something happens on another stream. Therefore you can listen to events from other streams. This is done by the keyword from followed by the name of the stream and (optional) followed by a variable name to reference the event in your statement at a later point.


Adding conditions can be done with the keyword where to not trigger your event creation for every incoming event but only if these conditions are met. The where keyword is followed by an expression that results either in true or false. You can also have multiple expressions connected with and or or.


As an example, we create a statement. It should listen to a stream and create a new event in another stream whenever the specified condition applies. As example we want to create an alarm for each temperature measurement that is created.

  1. To create an alarm we need to insert into the stream CreateAlarm.
  2. We need to specify all parameters for the event in the select clause.
  3. We want the alarm to be created when an event from the stream MeasurementCreated is received.
  4. We want the alarm only be created under certain conditions of the event from the MeasurementCreated stream which we specify in the where clause.

The resulting statement can look like this:

insert into CreateAlarm
  measurementEvent.measurement.time as time,
  measurementEvent.measurement.source.value as source,
  "c8y_TemperatureAlarm" as type,
  "Temperature measurement was created" as text,
  "ACTIVE" as status,
  "CRITICAL" as severity
from MeasurementCreated measurementEvent
where measurementEvent.measurement.type = "c8y_TemperatureMeasurement";


Error message

Real-time event processing is currently overloaded and may stop processing your events. Please contact support.


The CEP queue for the respective tenant is full. This might for example happen when more events are created then currently can be handled.

In this case, an alarm will be raised. To avoid losing incoming new events, the oldest events will be deleted, i.e. an incoming new event triggers the deletion of the queue head event.