{
// About the event
"eid": , // Required.
"ets": , // Required. Epoch timestamp of event (time in milli-seconds. For ex: 1442816723)
"ver": , // Required. Version of the event data structure, currently "3.0"
"mid": , // Required. Unique message ID. Used for deduplication, replay and update indexes
// Who did the event
"actor": { // Required. Actor of the event.
"id": , // Required. Can be blank. Id of the actor. For ex: uid incase of an user
"type": // Required. Can be blank. User, System etc.
},
// Context of the event
"context": { // Required. Context in which the event has occured.
"channel": , // Required. Channel which has produced the event
"pdata": { // Optional. Producer of the event
"id": , // Required. unique id assigned to that component
"pid": , // Optional. In case the component is distributed, then which instance of that component
"ver": // Optional. version number of the build
},
"env": , // Required. Unique environment where the event has occured.
"sid": , // Optional. session id of the requestor stamped by portal
"did": , // Optional. uuid of the device, created during app installation
"cdata": [{ // Optional. correlation data
"type":"", // Required. Used to indicate action that is being correlated
"id": "" // Required. The correlation ID value
}],
"rollup": { // Optional. Context rollups example: Organization heirarchy("L1": "Parent org id", "l2": "sub org id")
"l1": "",
"l2": "",
"l3": "",
"l4": ""
}
},
// What is the target of the event
"object": { // Optional. Object which is the subject of the event.
"id": , // Required. Id of the object. For ex: content id incase of content
"type": , // Required. Type of the object. For ex: "Content", "Community", "User" etc.
"ver": , // Optional. version of the object
"rollup": { // Optional. Rollups to be computed of the object. Only 4 levels are allowed. example: Textbook heirarchy("L1": "Parent node id", "l2": "Child node id")
"l1": "",
"l2": "",
"l3": "",
"l4": ""
}
},
// What is the event data
"edata": {} // Required.
// Tags
"tags": [""] // Optional. Encrypted dimension tags passed by respective channels
}
- START - Start of a multi step activity. For ex: Session, App, Tools, Community etc would have start and end
- END - End of a work flow
- IMPRESSION - A visit to a specific page by an user
- INTERACT - User interaction on the page (such as search, click, preview, move, resize, configure)
- ASSESS - An assessment has happened during content play
- RESPONSE - To capture an user response. For ex: Responded to a poll or a calendar event or a question
- INTERRUPT - An interrupt trigged to the app (such as mobile app sent to background)
- FEEDBACK - Feedback provided
- SHARE - When any share happens. For ex: Share content, telemetry data, link, file etc
- AUDIT - When an object is changed. This includes lifecycle changes as well.
- ERROR - When an error has occured
- HEARTBEAT - An heart beat event to denote that the process is running.
- LOG - Generic log event. API call, Service call, app update etc
- SEARCH - A search is triggered (content, item, asset etc)
- METRICS - Service business metrics (also accessible via health API)
- SUMMARY - A summary event
- EXDATA - A generic wrapper event to capture encrypted/serialized data
Here is the standard flow of events in the stack for a mobile application:
START(type: "app")
...| --> app events such as IMPRESSION, FEEDBACK, etc may happen
START(type: "session")
...
| --> IMPRESSION - For the pages that the user visits
| --> INTERACT --> one of the content is clicked
| --> START(type: "player") --> events generated by specific content
...|
...| --> in-content events such as ASSESS, INTERACT, IMPRESSION, LEVEL_SET etc.
...|
| --> END(type: "player")
| --> IMPRESSION - Returned back to mobile app for content player
...| --> app events such as IMPRESSION, INTERACT, etc. may happen
| --> INTERACT --> one of the content is clicked
| --> START(type: "player") --> events generated by specific content
...|
...| --> in-content events such as ASSESS, INTERACT, IMPRESSION, LEVEL_SET etc.
...|
| --> END(type: "player")
| --> IMPRESSION - Returned back to mobile app for content player
...| --> app events such as IMPRESSION, INTERACT, etc. may happen
END(type: "session")
...| --> app events such as APP_UPDATE, FEEDBACK, etc may happen
END(type: "app")
Here is the standard flow of events in the portal stack:
AUDIT (object: user) --> (Optional if a user is created for the first time)
START(type: "session") --> User session starts
...
| --> IMPRESSION - For the pages that the user visits
| --> INTERACT - For the interactions on the page
// there is no explicit logout/timeout
Sample flow to find out when assets are added or removed
START (type: "session") - User logs in
...
| --> IMPRESSION (Portal) - User visits content creation page (cdata session)
| --> INTERACT (Portal) - User initiates content creation
| --> AUDIT (Platform) - User creates a new content
| --> START (type: "editor", mode: "content")
...
| --> INTERACT (Editor) - In editor, user is loading the asset browser
| --> SEARCH (Platform) - In AT, user is searching for assets (cdata session, search result id)
| --> PLUGIN_LIFECYCLE (Editor) - User selects the asset for content (which search result was used)
| --> PLUGIN_LIFECYCLE (Editor) - User removes the asset from content
| --> INTERACT (Editor) - User clicks save in AT
| --> ACCESS (Platform) - Platform save API is called
| --> INTERACT (Editor) - User clicks on submit to review
| --> AUDIT (object: Content, state: "Review", prevstate: "Draft") - Platform sends the content to review state
| --> END (type: "editor", mode: "content") - User closes the editor and goes back to portal
AUDIT (object: Service, state: "Ready") --> State transition to READY
...| --> ACCESS events for API requests
ACCESS
LOG --> Log events in the context of the incoming request (by request correlation ID)
...
METRICS --> Health/business metrics (e.g. number of jobs executed)
AUDIT (object: Service, state: "Stopped") --> State transition to STOPPED
Here is the standard flow of events in the analytics job stack:
JOB_START --> Data product job start
...
| --> JOB_LOG - To log some data while Data product job is in progress
...
JOB_END --> Data product job end
Following sections provide exact event specific structures edata
for all events. Generic envelope is defined here.
// Device Specification
DSPEC = {
"os": "", // OS name and version
"make": "", // device make and model
"id": "", // physical device id if available from OS
"mem": , // total mem in MB, -1 if unknown
"idisk": , // total internal disk in GB, -1 if unknown
"edisk": , // total external disk (card) in GB, -1 if unknown
"scrn": , // screen size in inches, -1 if unknown
"camera": "13,1.3", // primary and secondary camera specs
"cpu": "", // processor name
"sims" , // number of sim cards, -1 if unknown
"cap": []
}
UASPEC = {
"agent": "Mozilla", // which user agent (mozilla, chrome, safari, ie)
"ver": "5.0", // Agent version number
"system": "iPad; U; CPU OS 3_2_1 like Mac OS X; en-us" // System identification
"platform": "AppleWebKit/531.21.10" // client platform,
"raw": "Mozilla\/5.0 (X11; Linux x86_64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/57.0.2987.98 Safari\/537.36" // Raw user agent of server
}
OBJECT = {
"id": "", // Required. unique id for the object type
"type": "", // Required. Object Type - Tag, User, Partner, Content, Item, Asset
"ver": "", // Required. Version of the object
"subtype": "", // Optional. Sub type for each respective type. For ex: for Content - Story/Worksheet/Resource etc.
"name": "", // Optional. Name of the object eg: Name of the partner or user or content
"code": "", // Optional. unique code for the object
"parent": {
"id": "", // Optional. parent id of the object
"type": "" // Optional. parent type of the object. Required if parentid is present.
}
}
TARGET = {
"id": "", // Required. unique id for the target
"ver": "", // Required. version of the target
"type": "", // Required. Type of the target
"parent": {
"id": "", // Optional. parent id of the object
"type": "" // Optional. parent type of the object. Required if parentid is present.
}
}
PLUGIN = {
"id": "", // Required. unique id for the plugin. For ex: org.ekstep.text
"ver": "", // Required. version of the plugin
"category": "" // Optional. Category of the plugin. For ex: "core", "library", "numeracy" etc
}
VISIT = {
"objid": "", // Required. unique id for the object visited
"objtype": "", // Required. Type of the object visited
"objver": "", // Optional. version of the object visited
"section": "", // Optional. Free flowing text
"index": // Optional. Index of the object within a given list
}
QUESTION = {
"id": "", // unique assessment question id. its an required property.
"type": "", // type of the question. its an optional property.
"maxscore", // user defined score to this assessment/question.
"exlength": , // expected time (decimal number) in seconds that ideally child should take
"params": [ // Array of parameter tuples
{"id":"value"} // for ex: if var1 is substituted with 5 apples the parameter is {"var1":"5"}
],
"uri": "", // Unique external resource identifier if any (for recorded voice, image, etc.)
"desc": "short description",
"title": "title",
"mmc": [], // User defined missing micros concepts
"mc": [] // micro concepts list
}
{
"edata": {
"type": "", // Required. app, session, editor, player, workflow, assessment
"dspec": DSPEC, // Optional. Device spec
"uaspec": UASPEC, // Optional. User agent spec
"loc": "", // Optional. Location of the device
"mode": "", // Optional. Mode of start. For "player" it would be "play/edit/preview". For Workflow it would be Review/Flag/Publish. For editor it could be "content", "textbook", "generic", "lessonplan" etc
"duration": , // Optional. Time taken to initialize/start
"pageid": "" // Optional. Page/Stage id where the start has happened.
}
}
{
"edata": {
"type": , // Required. app, session, editor, player, workflow, assessment
"mode": "", // Optional. Mode of start. For "player" it would be "play/edit/preview". For Workflow it would be Review/Flag/Publish. For editor it could be "content", "textbook", "generic", "lessonplan" etc
"duration": , // Optional. Total duration from start to end in seconds
"pageid": "", // Optional. Page/Stage id where the end has happened.
"summary": [{"key":"value"}] // Optional. Summary of the actions done between start and end. For ex: "progress" for player session, "nodesModified" for collection editor
}
}
{
"edata": {
"type": "", // Required. Impression type (list, detail, view, edit, workflow, search)
"subtype": "", // Optional. Additional subtype. "Paginate", "Scroll"
"pageid": "", // Required. Unique page id
"uri": "", // Required. Relative URL of the content
"duration": , // Optional. Time taken to render the page/stage in seconds
"visits": [VISIT] // Optional. Capture the object visits
}
}
{
"edata": {
"type": "", // Required. Type of interaction CLICK,TOUCH,DRAG,DROP,PINCH,ZOOM,SHAKE,ROTATE,SPEAK,LISTEN,WRITE,DRAW,START,END,CHOOSE,ACTIVATE,SHOW,HIDE,SCROLL,HEARTBEAT,OTHER
"subtype": "", // Optional. Additional types for a global type. For ex: for an audio the type is LISTEN and thesubtype can be one of PLAY,PAUSE,STOP,RESUME,END
"id": "", // Required. Resource (button, screen, page, etc) id on which the interaction happened - use systemidentifiers when reporting device events
"pageid": "", // Optional. Stage or page id on which the event happened
"target": TARGET, // Optional. Target context where the interaction has happened
"duration": , // Optional. Time taken to interact on object in seconds
"plugin": PLUGIN, // Optional. Plugin on which the interaction has happend
"extra": { // Optional. Extra attributes for an interaction
"pos": [{"x":,"y":,"z":}], // Array of positional attributes. For ex: Drag and Drop has two positional attributes. One where the drag has started and the drop point
"values": [], // Array of values, e.g. for timestamp of audio interactions
}
}
}
{
"edata": {
"item": QUESTION, // Required. Question Data
"index": , // Optional. Index of the question within a content.
"pass": "", // Required. Yes, No. This is case-sensitive. default value: No.
"score": , // Required. Evaluated score (Integer or decimal) on answer(between 0 to 1), default is 1 if pass=YES or 0 if pass=NO.
"resvalues": [{"id":"value"}], // Required. Array of key-value pairs that represent child answer (result of this assessment)
"duration": // Required. time taken (decimal number) for this assessment in seconds
}
}
{
"edata": {
"target": TARGET, // Required. Target of the response
"type": "", // Required. Type of response. CHOOSE, DRAG, SELECT, MATCH, INPUT, SPEAK, WRITE
"values": [{"key":"value"}] // Required. Array of response tuples. For ex: if lhs option1 is matched with rhs optionN - [{"lhs":"option1"}, {"rhs":"optionN"}]
}
}
Examples
- Responding to a question
{
"object": {
"id": "content101",
"type": "content",
"hrchy": {
"l1": "textbook101",
"l2": "course101",
"l3": "curriculumA"
}
}
"edata": {
"target": {
"id": "q-101",
"type": "AssessmentItem",
"parent": {
}
}, // Required. Question Data
"type": "SELECT", // Required. Type of response. CHOOSE, DRAG, SELECT, MATCH, INPUT, SPEAK, WRITE
"values": [{"state":"selected", "option": "A"}] // Required. Array of response tuples. For ex: if lhs option1 is matched with rhs optionN - [{"lhs":"option1"}, {"rhs":"optionN"}]
}
}
- Responding to a poll
{
"object": {
"id": "community101",
"type": "Community",
"hrchy": {
"l1": "poll101",
"l2": "thread202",
"l3": "forum211"
}
}
"edata": {
"target": {
"id": "p101",
"type": "Poll",
"parent": {
"id": "thread202",
"type": "ForumThread"
}
}, // Required. Question Data
"type": "MATCH", // Required. Type of response. CHOOSE, DRAG, SELECT, MATCH, INPUT, SPEAK, WRITE
"values": [{"state":"selected", "option": "A"}] // Required. Array of response tuples. For ex: if lhs option1 is matched with rhs optionN - [{"lhs":"option1"}, {"rhs":"optionN"}]
}
}
- Responding to a calendar event (rsvp)
{
"object": {
"id": "community101",
"type": "Community"
"hrchy": {
"l1": "cal101"
}
},
"edata": {
"target": {
"id": "event101",
"type": "Event",
"parent": {
"id": "cal101",
"type": "Calendar"
}
}, // Required. Question Data
"type": "CHOOSE", // Required. Type of response. CHOOSE, DRAG, SELECT, MATCH, INPUT, SPEAK, WRITE
"values": [{"state": "selected", "option":"Rejected/Decline", "reason": "Conflicting schedule"}] // Required. Array of response tuples. For ex: if lhs option1 is matched with rhs optionN - [{"lhs":"option1"}, {"rhs":"optionN"}]
}
}
{
"edata": {
"type": "", // Required. [m:background, m:resume]
"pageid": "" // Optional. Page id where the interrupt has happened
}
}
{
"edata": {
"rating": 3, // Optional. Numeric score (+1 for like, -1 for dislike, or 4.5 stars given in a rating)
"comments": "User entered feedback" // Optional. Text feedback (if any)
}
}
{
"edata": {
"dir": "", // In/Out
"type": "", // File/Link/Message
"items": [{ // Required. array of items shared
"id": "",
"type": "",
"ver": ""
"params": [
{"key": "value"}
}],
"origin": { // Origin of the share file/link/content
"id": "", // Origin id
"type": "" // Origin type
},
"to": {
"id": "",
"type": ""
}
}]
}
}
Examples
- Export content on app
{
"edata": {
"dir": "out",
"type": "File",
"items": [{
"id": "numeracy_377",
"type": "Content",
"ver": "11",
"params": [
{"transfers": "3"},
{"size": "23456.0"}
],
"origin": {
"id": "0fca12d5-9b4f-48ea-89bc-31220f78f14a",
"type": "Device"
}
}, {
"id": "numeracy_398",
"type": "Content",
"ver": "5",
"params": [
{"transfers": "7"},
{"size": "23456.0"}
],
"origin": {
"id": "0fca12d5-9b4f-48ea-89bc-31220f78f14a",
"type": "Device"
}
}]
}
}
- Import content on app
{
"edata": {
"dir": "in",
"type": "File",
"items": [{
"id": "numeracy_377",
"type": "Content",
"ver": "11",
"origin": {
"id": "0fca12d5-9b4f-48ea-89bc-31220f78f14a",
"type": "Device"
}
}, {
"id": "numeracy_398",
"type": "Content",
"ver": "5",
"origin": {
"id": "0fca12d5-9b4f-48ea-89bc-31220f78f14a",
"type": "Device"
}
}]
}
}
- Download content on app
{
"edata": {
"dir": "in",
"type": "File",
"items": [{
"id": "numeracy_377",
"type": "Content",
"ver": "11"
}]
}
}
- Export profile on app
{
"edata": {
"dir": "out",
"type": "File",
"items": [{
"id": "user1",
"type": "User",
"origin": {
"id": "0fca12d5-9b4f-48ea-89bc-31220f78f14a",
"type": "Device"
}
}, {
"id": "user999",
"type": "User",
"origin": {
"id": "0fca12d5-9b4f-48ea-89bc-31220f78f14a",
"type": "Device"
}
}]
}
}
- Import profile on app
{
"edata": {
"dir": "in",
"type": "File",
"items": [{
"id": "user1",
"type": "User",
"origin": {
"id": "0fca12d5-9b4f-48ea-89bc-31220f78f14a",
"type": "Device"
}
}, {
"id": "user999",
"type": "User",
"origin": {
"id": "0fca12d5-9b4f-48ea-89bc-31220f78f14a",
"type": "Device"
}
}]
}
}
- Export telemetry on app
{
"edata": {
"dir": "out",
"type": "File",
"items": [{
"id": "telemetry1",
"type": "Telemetry",
"params": [
{"count": "70"},
{"size": "23456.0"}
],
"origin": {
"id": "0fca12d5-9b4f-48ea-89bc-31220f78f14a",
"type": "Device"
}
}]
}
}
- Share link
{
"edata": {
"dir": "in",
"type": "Link",
"items": [{
"obj": {
"id": "numeracy_377",
"type": "Content"
},
"params": [
{"link": "https://community.ekstep.in/content/numeracy_377"}
]
}]
}
}
- Share Post
{
"edata": {
"dir": "out",
"type": "Message",
"items": [{
"obj": {
"id": "thread101",
"type": "ForumThread"
},
"to": {
"id": "comm202",
"type": "Community"
}
}]
}
}
{
"edata": {
"props": [""], // Updated properties
"state": "", // Optional. Current state
"prevstate": "", // Optional. Previous state
"duration": // Optional. Duration or time taken in seconds to change from prevstate to current state. Should only be passed if the state has truly changed
}
}
{
"edata": {
"err": "", // Required. Error code
"errtype": "", // Required. Error type classification - "SYSTEM", "MOBILEAPP", "CONTENT"
"stacktrace": "", // Required. Detailed error data/stack trace
"pageid": "", // Optional. Page where the error has occured
"object": OBJECT, // Optional. Object on which the error occured
"plugin": PLUGIN // Optional. Plugin in which the error occured
}
}
{
"edata": {
}
}
{
"edata": {
"type": "", // Required. Type of log (system, process, api_access, api_call, job, app_update etc)
"level": "", // Required. Level of the log. TRACE, DEBUG, INFO, WARN, ERROR, FATAL
"message": "", // Required. Log message
"pageid": "", // Optional. Page where the log event has happened
"params": [{"key":"value"}] // Optional. Additional params in the log message
}
}
Exaples
- Simple log
- API log when being accessed
{
"edata": {
"type": "api_access",
"level": "INFO",
"message": "",
"params": [
{"rid": "org.ekstep.search"}, // Resource being accessed
{"uip": "10.0.0.7"}, // User IP address (if available) - server will anonymize
{"title": "Search API"}, // Title of the resource for analytics (e.g. the page title)
{"category": "contentsearch"}, // Categorization of the event
{"url": "/content/search"}, // Categorization of the event
{"size": "3333"}, // Size of the response in bytes
{"duration": "333"}, // Response time in ms
{"status": "200"}, // Response code (use standard protocol codes - e.g. 200, 404)
{"protocol": "http"}, // Protocol of access (http, or others such as messaging/Akka calls)
{"method": "GET"}, // Protocol specific method (e.g. GET/POST)
{"req": ""} // Serialized request
]
}
}
Please note:
- The search is not indexed as it might contain PII
- The search is available as an exhaust post anonymization
{
"edata": {
"type": "",
"query": "", // Required. Search query string
"filters": {}, // Optional. Additional filters (see the API spec)
"sort": {}, // Optional. Additional sort parameters
"correlationid": "", // Optional. Server generated correlation id (for mobile app's telemetry)
"size": 333, // Required. Number of search results
"topn": [{}] // Required. top N (configurable) results with their score
}
}
{
"edata": {
"metric1": Int,
"metric2": Int
/// more metrics, each is a key value
}
}
{
"edata": {
"type": "", // Required. Type of summary. Free text. "session", "app", "tool" etc
"mode": "", // Optional.
"starttime": Long, // Required. Epoch Timestamp of app start. Retrieved from first event.
"endtime": Long, // Required. Epoch Timestamp of app end. Retrieved from last event.
"timespent": Double, // Required. Total time spent by visitor on app in seconds excluding idle time.
"pageviews": Long, // Required. Total page views per session(count of CP_IMPRESSION)
"interactions": Long, // Required. Count of interact events
"envsummary": [{ // Optional
"env": String, // High level env within the app (content, domain, resources, community)
"timespent": Double, // Time spent per env
"visits": Long // count of times the environment has been visited
}],
"eventssummary": [{ // Optional
"id": String, // event id such as CE_START, CE_END, CP_INTERACT etc.
"count": Long // Count of events.
}],
"pagesummary": [{ // Optional
"id": String, // Page id
"type": String, // type of page - view/edit
"env": String, // env of page
"timespent": Double, // Time taken per page
"visits": Long // Number of times each page was visited
}]
}
}
{
"edata": {
"type": "", // Free flowing text. For ex: partnerdata, xapi etc
"data": "" // Serialized data (can be either encrypted/encoded/stringified)
}
}