Analytics API
Analytics data is composed of atomic events stored in a form similar to:
{
"store_id": [ "-MeZJMTPL6CJndeZshjd" ],
"controller": [ "SHOWROOM (id:CONTROLLER-I9 ip:192.168.1.100)" ],
"year": [ "2022" ],
"weekday": [ "4" ],
"installation_id": [ "-MiXCxXPdTBwYxgmthGN" ],
"audience_id": [ "-NFSTjOj33xXTDW0WSQV" ],
"ev_action": [ "in" ],
"client_id": [ "-MV1AcMcnZE7_9Knly4F" ],
"ev_category": [ "media" ],
"campaign_name": [ "LIFT Intel" ],
"@timestamp": [ "2022-11-24T14:58:03.034713Z" ],
"month": [ "11" ],
"hour": [ "15" ],
"installation_name": [ "Lift&Learn Installation" ],
"media_idle": [ false ],
"media_id": [ "-MpabW2QVoLFBRIbViun" ],
"store_name": [ "Showroom Store" ],
"audience_name": [ "Axe Gold Temptation" ],
"media_name": [ "Leather&Cookies.jpg" ],
"day": [ "24" ],
"client_name": [ "Broox" ],
"campaign_id": [ "-MpazcBg5z25dCaEYiXW" ]
}
See Event Schema for the current schema.
Broox Studio provides an endpoint to request processed analytics data.
- The URL PATH format is composed of:
- A
clientId, obtained from Broox Studio (e.g.-MV1BcMxnZE7_9Kn3y4F). - A
reportName, a simple keyword to select the report. - Several query parameters to filter the data.
- A
GET /analytics/<clientId>/<reportName>?query_args...`
- The Endpoint URL is:
https://<your-cms-name>.web.app/analytics/ - All requests return Content-type:
application/json - The requests are authenticated via a
Authentication: Bearer <api key>header.
Authentication
-
Go to Broox Studio
-
Edit your client record

-
Copy your
client idandapi key. -
In your requests, add the header:
GET /analytics/<clientId>/<reportName>?query_args...`
Authentication:Bearer API_KEY
Common query parameters
Most common filters is by date range.
btandet. Both should be present.- ISO8601 format:
2020-12-31T00:00:00.000
GET /analytics/-MV1AcMcnZE7_9Knly4F/eventcount?bt=2021-05-01T00:00:00&et=2022-10-01T00:00:00
{
"count": 100
}
IDentifiers and Names
Several filters can be paired as filter_id + filter_name.
While _id fields are unique, _name fields are not necessarily so.
For example campaign_id+campaign_name: You could have two campaigns named "Christmas campaign" with different ids (think christmas campaign of different years, where the user entered the same name).
Also, keep in mind that values present in Broox Studio might not match those present in the events, as the former might have been deleted, altered, etc. The event database is a historical record, not a live one.
See Event Schema for the current schema.
"Keyword" (strict) Filters:
This filters have a limited range of values, and should always use an exact match.
-
Studio Object Identifiers:
store_id:installation_idcampaign_idplaylist_idaudience_id
-
Split dates:
day: 1-31month: 1-12weekday: 0-6hour: 0-24year: 4-digit YYYY (e.g.2022)
-
Event data:
ev_category:media,sensor,profile...ev_action:in,out...
-
Event target (optional, when referred to a profile):
target_type:face,person,blobtarget_action:enter,exit,look...target_gender:MorFtarget_dominant_emotion:happy,sad,neutral...
Boolean filters
Those can use a true/false value.
- For
event_category== "media"media_idle
- For
event_category== "profile"is_view(someone is been looking at the screen long enough).
"Match" (text) filters:
This filters are textual strings, unindexed and matched by substring. In general those should not be used for querying.
-
Studio object names:
client_namestore_nameinstallation_namecontroller(name)campaign_nameplaylist_nameaudience_namemedia_namecanvas_nametrigger_name
-
Vision Node Profile type values:
target_id(a random id given to a face/person/blob)target_age: integer 0-99.target_dwell: Seconds the target has been present.target_distance: (optional, distance to camera)target_attention: (optional, % of dwell_time looking straight to screen)area: (optional, name of an area of detection)
Reports
Reports might contain extra filters/aggregations. Those parameter names are prepended with an underscore character (e.g. _average_field).
Metadata reports
This reports offer the structure and list of available Studio Objects
- campaigns/playlists/installations/audiences
GET /analytics/-MV1AcMcnZE7_9Knly4F/campaigns
{
"-YYYYyyyyyy": "San ValentÃn",
"-XXXX122332": "Navidad"
}
- Collapsed store+campaign
GET /analytics/-MV1AcMcnZE7_9Knly4F/collapsed
{
"-MaXuJ5jZFIwEyLjyfKp": {
"store_name": "Main Store 1",
"installations": {
"-MqzBq3Gz2VseORluDe2": {
"installation_name": "LED Wall",
"campaigns": {
"-YYYYyyyyyy": "San ValentÃn"
},
"audiences": {
"-XXYTYszxz": "Audience 1"
}
},
"-MqzBq3Gz2VseORaaaaa": {
"installation_name": "Kiosk",
"campaigns": {
"-XXXX122332": "Navidad"
},
"audiences": {
"-XXYTYszxz": "Audience 2"
}
}
}
}
}
eventcount
Number of events given a filter range.
GET /analytics/-MV1AcMcnZE7_9Knly4F/eventcount?bt=2021-05-01T00:00:00&et=2022-10-01T00:00:00
{
"count": 100
}
average
- Average of a numeric field values.
- Numeric field to average:
_avgfield=field_name
GET /analytics/-MV1AcMcnZE7_9Knly4F/average?_avgfield=target_dwell&ev_action=out
{ average: 9.890901652255442 }
split
- Count of events split by a keyword field.
- Use the
_splitparameter for the field to split with. - Use the
_split_missingparameter to set a default value when the_splitfield has no value set.
GET /analytics/-MV1AcMcnZE7_9Knly4F/split?bt=2021-05-01T00:00:00&et=2022-10-01T00:00:00&_split=target_gender&_missing=unknown
{
"count": 33040,
"split": [
{
"key": "F",
"doc_count": 8265
},
{
"key": "M",
"doc_count": 8255
}
]
}
Averages over splits
- Use the
_aggregateand_aggregate_fieldparameters. _aggregatecan beavgorsum_aggregate_fieldcan be any numerical field.
GET /analytics/-MV1AcMcnZE7_9Knly4F/split?bt=2021-05-01T00:00:00&et=2022-10-01T00:00:00&_split=weekday&_aggregate=avg&_aggregate_field=target_dwell
{
"count": 33040,
"split": [
{
"key": 4,
"doc_count": 8265,
"average": { "value": 10.23 }
},
{
"key": 5,
"doc_count": 2251,
"average": { "value": 20.12 }
},...
]
}
Multisplit
Split ranges by two fields.
- User
_split0and_split1as split fields. - Optionally, use the
_aggregateand_aggregate_fieldparameters. _aggregatecan beavgorsum_aggregate_fieldcan be any numerical field.- Optionally use the
_split0_missingand_split1_missingparameters to set values in case the field is not populated.
GET /analytics/-MV1AcMcnZE7_9Knly4F/multisplit?_split0=weekday&_split1=target_gender&_split1_missing=Unknown
{
count: 40000,
split: [
{
key: [4, 'M'],
key_as_string: '4|M',
doc_count: 1584,
},
}
Multisplit with ranges
- Report:
multisplit_range - Use
_field_termfor the field to split via values. (e.g. day) - Use
_field_rangesfor the field to split via ranges (e.g. target_age) - Use
_rangeN=min-maxfor the ranges. Note that this aggregation includes theminvalue and excludes themaxvalue for each range. - Optionally,
_rangeN_keyto set a key for the returned dictionary.
GET /analytics/-MV1AcMcnZE7_9Knly4F/multisplit_range?_field_term=day&_field_ranges=target_age&_range1=0-20&_range1_key=Children (0-20)&_range2=21-40...
{ count: 40000,
split: [
{
"key": 25,
"doc_count": 1640,
"split": {
"buckets": {
"Children (0-20)": {
"from": 0,
"to": 20,
"doc_count": 163
},
"Young (21-40)": {
"from": 21,
"to": 40,
"doc_count": 205
},
"Middle Age (41-60)": {
"from": 41,
"to": 60,
"doc_count": 203
},
"Elder (61-99)": {
"from": 61,
"to": 99,
"doc_count": 212
}
}
}
},
ranges split
- Use the
_splitfield for the target field and_split_missingoptionally for missing values. - Use
_rangeN=min-maxfor the ranges. - Optionally,
_rangeN_keyto set a key for the returned dictionary.
GET /analytics/-MV1AcMcnZE7_9Knly4F/ranges?_split=target_age&_range1=0-20&_range1_key=Children (0-20)&_range2=21-40...
{
count: 40000,
split: {
'Children (0-20)': { from: 0, to: 20, doc_count: 3925 },
'Young (21-40)': { from: 21, to: 40, doc_count: 4974 },
'Middle Age (41-60)': { from: 41, to: 60, doc_count: 4955 },
'Elder (61-99)': { from: 61, to: 99, doc_count: 5317 }
}
}
Date Histogram
GET /analytics/-MV1AcMcnZE7_9Knly4F/datehistogram?_interval=1M&_format=yyyy-MM-dd&ev_action=out
[
{ key_as_string: '2021-02-01', key: 1612137600000, doc_count: 43 },
{ key_as_string: '2021-03-01', key: 1614556800000, doc_count: 1879 },
{ key_as_string: '2021-04-01', key: 1617235200000, doc_count: 1622 },
{ key_as_string: '2021-05-01', key: 1619827200000, doc_count: 1658 },
{ key_as_string: '2021-06-01', key: 1622505600000, doc_count: 1813 },
{ key_as_string: '2021-07-01', key: 1625097600000, doc_count: 1871 },
{ key_as_string: '2021-08-01', key: 1627776000000, doc_count: 1784 },
{ key_as_string: '2021-09-01', key: 1630454400000, doc_count: 1849 },
{ key_as_string: '2021-10-01', key: 1633046400000, doc_count: 1906 },
{ key_as_string: '2021-11-01', key: 1635724800000, doc_count: 1446 },
{ key_as_string: '2021-12-01', key: 1638316800000, doc_count: 1784 },
{ key_as_string: '2022-01-01', key: 1640995200000, doc_count: 1674 },
{ key_as_string: '2022-02-01', key: 1643673600000, doc_count: 693 }
]
Product Interaction
Product interactions are obtained by filtering by ev_category=sensor (Sensor Node events).
In case of different trigger sets (different products), you have to split by audience_id. You'll have to get the audience_id:audience_name relation from the collapsed query or audiences query.
Some examples:
- Interaction count
GET /analytics/-MV1AcMcnZE7_9Knly4F/eventcount?bt=2021-05-01T00:00:00&et=2022-10-01T00:00:00&ev_category=sensor
- Interaction avg. time
GET /analytics/-MV1AcMcnZE7_9Knly4F/split?bt=2022-08-01T00:00:00&et=2022-12-12T00:00:00&ev_action=out&ev_category=sensor&_split=audience_id&_aggregate=avg&_aggregate_field=target_attention_time