Skip to content

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

  1. Go to Broox Studio

  2. Edit your client record

  1. Copy your client id and api key.

  2. 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.

  • bt and et. 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_id
    • campaign_id
    • playlist_id
    • audience_id
  • Split dates:

    • day: 1-31
    • month: 1-12
    • weekday: 0-6
    • hour: 0-24
    • year: 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, blob
    • target_action: enter, exit, look...
    • target_gender: M or F
    • target_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_name
    • store_name
    • installation_name
    • controller (name)
    • campaign_name
    • playlist_name
    • audience_name
    • media_name
    • canvas_name
    • trigger_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 _split parameter for the field to split with.
  • Use the _split_missing parameter to set a default value when the _split field 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 _aggregate and _aggregate_field parameters.
  • _aggregate can be avg or sum
  • _aggregate_field can 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 _split0 and _split1 as split fields.
  • Optionally, use the _aggregate and _aggregate_field parameters.
  • _aggregate can be avg or sum
  • _aggregate_field can be any numerical field.
  • Optionally use the _split0_missing and _split1_missing parameters 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_term for the field to split via values. (e.g. day)
  • Use _field_ranges for the field to split via ranges (e.g. target_age)
  • Use _rangeN=min-max for the ranges.
  • Optionally, _rangeN_key to 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 _split field for the target field and _split_missing optionally for missing values.
  • Use _rangeN=min-max for the ranges.
  • Optionally, _rangeN_key to 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