Only this pageAll pages
Powered by GitBook
Couldn't generate the PDF for 166 pages, generation stopped at 100.
Extend with 50 more pages.
1 of 100

Developer

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Advanced usages

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Imports

Organisations structure

Please read page on User guides.

Datamart

All user data captured or calculated by the mediarithmics platform ends in a special database named datamart. ‌

A mediarithmics datamart is more than a traditional database. This new generation database leverages a database engine specially designed to outperform in the domain of data-driven marketing applications. This database engine is the outcome of more than seven years of R&D from mediarithmics engineering teams. Datamart is the first database engine to provide both real-time query processing and scalability on large data volumes.

A datamart is a multi-model database. Datamart displays information it manages in an object graph, where nodes can either be persisted objects or objects computed on the fly. Datamart then generates column-oriented tables specialized for analytics scenarios.

The object graph nature of a datamart is particularly adapted to capture the 'user graph' where each piece of information associated to a user is connected with the others in a local graph structure.

Users and roles

Please read page on User guides.

Device-based Network IDs

Device-based Network IDs refer to Device Registries because each device is assigned a "registry" where its identifiers are stored.

Here are common steps to activate a Device registry on a specific datamart:

  • If you have a single datamart, the Device Registry is automatically activated, and you can go to the next step.

  • If you have multiple datamarts, you must manually activate the Device Registry:

  • Go to Navigator > Settings > Organisation > Device Registries.

  • Select your Device Registry.

  • Click More button to open the menu.

  • Choose Edit linked datamarts.

  • Select all datamarts where you want to activate the Device Registry.

  • Managing device registries in the mediarithmics platform

    How to active a Device Registry on a datamart

    Communities and organisations
    Users and roles

    Compartments

    A UserPoint could have multiple user accounts and user profiles on the same datamart. For example, having a profile on one of your sites and another profile on another site.

    Compartments are a notion created to represent those different places where you have accounts and profiles. There is always one default compartment on a datamart, and you can create more of them. Compartments are associated with user account IDs to create a user identifier.

    Audience segmentation

    Data ingestion

    The mediarithmics graph structure organizes a user as a node, called a UserPoint. The user can be identified or anonymous. Think of the UserPoint as a pin-point that a detective would use to connect various pieces of information on the board, as shown in the following diagram.

    Automatic identity resolution is where the software "detective" merges two UserPoint representing the same person. All content and identifiers are regrouped under the older UserPoint. The newer UserPoint is then archived.

    The structure of a datamart is defined by a customizable schema, defined in a text file and based on the GraphQL Schema Definition Language (SDL). The GraphQL schema defines what types of data are stored in your data graph. Schemas are strongly typed, which unlocks powerful developer tooling.

    SDL is simple and intuitive to use, while being extremely powerful and expressive. The specification of this standard is available here: http://spec.graphql.org/

    A tutorial explaining the syntax of the type system is available here: https://graphql.org/learn/schema/

    User data alone is not sufficient to implement powerful personalized marketing. As in interpersonal communication, experience can help us make educated guesses. Datamart supports homogeneous management collected and automatically computed data to get the necessary insight on each user. Both types of data are declared in the same GraphQL schema.

    The mediarithmics datamart allows the homogeneous management of the collected data and the computed data. They are both declared in the same GraphQL schema and from the outside nothing distinguishes them.

    From the inside, the computed data is associated with algorithms that are loaded into the platform in the form of plugins. These algorithms can have different roles:

    • Machine Learning Function to calculate predictive data

    • UserTrait Function to calculate aggregates on user data

    Like all the other plugins, they are freely modifiable and customizable.

    • GraphQL: to allow querying, in real time, the local graph of a single user (e.g. for real-time personalization scenarios)

    • OTQL (Object Tree Query Language): to query the whole object graph in a couple of seconds, even with billions of data points. (e.g. for audience segmentation queries)

    • SQL: to run powerful analysis of your behavioral data

    Automatic identity resolution

    Schema based

    Computed objects

    Query languages

    First ID

    For First ID, you need to :

    1. Subscribe to First ID

    2. Activate First ID data ingestion from Websites

    Subscribe to First ID

    1. Go to Navigator > Settings > Organisation > Device Registries.

    2. In the Shared device registries section, click Manage subscriptions.

    3. Subscribe to First ID.

    If you have multiple datamarts, don't forget to activate First ID on all datamarts.

    First ID requires a modification of the user-event-tag to ingest the identifier.

    Follow these steps:

    1. Head to Navigator > Settings > Datamart > Channels.

    2. Select the site where you want to activate automated First ID capture.

    3. Go to JS Tag Configuration > Device Identification.

    User identifiers

    It is important to distinguish the nodes representing a user identifier and the nodes describing content on the user.

    Every activity or import that'll have one of those properties set will automatically be related to the correct UserPoint.

    Any activity using an identifier that doesn't already exist in the datamart will trigger the creation of a new UserPoint.

    You can bulk associate, dissociate or delete user identifiers using the feature.

    There are three different types of user identifiers:

    • User accounts

    UserPoint

    A UserPoint is a 360° vision of a unique user on the platform.

    It is composed of different sets of data to cover all the user aspects providing a 360° view (online and offline):

    • UserActivity represent an interaction with the user

    • represent a summary of timeless information about the user, like first name, last name, birth date...

    • are here to capture that the user belongs to a particular group of users

    • capture that the user has given his consent for a specific type of data processing

    • UserTrait represent a calculated attribute used to describe the user.

    Imagine you are going to a site with firefox, and you go back to that site later on safari. At the moment, there is no way for the platform to know that all those actions are from the same user. You'll have two UserPoints: one with the UserDeviceTechnicalId from firefox and the other with the UserDeviceTechnicalId from safari. If later you log into the site with your UserAccount on both navigators, the two UserPoint will be associated with a common UserAccount ID identifier. The platform will automatically merge the two UserPoint and their activities to represent the reality that we now know those two users were the same.

    UserPoint merges can only be triggered by :

    • updates

    The merge will result in a UserPoint survivor, to which we migrate all the data related to the previous two UserPoint.

    IP address

    IP address automatic capture is only available for CTV channels. If you wish to discuss activating it for Site or Mobile channels please get in touch with your account manager.

    For IP address, you have 2 options :

    Option 1 : Activate auto IP address capture for a CTV channel

    Option 2 : Create dedicated registries then activate auto capture

    Option #1

    If you wish to have 2 dedicated registries for each CTV channel

    1. Go to Navigator > Settings >Channels

    2. Select an existing CTV Channel or create a new one

    3. In the IP addresses capture section, toggle "Active"

    4. Save

    This will automatically create dedicated registries to store IPv4 and IPv6 addresses. All captured IP addresses will then be stored in one of these two registries.

    If you have multiple CTV channels don't forget to do this for each one.

    If you wish to use the same 2 registries for all your CTV channels

    1. Create 2 devices registries Navigator>Settings>Organisation>Device Registries

      1. One of type IP_V4_ADDRESS_ID

      2. One of type IP_V6_ADDRESS_ID

    UserEmail

    Users can have multiple UserEmail registered on the platform. They have the following properties:

    Property
    Type
    description

    hash

    ID

    The hash property is mandatory and is the property used to identify a user (provided in $hash property in User activities request).

    Networks IDs

    We categorise Network IDs into two groups: Device-based Network IDs and User-based Network IDs. Each category allows you to add custom identifiers or subscribe to existing ones.

    To integrate a Device-based or User-based Network ID, the steps are generally:

    1. Create a new / Subscribe to a Device Registry or Compartment

    2. Activate this Device Registry or Compartment on the desired Datamarts (only required where there is multiple datamarts in your environment)

    3. Activate the Device Registry or Compartment ingestion on your Channels

    Don't hesitate to check the documentation of a particular Network ID below for more information and detailed procedures.

    UserSegment

    Audience segments represents a group of users and are central to most marketing actions. Users can be grouped by common profile characteristics, or similar behavior in their online browsing or in their purchases. Users can be grouped either using the mediarithmics platform, or externally and then imported.

    Here is a list of audience segment types that differ from each other by the method used to group users:

    • Audience segments calculated from a query (type USER QUERY). Several tools are provided to define this type of segment. Occasional platform users will find it easier to use the Audience Builder. More advanced users such as data admin or data analyst will find a greater wealth of expression in the Segment Builder. Finally, technical users, data engineers or integrators, can directly use a textual query language (see OTQL).

    User-based Network IDs

    User-based Network IDs refer to Compartments because each user network ID is assigned a compartment where its identifiers are stored.

    Here are general steps to follow in order to activate a Compartment on a specific datamart:

    • If you have a single datamart, the Compartment is automatically activated.

    • If you have multiple datamarts, you must activate it on every datamart

    Custom User ID integration

    Custom User IDs are used to identify your users with your systems such as CRMs, loyalty programs, or authentication systems.

    1. Go to Navigator > Settings > Organisation > Compartments.

    2. In the First-party user account compartments section, click on New Compartment.

    Data warehouse management

    If you wish to leverage data stored in your data warehouse, you can declare you own data warehouse in mediarithmics as a data source.

    We currently support the following warehouses :

    Learn more :

    Building new feeds

    Here are our creation steps for making a new audience segment feed for you :

    1. Validation process to ensure we need the connector.

    2. Audience segment feed specifications:, studying how we connect to the partner and which parameters should be made available to the user.

    ID5

    For ID5, you need to :

    1. Subscribe to ID5

    2. Activate ID5 data ingestion from websites

    1. Go to Navigator > Settings > Organisation > Device Registries

    Hashed user email. Always use the same hashing function (ex: SHA-256) in your datamart and all its integrations to allow proper matching between data flows.

    email

    String

    Optional. User's email, not hashed.

    creation_ts

    Timestamp

    When the email was registered on the platform

    expiration_ts

    Timestamp (optional)

    Email's eventual expiration timestamp

    Enable First ID.
  • Optionally enable Install First ID javascript tag (SDK) on the webpage.

  • Repeat these steps for all site where First ID data collection is expected.

  • Activate First ID ingestion from websites

    The Install First ID javascript tag on the webpage option allows the mediarithmics JavaScript tag to automatically install the First ID JavaScript tag (SDK) on the webpage.

    This option is optional. You may also choose to deploy and manage the First ID SDK independently on your websites.

    The First ID SDK may read and write information on the device (cookies and local storage) and trigger additional processing of personal data by First ID.

    Before enabling this option, make sure you have implemented all prerequisites required by First ID regarding user information and consent collection.

    Activate automatic IP capture on your CTV channel(s) : Navigator > Settings >Channels

  • Select an existing CTV Channel or create a new one

  • In the IP addresses capture section, toggle "Active"

  • Check the "Use exisiting device registries" and select the 2 registries you created

  • Save

  • Option #2

    Specify the following details:
    Parameters
    Description

    Name

    Name of the Compartment

    Token

    A technical identifier used to link the Compartment with the JS Tag

    If you have multiple datamarts, don't forget to activate the new Compartment on all other datamarts.

    Create a Custom User ID

    Code and validation.
  • Cookie matching set up. Some partners need a cookie-matching mechanic so that we can send them identifiers that have meaning for them.

  • Deployment. We allow connections to the partner's API during this step.

  • mediarithmics will create new audience segment feeds for you, and they will be made available to all other customers. Please discuss your needs with your Account Manager.

    Creation steps

    User emails
    User device points and device technical ids
    bulk import

    How to set up a connection to your data warehouse

  • Ingest data coming from your warehouse

  • This feature is in Alpha, please contact your Account Manager to learn more.

    Google BigQuery
    Snowflake
    Drawing
    Audience segments imported from an external system (type USER LIST)
  • Audience segments calculated from a likeness prediction algorithm (type USER LOOKALIKE)

  • Audience segments associated with the events of a campaign (eg: all the people exposed to a given video campaign) (type USER ACTIVATION)

  • Audience segments associated with A / B tests (control group and test group)

  • An audience segment represents a group of users. A UserSegment is a piece of information that is associated with a user to indicate that this user belongs to the segment.

    For example, if an audience segment has 10,000 users, each user has a UserSegment to signify their membership in this segment. So there are 10,000 UserSegment, one for each user in the segment.

    In the data schema this information element is materialized in the form of an object of type UserSegment (see standard datamart schema). This object contains the following information:

    • The segment identifier

    • The date the user entered the segment (creation date of the UserSegment object)

    • The expiration date at the end of which the user will exit the segment. This date is optional and is only entered for some types of segments.

    When working with a User Query audience segment, it is important to understand the difference between the count of the segment and the persistence of this segment.

    Counting consists of calculating the number of users who verify the segment's grouping rules. That is to say the users who respond positively to the conditions and to the boolean operators present in the segment query. The counting of a segment is done in real time. It usually only takes a few seconds (2-5 sec) to get a result.

    However, if the count is immediate, the process of bringing all the targeted users into the segment by creating a UserSegment type record for each of them may take more time. This time depends on the size of the segment, the segment refresh policy and the calculation budget allocated to the account.

    Audience Segment & UserSegments

    Counting and Persistence of an audience segment of type User Query

  • Head to Navigator > Settings > Datamart > Compartments.

  • Select your Compartment.

  • Click to the More button to open the menu.

  • Choose Edit linked datamarts.

  • Select the datamart where you want to activate the Compartment.

  • For community-created user IDs, activate them across organizations by selecting Enable Compartment in the Shared User Account Compartments Enabled section.

    Managing compartments in the mediarithmics platform

    How to activate a compartment on a datamart

    Activate IDs across your organisations:

    .
  • In the Shared device registries section, click on Manage subscriptions

  • Subscribe to ID5.

  • If you have multiple datamarts, activate the ID5 subscription on all datamarts.

    ID5 requires a specific technical configuration to be properly ingested from your website.

    Please contact your Account Manager to complete the ID5 configuration for your channel (an activity analyzer will be added to your channel to handle ID5 IDs).

    Subscribe to ID5

    Activate ID5 ingestion for your websites

    UserPoint merges

    UserProfile
    UserSegment
    UserChoice
    UserActivity
    User identifiers association declarations

    Data visualisation

    You can manage charts using and . Manipulating dashboards by API and in advanced mode can be useful in some advanced integrations, but will take longer.

    With data visualisation, you can create dashboards :

    • In your datamart's home page

    • In your segments

    • In the standard segment builder

    Those dashboards will answer questions like :

    • What is ingested in the platform?

    • Do we have moments where we ingest less data than on other days?

    • Who are my users?

    Create your first dashboard with our guide.

    Speed up your learning curve with useful examples in our .

    Computed fields

    This feature is in Alpha.

    Definition

    A computed field is a dynamic field defined in the schema, linked to a script that is triggered for each new user activity or profile update and performs a computation of a function's result on a regular basis. It is used when the desired outcome cannot be achieved with existing directives or to simplify an OTQL query by replacing multiple directives with a single field.

    Those fields can be used in segment definition to improve analysis and sharing, or in the Experiment feature to enhance control groups creation.

    Examples

    Those examples are handled by computed fields:

    • Retrieve the most recent event (e.g. last visit, last transaction, etc.)

    • Get the total amount for a specific type of event (e.g. sum of transactions in the last 30 days, total expenditure on a particular category of product, etc.).

    • Weighted sum (Affinity total, etc.)

    • Compare multiple channels (e.g. to find the best channel for transactions).

    This example should be handled by a standard directive:

    • Get all users with at least a specific amount for one category

    This example can't be handled by a computed field:

    • Identify the top X% of a specific user group (e.g. the top 10% of buyers).

    Once live, a computed field behaves like a regular field, making it transparent to the user. Here's how you can use it in practice:

    Use Case: Identify Users Who Have Spent More Than 100€ on IT Products in the Last 3 Months

    With Standard Directives:

    This query uses standard directives to sum the basket amounts for IT products over the last 3 months.

    With a Computed Field:

    In this version, the computed field IT_amount_3months is used directly in the query. The field is calculated on a regular basis, meaning no computation is performed during query execution. This results gives faster query response times, as the value is precomputed and readily available.

    UserPoint deletion

    This document import allows you to mark UserPoint for deletion.

    Each line in the document is a user identifier that is linked to a UserPoint (or is a UserPoint ID directly). For each of those identifiers, the job will find its associated UserPoint and delete it, along with all of its identifiers, segments, scenario and its profile .

    How-to

    1. Use the bulk import endpoints to create a document import with the USER_POINTS_DELETION document type and APPLICATION_X_NDJSON mime type. Only ndjson data is supported.

    2. Create anwith your commands formatted in ndjson. Each line can represent either a user agent, a user email, a user account or a UserPoint ID. Their respective syntax is detailed in .

    Please note that the uploaded data is in ndjson and not json. That means the different deletions are not separated by commas, but by a line separator.

    A list of possible user_agent_id values can be found at

    Hyper point & Quarantine

    Hyper point

    A hyper point is a preventive way to flag a UserPoint whenever there are too many identifiers linked to it. Concretely, a UserPoint becomes a hyper point when mediarithmics tries to merge UserPoint and especially when at least one of the following conditions is met:

    • the frequency of user identifiers creation in this UserPoint reaches:

      • more than 10 identifiers by Registry ID in 2 days,

      • more than 4 Account ID in 7 days,

      • more than 4 Email hash in 7 days,

    • more than 8 UserPoint were merged to that UserPoint in the last 14 days,

    • more than 100 user identifiers are attached to this UserPoint.

    This system is a preventive action of flagging a UserPoint so that the UserPoint is still actionable in mediarithimics.

    The quarantine job is a monthly process that flags any UserPoint which has too many objects attached to it. This happens especially when at least one of the following conditions is met:

    • more than 10.000 ,

    • more than 5.000 .

    A UserPoint in quarantine can still be looked up in Navigator but no more additions will happen to it.A UserPoint can be freed by the quarantine job if it gets below the above-mentionned limits. This particularly happens by deleting activities (through API or when cleaning rules are applied) on a quarantined UserPoint.

    Data warehouse ingestion

    This feature is in Alpha, please contact your Account Manager to learn more.

    Pre-requisite

    You first need to declare your data warehouse as a data source in mediarithmics as detailed in the data warehouse management section.

    Synchronization strategies

    When trying to ingest data from a data warehouse to mediarithmics, you will need to configure a service account with specific rights on the data you want to expose : the service account will need to at least have read access on the data.

    Working dataset/schema

    If you want to use synchronization strategies that can handle updates and deletes on existing data, you will need to create a working dataset/schema. On this dataset/schema, the service account should have editing rights : this will be used to create temporary tables and track changes on your tables.

    Available strategies

    • Profile data

      • Timestamp based : all updates in the source table (insert, update, delete) are impacted in mediarithmics. This requires a timestamp column tracking the last update of each line of the table.

      • Hash table : all updates in the source table (insert, update, delete) are impacted in mediarithmics. A temporary table is created based on a hash of columns of the source table.

      • Full import : every synchronization will import the full table. It does not handle deletes or updates, this is a append-only strategy.

    • Event data

      • Timestamp based : import all events that occurred since the last import. This requires a timestamp column tracking when each event of the table has occurred. It does not handle deletes or updates, this is a append-only strategy.

    Without a working dataset/schema only append-only strategies are available : timestamp based for event data, and full import for profile data.

    Strategy
    Needs a working dataset/schema

    Querying your data

    You have three different ways to query your data in mediarithmics depending on what you want to achieve.

    GraphQL

    The GraphQL API gives you the ability to query all kinds of UserPoint data, as collected by the platform (profile, activities, segments, identifiers, etc.) with a single request.

    OTQL

    The OTQL Language is an extension to GraphQL. It is based on the same schema and adds unique features to query a graph of millions/billions of objects.

    Analytics

    We provide an analytics data cube to query user activities.

    UserPoint API

    The UserPoint API allows to retrieve, create, update or delete all data related to a single UserPoint.

    General description

    The endpoint is formatted as follows:

    /v1/datamarts/<DATAMART_ID>/user_points/<USER_POINT_SELECTOR>/<DOCUMENT_TYPE>/<DOCUMENT_SELECTOR>

    where

    • <USER_POINT_SELECTOR> allows to select a UserPoint based on any of its identifiers

    Possible values are:

    • <DOCUMENT_TYPE> designates the type of data that will be addressed

    Possible values are:

    • <DOCUMENT_SELECTOR> allows to select a particular document on the UserPoint

    As each document is identified by a different identifier, possible values depend on the type of document previously selected. It is also optional: use it if you want to get, update or delete a particular document.

    Sections and cards

    A DashboardContent is composed of sections and cards.

    • Each section has a title and cards disposed on a grid.

    • Each card is a white block organizing charts horizontally or vertically.

    Dashboard structure

    The size and position of each card is defined by a 12 column grid, with as many rows as needed. Cards size and position are set with {h,w,x,y} properties :

    • h is the number of rows that the card takes.

    • w is the number of columns that the card takes

    • {x,y}

    Here is a sample grid with five cards and their corresponding properties :

    Audience segment feed

    An audience feed is a plugin acting like a connector that allows mediarithmics customers to push their segments to a third-party platform.

    It is generic: once a connector to a partner has been created, every customer can use it. Each audience feed has a specific set of options to adapt to each customer.

    For more details on how to manage consent in segments and feeds, have a look at the s section.

    Key concepts

    An audience external feed is a mediarithmics plugin specific to a partner, but shared across customers. In the UI, it is called Server-side plugin: go to a specific segment, click Add a feed, and you will see a feed type called server-side. It is marketed as connectors or server-to-server connectors.

    It has:

    • Plugin definition

      • group_id: com.mediarithmics.audience.externalfeed

      • artifact_id: [[partner]]-connector

    • Plugin versions with

      • Deployed code

      • An external service referencing partner’s API

    A feed is an instance of an audience feed. It is specific to a segment in an organisation. It has:

    • Feed ID

    • Instance properties specified by users in the UI when adding a feed to a segment.

    A feed session is initiated whenever an external feed is activated. A new session will also be created if a feed is paused and then reactivated. This session is not visible in the UI.

    A feed preset is a template allowing users to easily create feed instances with pre-configured properties. You can, for example, create a Facebook feed preset containing your key for your organisation, and you won't have to remember it every time you set up a new feed.

    Custom Device ID integration

    A UserPoint can be associated with multiple UserDevicePoint. Each user device point can include:

    • Multiple device technical identifiers

    • One device information record

    Create a new registry

    1. Go to Navigator > Settings > Organisation > Device Registries.

    2. In the First-party device registries section, click on New Registry.

    3. Specify the following details:

    Parameters
    Description
    1. Go to Navigator > Settings > Organisation > Device Registries.

    2. In the Shared device registries section, click on Manage subscriptions.

    3. Select Subscribe to the desired registry.

    If you have multiple datamarts, don't forget to activate your Device Registry on all datamarts.

    Dashboards

    Each dashboard is represented by a DashboardRegistration object. It has a title, scopes, and a DashboardContent. Its content is composed of sections and cards.

    Dashboards can be displayed on:

    • Datamart's home page with the home scope.

    • Segments page with the segments scope.

    • Standard segment builders with the builders scope.

    • A specific set of segments with the segments scope and segment IDs in the segment_ids property.

    • A specific set of standard segment builders with the builders scope and builder IDs in the builder_ids property.

    You can have multiple dashboards at the same scope.

    If you have multiple dashboards to be displayed at a given scope, tabs will be created to switch between them. If you don't have multiple dashboards, it is displayed without any tab.

    See for managing dashboards by API.

    If you want to start from an existing dashboard, you can

    1. Open the dashboard you want to clone on the computing console

    2. Go to the Advanced tab and copy the whole JSON

    3. Create a new dashboard

    Contextual targeting

    Context

    Check User guides documentation to learn more about this feature.

    Prerequisites

    URLs & hits must be captured into mediarithmics in order to perform the contextual extraction and semantic analysis. This can be done either through:

    • User event tag (user tracking)

    • Contextual targeting tag (no user tracking)

    • (for mobile app only. url field needs to be populated in that case)

    To configure the Contextual targeting feature, follow the setup steps below depending on your needs:

    1. - MANDATORY. This initial configuration is required for all customers using the Contextual targeting feature

    2. - OPTIONAL. Complete this step only if you plan to activate your contextual targeting lists. You do not need this step if your goal is solely to use contextual extraction for audience building within the platform

    Welcome!

    Welcome to our documentation web site, whether you are Ad / Digital Ops, Data Engineer, Data Analyst or Data Scientist, you will find here all the information you need to make the most of mediarithmics.

    Our vision is to provide a data-first marketing cloud to solve the need for organisations to serve as best-in-class in a digital economy.

    The mediarithmics platform can be seen both as a set of digital marketing applications that can be used directly by marketers, or as a highly customizable data marketing cloud infrastructure that data engineers and data scientists can tailor to the needs of their organisation.

    Even if this 'Get started' section is mainly targeted at a technical audience, it is written in plain English, without reference to technical implementation details, and should be readable by anyone interested in the way mediarithmics structures the world of modern marketing. It is a good introduction to the mediarithmics platform.

    The purpose of a data marketing platform is to enable use of all available information to make better decisions in all areas of marketing.

    Decorators

    Schema decorators allow you to customize how your graph appear within the mediarithmics platform interfaces, specifically the Advanced Segment Builder and the Query Tool.

    By uploading a specific CSV file, you can "shallow-rename" fields (change their display label) or hide specific properties from users without altering the underlying technical schema.

    Schema decorators are defined using a CSV file. Below are the specifications for the file format.

    • Separator: Comma (,)

    • Quotes: Double quotes (

    Concepts

    Computed fields are defined in the schema at the UserPoint level.

    The plugin behind it performs computations on a regular basis of a function's result, based on the user activities and profile updates.

    A computed field is an instance of a Datamart function applied within a specific context. To use it, it must be declared in your schema.

    A Computed Field Function is a of type COMPUTED_FIELD_FUNCTION, which can be created via the API following the standard or through the computing console interface.

    A computed field is defined by these elements:

    User activities import

    Bulk import to insert user activities that happened outside of . Those activities usually are offline activities, like store visits or store purchases, but you can adapt it to your use cases.

    Use the endpoints to create a with theUSER_ACTIVITYdocument type and APPLICATION_X_NDJSON mime type. Only ndjson data is supported for user activities.

    Then, create anwith your user activities formatted in ndjson .

    Edge segments

    You can compute segments browser-side using our Edge technology and share them with Google Ad Manager. This allows you to react instantly to user behavior and trigger campaigns as users navigate your website.

    To do so, the mediarithmics tag:

    • Collects and stores identifiers and navigation data in local storage. When an event is pushed by the tag, it is sent both to the activity processing pipeline and saved locally.

    • Computes browser-side which segments the user enters or leaves.

    Conversions tracking

    To measure and optimize the performance (i.e., cost per action) of your marketing campaigns, you need to track user conversions driven by your Marketing Campaign.

    On the mediarithmics platform, you create a Goal to define a trigger when a user should convert.

    There are two ways of configuring a Goal:

    1. Creating a Goal and using the associated Pixel. Each user that sees the Pixel in a page will convert for this goal. This Pixel should be present on the confirmation page or dynamically loaded when the user converts (by using a Tag Manager or by including the 'pixel load' in the website logic)

    Activities analytics queries

    The activity analytics endpoint has been designed as a cube to query user activities.

    This API gives you programmatic access to user activities as a data cube. You get metrics with dimensions, filters, and within date ranges leveraging the part of our multi-model database.

    With the activities analytics API, you can create reports to answer questions like:

    • Number of active users. The metric is users and it has no dimensions or filter.

    Exporting your data

    There are few ways to export data depending on your usage.

    Use if you need to export audience segments data to your partners' solutions and keep it recurring and synchronized.

    If you need a feed to deliver its data to an external system, first set up a destination file to define where and how those files are delivered.

    Create to create ndjson files corresponding to results of .

    by sending all the ingested data to Google Cloud Platform (Pub/Sub) or Microsoft Azure (Event Hubs - Alpha).

    Device points deletion

    This document import allows you to mark device points for deletion.

    Each line in the document is a user agent identifier that is linked to a device point (or is a device point id directly). For each of those identifiers, the job will find its associated device point and delete it. Note that a device point may be linked to multiple user agent identifiers, all of which will be deleted once their device point is (including user agent identifiers that may not appear in your document).

    1. Use the endpoints to create a with the USER_DEVICE_POINTS_DELETION document type and APPLICATION_X_NDJSON mime type. Only ndjson data is supported.

    Timestamp based

    Events : No Profile : Yes

    Full import

    No

    Hash table

    Yes

    At the time of the synchronization, if the source table for events contains data that will be impacted by active cleaning rules on events for the datamart, then these events will not be imported.

    Summary

    Description

    (Optional) More information about the Device Registry

    Name

    Name of the Device Registry

    Token

    A technical identifier used to link the Device Registry with the JS Tag

    Type

    Must be one of the following enums:

    MOBILE_VENDOR_ID ,CUSTOM_DEVICE_ID

    Subscribe to an existing registry

    Quarantine

    activities
    segments

    Setup

    User activities import
    General setup
    Activation setup
    Configuration files for things like credentials, tokens, technical configurations
    User choice
    How many active users do I have? On which channels?
  • What differentiates people in this segment from the rest of my users?

  • Do I have enough data to activate a segment?

  • Quick start guide

    Cookbook

    Quickstart
    Cookbook
    the query tool
    edit dashboards in the UI

    When a user enters or exits one or more segments:

    • Triggers the Google Ad Manager integration

    • Sends the information back to the server to maintain a server-side state of the segment. Segment statistics are computed periodically by running a query that counts users flagged as belonging to the segment.

    To configure the Edge segmentation feature, please follow the steps outlined below.

    • Update Snippet: Ensure your site is running the latest version of the mediarithmics snippet. (Refer to Website tracking documentation for details).

    • Feature Activation: Contact your Account Manager to enable Edge on your specific channels.

    Identify the properties in your schema required for Edge-based user segmentation and mark them with the @EdgeAvailability flag (see Data model @EdgeAvailability directives for more information)

    Note that you must meet the following requirements:

    • Supported Objects: Edge only supports properties from the following objects:

      • UserDeviceTechnicalId

      • DeviceInfo

      • UserSegment

      • UserEvent (including all sub-object properties)

    • Data Integrity: Properties must exist in the schema and be stored exactly as pushed by the tag. No transformations (e.g., event rules or visit analyzers) can be applied.

    • Directives: A property using the @PropertyPath directive is only compatible if the path name and property name are identical in both the schema and the data layer.

    Finalize the connection between mediarithmics and your delivery platforms.

    • Google Ad Manager (GAM): The JS snippet automatically pushes segment IDs as key-values to the ad call. However, these must be manually created within the GAM UI.

      • Reference: GAM Key-Value Setup Guide

    • Other Platforms: While there is no native "out-of-the-box" integration for other platforms yet, it can be implemented easily on your side, as segment IDs are stored and available in Local Storage.

    How it works

    Only users who navigated your site with the Edge feature activated will be in the segment.

    Setup

    1. Prerequisites

    2. Schema Configuration

    Tip: We recommend validating your schema changes with our technical team before deployment.

    3. SSP / AdServer Integration

    Writing a rule that will be run on the Datamart data. It will generate a user conversion each time a user matches the rule.

    From experience option #1 is the simplest solution to configure and should be used for each 'non-recurrent' User Conversion tracking.

    The option #2 offers more flexibility but with the cost of a longer & more complex configuration. It should be used either when the:

    • datamart tracking JS TAGs / Pixels are already present on the website, including the page where the conversion happens

    • Goal to track will be used repeatedly

    • Goal definition requires a complex rule that can't be achieved by displaying a JS TAG / Pixel

    When creating a goal in the navigator (Campaigns tab > Goals sub-tab):

    1. Define the name of the goal.

    2. Select Trigger via Pixel.

    3. Copy/paste the generated HTML code to your technical team so that they can integrate it.

    4. Don't forget to associate the correct attribution model for the attribution of the conversion to your Marketing Campaigns.

    5. Save the goal.

    When creating a goal in the navigator (Campaigns tab > Goals sub-tab) :

    1. Define the name of the goal.

    2. Select Trigger via Query.

    3. Define the query that should be used to tell if a User has converted or not. Please read the documentation about Queries here

    4. Don't forget to associate the correct attribution model for the attribution of the conversion to your Marketing Campaigns

    5. Save the goal.

    If you have issues when defining the proper Query to define your Goals, please try Option #1 or reach out to your Account Manager.

    Tracking User Conversions by using Pixels

    Tracking User Conversions by using Datamart Queries

    Deletions

    Usage Example

    <USER_POINT_ID> or user_point_id=<USER_POINT_ID>
    user_agent_id=<USER_AGENT_ID>
    compartment_id=<COMPARTMENT_ID>,user_account_id=<USER_ACCOUNT_ID>
    email_hash=<EMAIL_HASH>

    Activities imported through bulk import don't go through the activity processing pipeline. You shouldn't use this feature if you intend to do conversion detection or automation activation. Your activity analyzers also won't process those activities, and you should format exactly how you expect them to be stored by mediarithmics.

    How-to

    Example

    You can, of course, upload multiple activities at once. Note the uploaded data is in ndjson and not json. That means the different activities are not separated by commas, but by a line separator \n

    user activities
    real-time tracking
    bulk import
    document import
    execution
    // With standard directives
    SELECT { id } FROM UserPoint
    WHERE activity_events @ScoreSum(min : 100) {
        basket { 
            items @ScoreField(name:"price") @ScoreSum(result:"score_value") {
                category="IT" AND date >= "now-3M/M"
            }
        }
    }
    //With a COmputed field "IT_amount_3months"
    SELECT { id } FROM UserPoint WHERE IT_amount_3months >= 100
    user_identifiers
    user_profiles
    user_activities
    user_choices
    user_scenarios
    user_segments
    user_profiles/compartment_id=<COMPARTMENT_ID>
    user_profiles/compartment_id=<COMPARTMENT_ID>/user_account_id=<USER_ACCOUNT_ID>
    user_choices/processing_id=<PROCESSING_ID>
    user_scenarios/scenario_id=<SCENARIO_ID>
    user_segments/audience_segment_id=<SEGMENT_ID>
    # Create the document import
    curl -X POST \
      https://api.mediarithmics.com/v1/datamarts/<DATAMART_ID>/document_imports \
      -H 'Authorization: <YOUR_API_TOKEN>' \
      -H 'Content-Type: application/json' \
      -d '{
    	"document_type": "USER_ACTIVITY",
    	"mime_type": "APPLICATION_X_NDJSON",
    	"encoding": "utf-8",
    	"name": "<YOUR_DOCUMENT_IMPORT_NAME>"
    }'
    # Create the execution
    curl -X POST \
      https://api.mediarithmics.com/v1/datamarts/1162/document_imports/<DOCUMENT_IMPORT_ID>/executions \
      -H 'Authorization: <API_TOKEN>' \
      -H 'Content-Type: application/x-ndjson' \
      -d '{ "$user_agent_id": "<USER_AGENT_ID>", "$type":"TOUCH","$session_status":"NO_SESSION","$ts":<TIMESTAMP>,"$events":[{"$event_name":"$email_mapping","$ts":<TIMESTAMP>,"$properties":{}}]}'
    are the coordinates of the top left corner of the card on the grid
    A sample grid with 5 cards
    Go to the Advanced tab and paste the whole JSON
  • Start editing your new dashboard in the WISYWIG or the Advanced tab

  • It is best to have multiple dashboards than a single big one to prevent too many requests from being executed simultaneously.

    Tip: Cloning a dashboard

    REST resources
    Multiple dashboards displayed on "home" scope

    The mediarithmics platform can collect all data sources. Whether the data comes from the users' online activity or from backoffice management systems such as CMS', ERPs, and CRMs, all the data is stored for each user in a graph model as shown below. This universal data model allows you to connect all the information of a user, the collected information such as account identifiers, terminal identifiers, profile information, activities, and purchases, as well as data calculated on the fly, such as appetence score, age and gender predictions, and recommendations of articles or other content.

    These centralized data allow us to conduct multiple analyzes (visit analytics, uplift analytics, segment insights, data discovery ...) and to act when the time comes:

    • Either by activating audience segments via a rich ecosystem of connectors to advertising networks, communication tools (notifications, emails) or personalization tools (on-site display, A/B testing on user journey),

    • Either by defining orchestrations that will be triggered automatically, by aligning themselves with the highlights of the user experience (e.g., first visit, creation of an account, drop in the frequency of visits, etc.).

    In many companies, the recent history of data marketing has been built by the accumulation of different solutions that stack or overlap. Whether it is for the acquisition of new customers, the improvement of the conversion rate, the retention of existing customers, or the construction of predictive models, each application in isolation makes sense and provides a service to a team.

    But after a while, this structuring in silos no longer makes it possible to be reactive and to innovate. The data is multiplied in multiple systems and these systems cannot speak to each other because of the "heaviness" of these huge amounts of data.

    The mediarithmics platform has been designed from the start to overcome these structural difficulties and introduce a new model: the data-first marketing cloud.

    In this model, the data gathered in a single datamart are shared by all applications and users. Both mediarithmics and partner applications access the same source of truth for analytical queries that mobilize large amounts of data, but also for all real-time personalisation micro-queries that are interested in the characteristics of a single user.

    All the user data captured or calculated by the mediarithmics platform ends up in a special database named Datamart.

    A mediarithmics datamart is more than a traditional database. This new generation database is leveraging a database engine specially designed to outperform in the domain of data-driven marketing applications. This database engine is the outcome of more than seven years of R&D from mediarithmics engineering teams. It is the first database engine to provide both real-time query processing and scalability on large data volumes (see focus on Datamart).

    The mediarithmics datamart is a key enabler of all the use cases that can be imagined in one-to-one marketing … (real-time user experience customization, audience segmentation, funnel analytics, and campaign analytics …).

    The information inserted in a datamart is primarily stored following a graph structure, where nodes containing pieces of information are connected through a link to represent a relationship between those pieces of information.

    Let's take an example. A user visits a website which implements a tracker connected to the mediarithmics platform. At the end of the visit, three nodes will be created in the datamart.

    • One node to represent the user

    • One node to represent the visit (e.g., piece of information: the web site, the date, the visit duration, pageviews, products in the basket, etc.)

    • One node to represent the device which was used.

    Notice that the node representing the user looks like a pinpoint. This node is called a UserPoint and it plays the role of a central pinpoint connecting all pieces of information which are collected about the user.

    In the User 360 View, it is important to distinguish the nodes representing a user identifier and the nodes representing a describing content on the user.

    There are three different types of user identifiers:

    • The UserAccount Id : It represents the identifier of a registered user. The registration system can be a CRM system, a loyalty program system, or an authentication system. This registration system is external to the mediarithmics platform. The UserAccount Id is composed of a character string and a compartment id, which represents the registration system.

    • The UserEmail: It represents an identifier based on the user email. It is usually derived from the user email by using a hash function (MD5, SHA-256, …)

    • The UserDeviceTechnicalId: it represents the identifier of a UserDevice.

    The describing content of a user 360 view is composed of different data elements corresponding to different point of view on the user:

    • A UserActivity represents an interaction with the user

    • A UserProfile represents a summary of timeless information about the user (e.g. firstname, lastname, birthdate, address, sex, age, etc.)

    • A UserSegment is here to capture that the user belongs to a particular group of users, such as an audience segment.

    • A UserChoice is here to capture that the user has given his consent for a specific type of data processing

    A UserActivity represents any interaction with the user either online or offline. It can represent the summary of an online visit, the detailed content of an in-store purchase, the summary of a call to a call-center, a campaign interaction like an opened email or a click on a banner.

    A UserActivity can contain a list of events. An event represents the most granular level of interaction with a user. It is defined by a name and a set of custom properties.

    For each user, the UserActivity are ordered in a timeline.

    For more detailed information on UserActivity and UserEvent, please follow the link below.

    UserProfile

    A UserProfile provides a summary of information on the user and can contain any kind of information. The UserProfile is usually imported from an existing information system like a CRM or login database, and collect information such as: contact details, the user preferences, the status in a loyalty program, the subscription to newsletters.

    A UserSegment node represents a user who belongs to an audience segment. An Audience Segment is a group of users who share some common characteristics in the eyes of the marketer. There are several ways to define an audience segment in the platform.

    Whatever the type of Audience Segment, a User 360 view contains a UserSegment node for each audience segment the user belongs to.

    For more detailed information on audience segments and their life-cycles, please follow the link below.

    A UserChoice node represents the choice of a user regarding data privacy and data processing declared by the organisation. This information is used to automatically adapt the behavior of the applications to consider the user choices about Data Privacy.

    A UserScore is a set of data calculated dynamically and providing predictive information on a user. A UserScore is connected to a Machine Learning Function (ML Function). A UserScore can, for example, predict the expected lifetime value, churn risk, age, or gender of a user.

    All platform services are directly manageable and consumable through APIs.

    Beyond these standard capabilities, the platform is also a computing infrastructure which enables the hosting of custom algorithms packaged in plugins. A plugin is a bundle of code and data which defines the behavior of a live function hosted in the mediarithmics cloud. It can be developed in any programming language. Due to latency requirements, some languages may be more adaptable than others.

    The mediarithmics platform can integrate these plugins:

    • Activity Analyzer: to filter and enrich activities data collected through a tag or the API

    • Audience Feed: to push audience segments to third-party systems

    • Machine Learning Function: to add live predictive data to a user graph

    • Display Ad Renderer: to customize the rendering of display ads

    • Email Renderer: to customize the rendering of emails

    • Attribution Processor: to customize the attribution of a marketing conversion to different campaigns

    The mediarithmics platform operates at the heart of an open ecosystem by offering connections with many partners.

    Our platform covers your needs, including (but not limited to): analytics tools, messaging solutions, personalization solutions, prediction tools, advertising networks, and audience monetization.

    Our vision

    From collection to activation

    For all stakeholders

    Multi-model database technology

    User 360 view

    Any kind of user identifiers

    Many different pieces of information attached to a user

    UserActivity

    UserSegment

    UserChoice

    UserScore

    Plug-able Custom Logic

    A large ecosystem of connectors

    UserActivity & UserEvent
    UserSegment
    "
    ) must be used for strings that contain commas.

    The CSV must contain the following headers.

    Header
    Description

    OBJECT_NAME

    The name of the object (resource) where the property is located.

    FIELD_NAME

    The original technical name of the property to decorate.

    HIDDEN

    true or false. Indicates if the field should be hidden from the UI.

    Code snippet

    You can manage schema decorators either through the mediarithmics user interface (Navigator) or programmatically via the API.

    In the Datamart > Object View Configuration section of the Navigator Settings, you can use the buttons under the Schema to manage your CSV files directly.

    The available actions are:

    • Upload new Decorators: Allows you to upload a prepared CSV file to apply new labels and visibility rules. This will overwrite existing decorators for this schema.

    • Download Template: Downloads a blank CSV file containing the required headers (OBJECT_NAME, FIELD_NAME, etc.) to help you get started.

    • Download Decorators: Downloads the current active decorator CSV file. This is useful if you want to make edits to the existing configuration.

    • Delete Decorators: Removes the current decorator file. The schema will revert to displaying raw technical field names, and hidden fields will become visible again.

    You will need the following values:

    • DATAMART_ID: The ID of your Datamart.

    • SCHEMA_ID: The ID of the Schema you wish to decorate.

    • MICS_API_TOKEN: Your API authentication token.

    To fetch the existing decorator file for a specific schema:

    Bash

    To upload a new decorator CSV file (replacing the existing configuration):

    Bash

    Decorator CSV Format

    CSV Dialect Rules

    OBJECT_NAME,FIELD_NAME,HIDDEN,LABEL,HELP_TEXT,LOCALE
    UserPoint,id,false,User ID,Unique identifier for the user point,en-US
    UserPoint,technical_hash,true,,,en-US
    UserEvent,subcategory,false,Subcategory,The specific sub-category of the event,en-US
    UserEvent,subcategory_id,true,,,en-US
    UserEvent,title,false,Event Title,The main title or headline of the event,en-US
    UserEvent,region,false,Region,The geographic region associated with the event,en-US
    curl -H "Authorization:$MICS_API_TOKEN" \
         -X GET \
         --location "https://api.mediarithmics.com/v1/datamarts/$DATAMART_ID/graphdb_runtime_schemas/$SCHEMA_ID/schema_decorators"
    curl -H "Authorization:$MICS_API_TOKEN" \
         -X PUT \
         --location "https://api.mediarithmics.com/v1/datamarts/$DATAMART_ID/graphdb_runtime_schemas/$SCHEMA_ID/schema_decorators" \
         --data-raw "$(cat path/to/schema_decorators.csv)"

    Columns Specification

    Example

    Note on Character Encoding

    You must normalize strings by removing accents. Characters such as é, è, or à are not supported in the CSV file and should be replaced with their non-accented counterparts.

    Managing Decorators

    Via User Interface

    Via API

    Prerequisites

    Retrieve Current Decorators

    Update Decorators

    State: The data stored to build the result. It is the history. Each new activity updates the State.

    → the state is closely related to the Lookback Window - i.e. the historical depth of events to be analyzed.

  • Logic: The logic can be very simple (like a formula, a sum, a count…) or more complex (like a logical operation).

  • Result: The data calculated and stored. It contains the score(s) to be used.

    The result can be either a single variable or an object, depending on the complexity of the computation. It is computed from the State

  • Other interesting concepts to take into consideration:

    • Input Data: Either new userActivities, either userProfile update, either both.

    • Period Update: The regularity of updates (every x days - by default x=1).

    1. INITIAL – The instance is created with this status.

    2. INITIAL_LOADING – Once declared in the schema and successfully validated, an initial loading job is triggered.

    3. ACTIVE – The computed field becomes active if the job is completed successfully.

    To better understand how a computed field works, here are the technical steps and the relation with the methods:

    1. Initialization: The computed field is declared in the schema.

    2. State Updates: Triggered by new user activities or profile updates.

    3. Result Calculation: The result is computed based on the current state.

    4. Storage: The result is stored for querying.

    Technical concept

    Definitions

    Computed Field

    Computed Field Function

    Notions

    plugin
    process

    Lifecycle

    Technical flow

    Computed field lifecycle

    Number of active users per channel per day. The metric is users, grouped by channel_id and date_yyyymmdd dimensions, without filters.

  • Number of sessions per day for users who had an activity of type AD_VIEW on campaign 666. The metric is sessions, grouped by the date_yyyymmdd dimension with filter clauses activity_type = AD_VIEW and origin_campaign_id = 666

  • Days with more than 200k transactions on a specific channel. The metric is number_of_transactions, grouped ty the date_yyyymmdd dimension with filter clauses on channel_id = 666. Then a filter is applied on the calculated metric to only keep days with more than 200k transactions.

  • It can also be used to build custom dashboards. For more information, see Dashboards.

    Calling the API to get your first metrics is easy with your favorite tool that you already use to query other mediarithmics endpoints. See the API Quickstart guide to get started.

    • user_activities_analytics returns a customized report of your activities analytics data.

    See Dimensions en metrics for the complete list of supported dimensions and metrics.

    This endpoint is a mediarithmics Data cube. You can find documentation on how data cubes work and which data cubes are available in the specific documentation section.

    Activity analytics
    • Maximum recommended 5 queries per second.

    • Response time around 1 second.

    Quick start guide

    Available endpoints

    Supported dimensions and metrics

    How data cubes work

    Create an execution with your commands formatted in ndjson. Each line represents a user agent.

    Please note that the uploaded data is in ndjson and not json. That means the different deletions are not separated by commas, but by a line separator.

    A list of possible user_agent_id values can be found at

    This is only supported for datamarts using a UserPoint system version of v202205 or later.

    It only deletes the device point and its identifiers but not the associated UserPoint.

    How-to

    bulk import
    document import
    # Create the document import
    curl -X POST \
      https://api.mediarithmics.com/v1/datamarts/<DATAMART_ID>/document_imports \
      -H 'Authorization: <YOUR_API_TOKEN>' \
      -H 'Content-Type: application/json' \
      -d '{
    	"document_type": "USER_DEVICE_POINT_DELETION",
    	"mime_type": "APPLICATION_X_NDJSON",
    	"encoding": "utf-8",
    	"name": "<YOUR_DOCUMENT_IMPORT_NAME>"
    }'
    # Create the execution
    curl -X POST \
      https://api.mediarithmics.com/v1/datamarts/<DATAMART_ID>/document_imports/<DOCUMENT_IMPORT_ID>/executions \
      -H 'Authorization: <API_TOKEN>' \
      -H 'Content-Type: application/x-ndjson' \
      -d '
        { "type": "USER_AGENT", "user_agent_id": "vec:89998434" }
        { "type": "USER_AGENT", "user_agent_id": "udp:987654" }
      '

    Example

    If you want to pass device point ids directly ("udp:987654") you must do so using the USER_AGENT type.

    # Create the document import
    curl -X POST \
      https://api.mediarithmics.com/v1/datamarts/<DATAMART_ID>/document_imports \
      -H 'Authorization: <YOUR_API_TOKEN>' \
      -H 'Content-Type: application/json' \
      -d '{
    	"document_type": "USER_POINTS_DELETION",
    	"mime_type": "APPLICATION_X_NDJSON",
    	"encoding": "utf-8",
    	"name": "<YOUR_DOCUMENT_IMPORT_NAME>"
    }'
    # Create the execution
    curl -X POST \
      https://api.mediarithmics.com/v1/datamarts/<DATAMART_ID>/document_imports/<DOCUMENT_IMPORT_ID>/executions \
      -H 'Authorization: <API_TOKEN>' \
      -H 'Content-Type: application/x-ndjson' \
      -d '
        {
          "type": "USER_ACCOUNT",
          "compartment_id": "1000",
          "user_account_id": "8541254132"
        }
        {
          "type": "USER_EMAIL",
          "hash": "982f50d88d437d13bdbd541edfv4fe5176cc8d862f8cbe7ca4f0dc8ea"
        }
        { "type": "USER_AGENT", "user_agent_id": "vec:89998434" }
        { "type": "USER_AGENT", "user_agent_id": "udp:987654" }
        { "type": "USER_POINT", "user_point_id": "95772db3-e762-45da-8cf1-4893debffae7" }
      '

    Example

    execution
    User identifiers deletion

    Audience feeds

    Destination file

    Query exports

    Datamart replication

    audience feeds
    query exports
    OTQL queries
    Replicate your datamart

    UserProfile

    A UserProfile is usually imported from an existing information system, for example CRM, and login database. We usually see our customers using the profile to collect:

    • Contact details

    • User preferences

    • Status in a loyalty program

    • Subscription to a newsletter

    • CRM information

    • Scoring calculated outside the platform

    • Aggregated Values

    • other details

    Each UserProfile is associated with a UserPoint by a . It can also be linked to a UserAccount.

    Real time user tracking

    Online tracking aims at giving the ability to track unique users across digital properties. We support the following integrations in real time:

    • Website tracking

    • Application tracking

    With real-time user tracking, you send user events to mediarithmics that are aggregated and encapsulated into . Some user activities only have one user event, while others can have multiple events.

    For example, when you send hits from the JS Tag on a web site, mediarithmics aggregates all the events into sessions, creating one user activity per session.

    If registering a visit as IN_SESSION, the visit will go through the session aggregation step. We aggregate visits in sessions based on the provided identifiers. We close sessions after 30 minutes of inactivity or if a new event is recorded with a referrer from a different domain than the previously recorded. Visits registered as LIVE don't create sessions.

    When using the real-time tracking capability of mediarithmics, you enter what is called the User Activity Processing Pipeline. It allows mediarithmics to do some processing on your behalf.

    Here are the steps of processing, in order :

    1. At session closing or every minute if events are live, creation of a user activity.

    2. Execution of . They allow you to edit the events in the activity and add new ones based on their shapes.

    3. Application of the It is a plugin allowing you to execute code to transform each activity.

    The activity is finally stored.

    UTIQ martechpass

    Understand UTIQ identifiers

    UTIQ proposes two types of identifiers:

    • UTIQ martechpass (mobile): refers to identifiers coming from mobile network connections

    • UTIQ martechpass (fixed): refers to identifiers coming from internet box connections

    Subscribe to UTIQ

    To subscribe:

    1. Go to Navigator > Settings > Organisation > Compartments.

    2. In the Shared user account compartments section, click on Manage subscriptions.

    3. Subscribe to:

      • UTIQ martechpass (mobile)

      • UTIQ martechpass (fixed)

    UTIQ IDs can be ingested natively via the user-event-tag when users browse your websites.

    To enable automatic ingestion:

    1. Go to Navigator > Settings > Datamart > Channels.

    2. Select the site where you want to activate UTIQ capture.

    3. Under JS Tag Configuration > Device Identification, enable:

    The storage method for UTIQ identifiers depends on their type, which directly impacts how UserPoint are merged:

    • UTIQ martechpass (mobile): stored as UserAccount identifiers in compartment 20. The identifier value is provided in the user_account_id property. These act as reconciliation keys, triggering a when the same identifier is seen across different sessions.

    • UTIQ martechpass (fixed): stored as UserProfile in compartment 21. The identifier value is provided in the $utiq_martechpass_fixed property. These are anonymous profiles (no user_account_id and therefore not linked to any userAccount) and do not trigger any UserPoint merge.

    AMP tracking

    For the following integration to work, you must add the amp-analytics module on the page environment.

    Here is an example of the AMP tag:

    <amp-analytics type="mediarithmics">
      <script type="application/json">
        {
          "vars": {
            "site_token": <SITE_TOKEN>,
            "event_name": "amp-test-pageview"
          },
          "extraUrlParams": {
            "prop1": "value1",
            "prop2": "value2"
          }
        }
      </script>
    </amp-analytics>

    Arguments

    name

    type

    description

    Setup

    Application tracking

    In order to track activities on your application, you'll need to keep in mind the following :

    • All user activities need to be sent to mediarithmics using the

    • The should be used to authenticate any requests between your application and mediarithmics. Don't hesitate to contact your Account manager to have more information about this.

    Filters

    Dashboards can have filters in the top action bar.

    You can set up filters only in advanced mode using the available_filters property of your .

    The user can select a value and all the queries in the dashboard adapt to the selected value.

    A query fragment tells the dashboard how to adapt each query to the value(s) selected by the user.

    Here is a sample with a filter that enables the selection of compartments and an other for channels

    Development

    These functions are triggered during the initialization of the Datamart Function and whenever a new activity, profile update, or computed field modification occurs, updating the State accordingly.

    onUpdateActivity(state: State, userActivity: UserActivity): State

    • Inputs:

    BigQuery

    1. Make sure the BigQuery project has the correct API enabled

    2. Create dedicated datasets

    3. Create a dedicated service account with the right set of permissions

    UserAccount

    UserAccount identify a user registered on your different systems, like your CRM, a loyalty program or any authentication system. They have the following properties:

    Property
    Type
    Description

    LABEL

    The user-friendly name to display in the Segment Builder and Query Tool.

    HELP_TEXT

    A short description displayed as a tooltip when hovering over the question mark (?) icon in the platform.

    LOCALE

    The locale for the label. Currently, this must be set to en-US.

    site_token

    string

    site_token is the token of the website (required).

    event_name

    string

    event_name is the name of the event (optional, default to '$page_view').

    any custom property

    string

    All custom properties should be added to the extraUrlParams object (prop1, prop2 in the example).

    Drawing

    compartment_id

    String

    Compartment associated with the user account

    creation_ts

    Timestamp

    Account's creation timestamp

    expiration_ts

    Timestamp (optional)

    Account's eventual expiration timestamp

    Always use the user_account_id in correlation with a compartment_id to identify a user by its account. If you don't specify a compartment_id, then the default compartment will be used.

    A Compartment is a group that organizes specific user account identifiers. Each compartment has a unique ID that is used to identify the corresponding user account identifier. For instance, “UTIQ Martechpass” might have the compartment id 20.

    There are two categories of Compartments:

    • The First-party user account compartments which compartments contain user account identifiers created within your organization, such as CRM identifiers.

    • Shared user account compartments which include user account identifiers shared from another organisation.

    For instance, if you wish to add UTIQ to your datamart, first subscribe to it within your community organisation. It will then be automatically shared with your other organisations, but you’ll still need to activate it within your datamart.

    user_account_id

    String

    Definition

    Usually the same as the ID as the source, like your CRM.

    The compartment ID. If none, the profile is imported into the default compartment_id.

    $last_modified_ts

    Timestamp

    The timestamp of the last edit operation for this user profile. Automatically set by the system.

    $creation_ts

    Timestamp

    The timestamp of the creation operation for this user profile. Automatically set by the system.

    [any custom property]

    Any

    The value of a custom property

    field

    type

    description

    $user_account_id

    String (Optional)

    The associated UserAccount ID. If none, the profile remains anonymous.

    $compartment_id

    User profile object

    When importing profiles it is recommended to complete the $user_account_id and the $compartment_id event if the values are the same than the ones used as the identifier as the values are not inherited from the identifiers info. You can find more information about the user profiles import.

    Example:

    You can have different compartment IDs and different UserAccount between the one in the profile wrapper, as the UserPoint identifier and the one into the UserProfile object.

    user identifier

    Integer (Optional)

    UTIQ martechpass (mobile)
  • UTIQ martechpass (fixed)

  • Repeat this process for each website where UTIQ ID capture is

    required.

  • If you manage multiple datamarts, ensure UTIQ is activated on each one.

    You must subscribe to each type individually, depending on the identifiers you want to capture. The configuration steps are the same for both mobile and fixed identifiers.

    Activate UTIQ ingestion from your websites

    Storage and impact on user point merges

    User Point merge
    state: Current state object.
  • userActivity: New user activity data.

  • Outputs: Updated state object.

  • What It Does: Updates the state with new user activities and removes outdated activities.

  • Example:

  • onUpdateUserProfile(state: State, userProfile: UserProfile, operation: core.Operation): State

    • Inputs:

      • state: Current state object.

      • userProfile: Updated userProfile data.

      • operation: Operation type (enum: UPDATE | DELETE).

    • Outputs: Updated state object.

    • What It Does: Handles updates to userProfile.

    • Example:

    onUpdateComputedFields(state: State | null): Result

    • Inputs: state: Current state object or null.

    • Outputs: Result object.

    • What It Does: Computes the result from the current state.

    • Example:

    buildResult(state: State | null): Result

    • Inputs: state: Current state object or null.

    • Outputs: Result object.

    • What It Does: Computes the result from the current state.

    • Example:

    Before deploying the plugin, create tests to ensure the function behaves as expected.

    Test cases might include:

    • Adding new activities, and update profiles and verifying the state is updated correctly. Check that the order we send profile updates and activities has no impact.

    • Checking that activities which are no more relevant to compute the result are removed from the state.

    • Validating that the correct values are returned in the result.

    • How to decide if we create 1 or several plugin(s)? (example with 2 scores)

      • If the required data in the state is the same for both scores → 1 plugin

      • If the required data in the state is different (state is polymorph) → 2 plugins

    • Always return the same state in case of error, or null. Otherwise, we delete the state, and so reset the result.

    • Maximize the number of scores calculated by a Computed Field Function to optimize performance. Therefore, the same state is used to calculate multiple scores, and we avoid storing the same state multiple times.

    • Ensure that the state is designed to store relevant information efficiently

    • Ensure that the state is commutative to maintain consistency while building the result. ie. state activities and profiles data updates can happend in any order

    • Be sure to have a cleaning rule to update the state base on the defined lookback window for both userProfile and userActivities.

      • In other words, when updating the state, be sure to remove the data that are no more useful to compute the result, in order to limit the state size.

    • When editing a live computed field, you must relaunch an Initial Loading through API.

    List of Methods

    OnUpdate methods

    These methods must be commutative to ensure consistency during initial loading, where event order is not guaranteed. It should always produce the same result, regardless of the sequence in which events are processed.

    To prevent system overload, the State size is restricted to a maximum of 1 MB. If this limit is exceeded, the update will be discarded and not saved.

    onUpdateActivity

    The activities or profiles received by the plugin are raw data, so you can't rely on the structure defined in your schema to understand its design. However, you can refer to the structure outlined on the User Lookup page.

    onUpdateUserProfile

    onUpdateComputedFields

    This method must be implemented, even if it not currently used.

    Please return the same state.

    buildResult

    Test

    Best Practices

    # UserProfile object 
    {
        "$compartment_id": 1606,
        "$user_account_id": "c9879698769OIUYOIY9879879",
        "$last_modified_ts": 5467987654613,
        "$creation_ts": 6579874654654654,
        "firstname": "David",
        "lastname": "Guetta",
        "gender": 1,
        "newsletter_options": {
            "subscribed": true,
            "preferred_periods": "MONTHLY"
        }
        
    }
    # Complete payload when importing a profile 
    { 
        "operation": "UPSERT",
        "compartment_id": "1600", 
        "user_account_id": "identifier_account_id",
        "force_replace": true,
        "user_profile": {
            "$compartment_id": 1606,
            "$user_account_id": "c9879698769OIUYOIY9879879",
            "$last_modified_ts": 5467987654613,
            "$creation_ts": 6579874654654654,
            "firstname": "David",
            "lastname": "Guetta",
            "gender": 1,
            "newsletter_options": {
                "subscribed": true,
                "preferred_periods": "MONTHLY"
            }
        }
    }
    {
        "type": "USER_ACCOUNT",
        "user_account_id": "mt1-k4LwxGWEn-...........",
        "creation_ts": 1770466916312,
        "compartment_id": 20,
        "expiration_ts": 1778241090397
    }
        {
            "$compartment_id": "21",
            "$last_modified_ts": 1774049259779,
            "$expiration_ts": 1779898252683,
            "$creation_ts": 1774049244368,
            "$utiq_martechpass_fixed": "mt2-k4LwxGWEn-..........."
        }
    // Trigger by a new activity
    onUpdateActivity(state, userActivity) {
        // Logic to update state
        return updatedState;
    }
    // Trigger by an update on the UserProfile
    onUpdateUserProfile(state, userProfile, operation) {
        // Logic to handle UserProfile updates
        return updatedState;
    }
    // Trigger by the result computation of another computed field
    onUpdateComputedFields(state) {
        // Logic to compute result
        return state;
    }
    buildResult(state) {
        // Logic to compute result
        return result;
    }

    Detection of query-based conversions. Conversions relying on pixels skip this step.

  • Evaluation of automations triggers "React to an event". If the ongoing activity matches the trigger, the UserPoint enters the scenario.

  • UserChoice management ensures the data you ingest is compatible with GDPR and other regulations.

  • Use this feature if you want to track in real time what your users are doing on your digital touch points.

    If your need is to mass import activities, users or CRM profiles, you should consider Bulk Imports.

    User activities and events

    Session aggregation

    The processing pipeline

    API tracking
    Conversion tracking
    AMP tracking
    Email tracking
    Display campaign tracking
    user activities
    UserActivity & UserEvent
    event rules
    activity analyzer.
    Results date range for the 4 latest months.
    Wait until the end of the initial loading
  • Use your computed field

  • Check the following documentation to learn more about Plugin development. Bellow are some precisions about specific Computed fields Function implementation.

    These 3 functions are triggered during the initialization of the Computed Field Function and whenever a new activity, profile update, or computed field modification occurs, updating the State accordingly.

    You can find the list of all the methods to be developed here.

    This function returns the result of the computed field function for a specific State. The Result will be stored for a defined duration, and querying the field will return the stored value during that period.

    You can find all the details about this method here.

    Follow the standard procedure to create a plugin with the type COMPUTED_FIELD_FUNCTION. Once the plugin is created, you can generate a new version from the build.

    1. In the Navigator > Settings > Datamart, navigate to Computed Fields.

    2. Add a new computed field.

    3. Select the plugin and version of the new instance you want to use.

    4. Complete the necessary fields:

    Fields
    Description

    Name

    Name of the computed field

    Description

    (Optional) Describe the computed field

    Technical name

    Name of the computed field used in the schema

    This will set up the computed field linked to your computedfield function for use in the schema.

    After creating the computed field, you need to connect it to your schema:

    1. Use the directive @ComputedField(technical_name = "...") at the appropriate level of your schema.

    2. Ensure the technical name matches the one used when creating the computed field.

    This will integrate the computed field into your schema and make it available for use in queries and operations.

    A schema validation will be triggered when you click Save. It will ensure that your Datamart has access to all the declared computed fields and verify their integration with the schema.

    Once your schema is validated, our service will run a job to initialize your computed field and set the state to match the current status of the timeline. For each UserPoint in your Datamart, we will process their timeline and execute the OnUpdateXXX() function.

    To monitor the progress:

    1. Go to the Computing Console > Computed Fields.

    2. Check if your computed field is ready or if the initial loading is still in progress.

    Please note, this process may take some time to complete (up to 72h) as it computes the timelines for all UserPoint.

    Once the initial loading is complete, you can start using your computed field just like any other standard field in mediarithmics features.

    For example, in query tools or any OTQL query:

    If your computed field is indexed, you can also perform queries like:

    This allows you to incorporate the computed field into your data analysis and queries once it's fully initialized.

    Computed fields are created as of plugin, requiring collaboration with mediarithmics Professional Services (PS) team.

    The implementation involves defining the logic, writing plugin specifications, developing the plugin, and configuring the computed fields.

    Please discuss your needs with your account manager.

    Create your computed field function (plugin)
    Create your computed field within the platform
    Declare your computed field in your schema
    // Example in your schema 
    type UserPoint {
      id: ID!
      accounts: [UserAccount]
      …
      rfm_score: RfmScore @ComputedField(technical_name = “RfmScore”) @TreeIndex(index:"USER_INDEX")
    }
    
    type RfmScore {
      …
    }
    SELECT { rfm_score } FROM UserPoint
    SELECT { id } FROM UserPoint WHERE rfm_score = "PASSIVE"

    Step 1: Create your computed field function (plugin)

    Develop the plugin with the SDK and create a build from it

    You are required to implement 4 key functions from the Plugin SDK.

    OnUpdate functions

    Although onUpdateComputedField has not been released yet, it is still required to be implemented in your plugin. In the meantime, simply return the State directly to avoid any errors.

    BuildResult

    Create a plugin and a version

    Step 2: Create your computed field within the platform

    Step 3: Declare your computed field in your schema

    The computed field must be in the UserPoint object.

    Step 4: Wait until the end of the initial loading

    Avoid using your computed field until the initial loading is complete. While the query will not return an error, the result may be inaccurate during this process.

    Step 5: Use your computed field

    The activity and events in the payload need to comply with the specificities described below
  • The user agent identifier ($user_agent_id) needs to be particularly formatted using guidelines described here

  • The first option is to integrate a small piece of code (approx. 100 lines) into the application to execute calls to the mediarithmics tracking API. Sample code for iOS and Android is available in the Authentication section (see illustration below).

    The second option is to re-use an already existing analytics tool. It is then possible to transfer events from the analytics solution's server to the mediarithmics API.

    In the context of app tracking, predefined event names are available out-of-the-box to simplify and automate event processing (full list of predefined event names):

    • app open event ($app_open) corresponds to the opening of the app and app resume event (when the app becomes active again)

    • app install event ($app_install)

    • app update event ($app_update)

    The install and update events are automatically calculated on server side and you don't have to send them :

    • The install event ($app_install) is triggered the first time an app open event is received for a user, regardless if the user is new or existing.

    • The update event ($app_update) is triggered when the SDK version, app version or OS version changes from one open to the next.

    In the context of mobile app tracking, you should adapt some fields of the UserActivity. Here are the fields to look out for :

    Field
    Type
    Description

    $type

    String enum

    The activity type should only be APP_VISIT

    $session_status

    String enum

    In the context of CTV app tracking, you should adapt some fields of the UserActivity. Here are the fields to look out for :

    Field
    Type
    Description

    $type

    String enum

    The activity type should only be CTV_VISIT

    $session_status

    String enum

    Setup summary

    Tracking API
    Signature authentication

    Application integration options

    Predefined event names

    Mobile application tracking - UserActivity formatting

    CTV application tracking - UserActivity formatting

    For CTV application tracking, we allow automatic capture of IP addresses.

    Generate a credentials JSON file
    • In the Google Cloud Console, navigate to the APIs & Services > Library page.

    • In the search bar, type "Cloud Resource Manager API".

    • Click on the search result for the Cloud Resource Manager API and click the Enable button

    We recommend to create two dedicated datasets for mediarithmics' usage.

    • mics_workspace dataset that holds all temporary tables created while syncing with your warehouse

    • mics_output dataset that holds all output tables — the clean results of daily processing, ready for consumption

    We recommend using a dedicated service account with the appropriate set of permissions.

    To create a service account follow these steps :

    • Go to https://console.cloud.google.com/iam-admin/serviceaccounts

    • Select you project

    • Click on “Create service account”

    • Input the necessary informations : service account name, service account id (automatically generated), description. Click on “Create and continue”

    • We recommend giving the service account Read only access to your data by giving the following roles at the project level :

      • bigquery.jobUser

      • bigquery.dataViewer

    • In addition, the service account should also have the following role on the mics_output and mics_workspace datasets

      • bigquery.dataEditor

    To export a credentials JSON file follow these steps :

    • Go to https://console.cloud.google.com/iam-admin/serviceaccounts

    • Select you project

    • Select your service account and on the “…” menu select “Manage keys”

    • Then click on “Add key”>”Create new key”

    • Select JSON then “Create”

    • The key is automatically downloaded

    Steps

    CREATE SCHEMA IF NOT EXISTS `project-name.mics_workspace`
    OPTIONS (
      location = 'EU',
      description = 'Working schema for mediarithmics'
    );
    
    CREATE SCHEMA IF NOT EXISTS `project-name.mics_output`
    OPTIONS (
      location = 'EU',
      description = 'Output schema for mediarithmics'
    );

    1. Enable Cloud Resource Manager API

    2. Create dedicated datasets

    Note that the tables in mics_output are not meant to be interface tables : their schema could change with successive releases. If you need a specific stable table schema to expose it to other tools, please contact your account manager.

    Nota bene : If you wish to use a that handles updates and deletes of data, you will need a (i.e. the mics_workspace dataset)

    3. Service account creation and permissions

    Grant access

    If you do not want to give the bigquery.dataViewer role at the project level, you can assign it only to specific datasets, tables or views in your project. If you do that then you should add the following permissions at the project level :

    • bigquery.datasets.get

    4. Generate a credentials JSON file

    Note you need to have at least the roles/iam.serviceAccountKeyAdmin role to perform these actions

    JSON representation
    {
        // Using technical names of compartments, segments or channels 
        // will result in IDs being automatically replaced by names in the UI
        "technical_name": String, 
        "title": String,
        "values_retrieve_method": 'Query', // Only available value at the moment
        // OTQL query to retrieve list of selectable values
        // Use a query string, not the ID of a query
        "values_query": String, 
        // How to adapt queries in the dashboard to the selected value(s)
        "query_fragments": [QueryFragment], 
        "multi_select": Boolean, // If the user can select multiple values
    }
    JSON representation
    {
        // Any available data source such as 'activities_analytics' or 'OTQL'
        "type": String, 
        // Only for OTQL type, chooses which queries should be transformed
        // Select 'ActivityEvent' to transform queries FROM ActivityEvent
        "starting_object_type": String,
        // The query part to add 
        "fragment": String,
    }
    {
        "available_filters": [
            {
                "values_retrieve_method": "query",
                "values_query": "SELECT {compartment_id @map} FROM UserProfile",
                "technical_name": "compartments",
                "query_fragments": [
                    {
                        "type": "OTQL",
                        "starting_object_type": "UserPoint",
                        "fragment": "profiles {compartment_id IN $values}"
                    },
                    {
                        "type": "OTQL",
                        "starting_object_type": "UserProfile",
                        "fragment": "compartment_id IN $values"
                    }
                ],
                "multi_select": true,
                "title": "Data provider"
            },
            {
                "values_retrieve_method": "query",
                "values_query": "SELECT {channel_id @map} FROM UserEvent",
                "technical_name": "channels",
                "query_fragments": [
                    {
                        "type": "OTQL",
                        "starting_object_type": "UserPoint",
                        "fragment": "events {channel_id IN $values}"
                    },
                    {
                        "type": "OTQL",
                        "starting_object_type": "UserEvent",
                        "fragment": "channel_id IN $values"
                    },
                     {
                        "type": "activities_analytics",
                        "fragment": [
                            {
                                "dimension_name": "channel_id",
                                "operator": "IN_LIST",
                                "not": false,
                                "expressions": "$values"
                            }
                        ]
                    }
                ],
                "multi_select": true,
                "title": "Channels"
            }
        ],
        "sections": ...
    }
    Compartment and channel filter in the top action bar

    Examples

    Context for the following example

    To demonstrate how the computed field works, consider this use case:

    Goal: Calculate the sales over 12 months for items in the IT category per user.

    For simplicity, this example focuses on the IT category. However, the computed field can be scaled to compute the amount for all categories, not just IT.

    In this scenario, the computed field will:

    1. Aggregate the order amounts over the last 12 months.

    2. Filter the data based on the IT category (or any other category, depending on the use case).

    By scaling this approach, you can calculate the sales amount for multiple categories, ensuring flexibility and extensibility in your calculations.

    In this use case, we need to declare the State, Result, and UserActivity for computing the sales amount over the last 12 months for items in the IT category.

    The State stores the order amounts for each day, categorized by IT items, for the last 12 months. Here's how the state structure looks :

    The activities_for_the_last_12_months keeps the amount data for each day, where the date is represented by a numeric value (e.g., timestamp), and the amount is the total order value for that day.

    The Result represents the total sales amount over the last 12 months for the IT category.

    The result will return the computed IT_amount_for_the_last_12_months after summing up the values stored in the state.

    The UserActivity defines the structure of the activity that triggers the update. In this example, we focus on the items bought, particularly in the IT category.

    The items_bought array contains details about each item, such as category (IT, for example) and price.

    With the context declared, you can implement your computed field logic. Here's how the MyComputedField class looks:

    • Goal: Update the state with new IT category purchases and remove activities older than 12 months.

      • It filters the UserActivity to ensure only IT items are included.

      • Removes old activities beyond the 12-month period.

    • Goal: Sum all the basket amounts stored in the state and return the total.

      • It checks each stored activity date to ensure it is within the last 12 months and sums the amount for each IT purchase.

    Before deploying the plugin, create tests to ensure the function behaves as expected. Test cases might include:

    • Adding new activities and verifying the state is updated correctly.

    • Checking that old activities are purged.

    • Validating that the correct basket amounts are returned in the result.

    Once the computed field is implemented, you need to declare it in your schema as follows:

    This will link the computed field (IT_amount_for_the_last_12_months) to your schema, making it available for querying.


    When working with profile and activity information:

    Be mindful that the computed field needs to be commutative during the initial loading. For cases where UserProfile and UserActivity need to be aggregated, it might be necessary to store more information in the State to ensure consistency and accuracy during this phase.

    Example use-case: Basket amount by fidelity card

    During initial loading, if you need to track the basket amount for current fidelity cards, you may need to store all activities grouped by fidelity card in the state. This is because, until the initial loading completes, you may not know which fidelity cards are currently active for the user.

    User choices import

    Use this feature to UPSERT or DELETE user_choices in your datamart.

    How-to

    Use the bulk import endpoints to create a document import with theUSER_CHOICEdocument type and APPLICATION_X_NDJSON mime type. Only ndjson data is supported for user choices.

    Then, create an execution with your user choice import commands formatted in ndjson .

    User choice import command

    Each line in the uploaded file can have the following properties:

    Monitoring a feed

    Accessing the feed

    1. Go to the Segment: Navigate to the segment where your feed is configured.

    2. Open Feed Options: Click the menu button and choose either Stats or Edit.

    Feed details overview

    The feed details are divided into three sections to enhance understanding:

    1. :

      • Provides a high-level summary of the feed.

      • Shows the status of the feed instance.

      • Displays the identifiers sent to the partner for addition or deletion.

    2. :

      • Lists all plugin properties configured for the current instance.

    3. :

      • Offers an in-depth view of processing steps, aiding in the investigation of anomalies.

    The Stats tab is tailored for non-technical users to easily assess feed activity. It shows whether the feed is successfully transmitting identifiers to the destination platform.

    1. Creation:

      • Waiting for Activation: The feed card is created on the segment but remains inactive.

      • Feed Activated: The feed creates the segment on the destination platform (triggers the onExternalSegmentCreation function).

    • Successful Identifier Transactions: number of upserts or deletions of identifiers successfully sent during the selected period.

    • Identifier Coverage: percentage of UserPoint without any identifiers sent to the destination platform.

    • Daily Graph: visual representation of upserts or deletions sent daily.

    Client-side feeds have simpler functionality but use a similar interface.

    • PAUSED: the feed card is created but not activated.

    • ACTIVE: the feed is activated on the segment and the feed is downloaded by the browser.

    • Daily Downloads: number of times the feed was downloaded by the browser during the selected period.

    The Configuration tab displays the plugin properties for the feed instance:

    • Plugin properties layout is determined during the creation of the plugin version.

    • These values can only be modified when the feed is not activated. Once activated, the configuration becomes read-only.

    The Troubleshooting tab is designed for technical users, providing detailed insights into:

    • Successful and failed operations (e.g., upserts and deletions).

    • Errors and processing steps for investigating anomalies.

    • Server-Side and Client-Side feeds:

      • Resource details, plugin information, and plugin version information.

    • Server-Side Feeds only:

    1. API Calls to the Audience Feed Plugin:

      • Displays response status for /user_segment_update calls.

    2. Identifiers Sent to the Destination Platform:

    • Push: Adding a UserPoint to the segment or an identifier to a UserPoint.

    • Remove: Removing a UserPoint from the segment or an identifier from a UserPoint.

    • Statuses:

    • API Calls to the Audience Feed Plugin (/batch_update route):

      • Number and status of batches created.

    • Records Sent to the Destination Platform:

    • Files Sent by File Delivery Service:

      • Number of files sent and response statuses.

    • Records Sent to the Destination Platform:

    • Displays a daily graph of browser downloads, as shown in the Stats tab.

    Snowflake

    Steps

    1. Service account and permissions setup

    2. Create dedicated schemas

    3. Configure key-pair authentication

    4. Create and format a credentials JSON file

    For the initial set up, start with the SQL script template below. The script will :

    • Create a dedicated service account, role, and warehouse for mediarithmics to use

    • Give the service account read only access on a database of your choice and all its content

    We recommend to create two dedicated schemas for mediarithmics' usage.

    • mics_workspace schema that holds all temporary tables created while syncing with your warehouse

    • mics_output schema that holds all output tables — the clean results of daily processing, ready for consumption

    The service account you created should have full access (read/write) on both schemas. Use this code to do so :

    Use the following command to generate a private key (called rsa_key.p8)

    Then use the following command to generate a public key (called rsa_key.pub linked to the private key called rsa_key.pub stored in the current directory)

    Then, from the Snowflake interface or the Snowflake CLI run the following SQL query to assign the public key generated at step 1 (rsa_key.pub) to the service account created for mediarithmics to use :

    Now you need to generate a JSON file with the following format :

    • "user" : the user you associated the public key with

    • "account" : the "account" property is what is called "Account identifier" in Snowflake. It's usually the organization name and the account name hyphenated

    • "database" : the database containing the data you want to make available to mediarithmics

    Create a data warehouse

    To declare a new data warehouse go to the Computing console, under the Data Store section you will find the Data warehouse menu.

    Select your Cloud Data warehouse provider and define the following properties :

    • A name

    • A description

    • A location (BigQuery only)

    • A working dataset/schema ()

    Then upload or drag and drop your credentials file. If the credentials file contains the correct set of permissions, the data warehouse will be created. If not, an error will be raised.

    Segments import

    Use this feature to add or remove from .

    1. Use the endpoints to create a with theUSER_SEGMENTdocument type and APPLICATION_X_NDJSON or TEXT_CSV mime type.

    UserActivity API

    The user activities endpoint gives you the ability to retrieve & delete any activities (and attached events) on a given UserPoint.

    GET https://api.mediarithmics.com/v1/datamarts/:datamartId/user_timelines/:userpointId/user_activities?filters=:filters

    Name
    Type
    Description

    Compute period (in days)

    Maximal duration before the periodic update of the Result in days.

    Events filter

    GraphQL selector query to filter the activity which will trigger the State updates

    Connection:

    • The feed tests the connection with the destination platform (triggers the onExternalSegmentConnection function).

  • Starting:

    • The feed begins transmitting identifiers to the destination platform.

  • Initial Loading:

    • Processes all users in the segment and sends their identifiers to the destination.

  • Live:

    • Continues to send new identifiers and requests deletion of those no longer present in the segment.

  • Instance details and initial loading logs.

    Shows processed identifiers and their statuses for non-batching cases.

    PROCESSED: Successful with no destination platform response (e.g., batch/file delivery).
  • SUCCEEDED: Successful with a positive response from the destination platform.

  • FAILED: Error occurred within the plugin or at the destination platform.

  • NO_ELIGIBLE_IDENTIFIERS: No eligible identifiers to send.

  • Rows sent per batch (may contain multiple identifiers).
    Rows sent per file (may represent multiple identifiers).

    Stats: high-level overview of the feed

    Server-side feeds

    Feed lifecycle

    Sending metrics

    Client-side feed

    Feed lifecycle

    Sending metrics

    Configuration: plugin properties setup

    Troubleshooting: technical details

    General information

    Metrics for server-side feeds

    Standard Metrics:

    Actions and Statuses:

    Batching Metrics:

    File Delivery Metrics:

    Metrics for Client-Side Feeds

    Stats
    Configuration
    Troubleshooting
    learn more

    The sessions status should be: IN_SESSION: This value should be used if you’re making one API call per tracked event (recommended way). The platform will automatically aggregate all the events of a session sent through many API calls when this value is used. CLOSED_SESSION: should be used only if you do a single API call per session at its end. In this case, you should provide ALL the events of the session in the $events array in the call. Each API call with this value will generate a new User Activity in the Platform.

    $user_agent_id

    String (Optional)

    The user agent identifier of the user device containing a unified representation of an identifier

    $app_id

    String

    The mobile app id (previously created through Navigator / API)

    The sessions status should be: IN_SESSION: This value should be used if you’re making one API call per tracked event (recommended way). The platform will automatically aggregate all the events of a session sent through many API calls when this value is used. CLOSED_SESSION: should be used only if you do a single API call per session at its end. In this case, you should provide ALL the events of the session in the $events array in the call. Each API call with this value will generate a new User Activity in the Platform.

    $user_agent_id

    String (Optional)

    The user agent identifier of the user device containing a unified representation of an identifier.

    $ctv_id

    String

    The ctv app id (previously created through Navigator / API)

    Learn more

    bigquery.tables.list

  • bigquery.tables.get

  • To assign these customs permissions you should create a custom role than carries the bigquery.jobUser role and the bigquery.datasets.get bigquery.tables.list bigquery.tables.get permissions.

    If the bigquery.dataViewer role is even too much, you can assign the bigquery.tables.getData permission at a table level only.

    Grant limited access

    synchronization strategy
    working dataset

    Step 1: Define your context for the Datamart Function

    State Declaration

    Result Declaration

    UserActivity Declaration

    To get some examples of your activity structure, you can look at the activity returned in the User lookup page in Navigator.

    Step 2: Declare your Computed Field class

    onUpdateActivity

    Best practice: Use the Events filter to exclude activities or profiles that are not relevant to your computed field, rather than adding a filter within your function.

    buildResult

    The onUpdateActivity function is triggered only when a new activity occurs. Therefore, you need to handle outdated activities within your function if the UserPoint does not receive a new event to update the State.

    Step 3: Test your plugin

    Step 4: Declare your Computed Field in the schema

    Handling Profile and Activity Information

  • "private key" : the private key generated in step 3 and associated to the user public key. Be ware of the formatting of the private key : the key must be in on a single line, this means you should use a "\n" separator at each return to line of the private key.

  • For more information on Snowflake key-pair authentication please refer to Snowflake documentation https://docs.snowflake.com/en/user-guide/key-pair-auth

    1. Service account and permissions setup

    Grant limited access

    If you wish to restrict access to specific tables or views the minimum permissions required are :

    • USAGE on DATABASE

    • USAGE on SCHEMA

    • SELECT on TABLES (or VIEWS)

    2. Create dedicated schemas

    Nota bene : If you wish to use a synchronization strategy that handles updates and deletes of data, you will need a working schema (i.e. the mics_workspace dataset)

    Note that the tables in mics_output are not meant to be interface tables : their schema could change with successive releases. If you need a specific stable table schema to expose it to other tools, please contact your account manager.

    3. Configure key-pair authentication

    Nota bene :

    • Exclude the public key delimiters in the SQL statement

    • To run this query you will need one of the following role/privilege

      • The MODIFY PROGRAMMATIC AUTHENTICATION METHODS or OWNERSHIP privilege on the user

      • The SECURITYADMIN role or higher

    4. Edit a credentials file

    Use cases

    This page demonstrates different useful queries that can be handled through the activities analytics API

    Number of active users

    Number of activities per day

    Values of a dimension

    Active users and the revenue per day per device form factor on a specific channel

    More use cases

    You can create any use case you want using the list of dimensions and metrics that are available.

    datamartId*

    String

    The ID of the datamart want to retrieve activities for

    userpointId*

    String

    The ID of the UserPoint you want to retrieve activities for

    Name
    Type
    Description

    filters

    String

    Filter(s) to select appropriat user activities

    {
        // Response
    }

    DELETE https://api.mediarithmics.com/v1/datamarts/:datamartId/user_timelines/:userpointId/user_activities?filters=:filters

    Name
    Type
    Description

    datamartId*

    String

    The ID of the datamart want to retrieve activities for

    userpointId*

    String

    The ID of the UserPoint you want to retrieve activities for

    Name
    Type
    Description

    filters

    String

    Filter(s) to select appropriat user activities

    As mentionned above, filters are optional and give you the ability to narrow your query. You can apply filters on any custom fields you have in your activity object as well as the following proprietary fields:

    • $unique_key

    • $type

    • $channel_id

    • $ts (through start_ts & end_ts keywords)

    To apply any filter, mention the field on which you want your filter to be applied, followed by double equal (==), then by value(s) for the field to be matched against.

    Note that:

    • You can provide in your query multiple filters by seperating filters with a comma (,). In that case, it will be considered as an "AND" between those filters

    • A filter can take multiple values by separating values with a pipe (|). In that case, it will be considered as an "OR" between those values

    Retrieve activities & events from a UserPoint

    Path Parameters

    Query Parameters

    Delete activities & events from a UserPoint

    Path Parameters

    Query Parameters

    Filters

    Query examples

    export interface State {
      activities_for_the_last_12 _months: { 
        [date: number] : [{
          amount: number;
        }]
      }
    }
    export interface Result {
      IT_amount_for_the_last_12_months: number;
    }
    interface Items {
        category: string;
        price: number;
    }
    
    interface UserActivity {
      items_bought: Items[];
    }
    export class MyComputedField extends core.ComputedFieldPlugin<State, Result, UserActivity, UserProfile, ComputedField> { 
        constructor() { 
            super(); 
        }
     
        // Function to Update the state
        onUpdateActivity(state: State, userActivity: UserActivity): State { ... }
        
        // Won't be used but need to be declared;
        onUpdateUserProfile(state: State, userProfile: UserProfile, operation: core.Operation): State {
           return state;
        }
    
        // Won't be used but need to be declared;
        onUpdateComputedField(state: State, computedField: ComputedField): State {
            return state;
        }
      
        // Function to compute the Result
        buildResult(state: State | null): Result { ... }
    }
    type UserPoint {
      id: ID!
      accounts: [UserAccount]
      …
      IT_amount_for_the_last_12_months: Int! @ComputedField(technical_name = “IT_Amount”) @TreeIndex(index:"USER_INDEX")
    }
    -- =============================================================
    -- Setup variables - update these values for your environment
    -- =============================================================
    SET mics_username          = 'MICS_USER';
    SET mics_default_warehouse = 'MICS_WAREHOUSE';
    SET mics_database          = '<database>';
    SET mics_default_namespace = '<database.schema>';
    SET mics_default_role      = 'MICS_USER_ROLE';
    
    -- =============================================================
    -- Switch to admin role
    -- =============================================================
    USE ROLE ACCOUNTADMIN;
    
    -- =============================================================
    -- Provision resources: warehouse, role and service user
    -- =============================================================
    CREATE WAREHOUSE IF NOT EXISTS identifier($mics_default_warehouse);
    CREATE ROLE IF NOT EXISTS identifier($mics_default_role);
    
    CREATE USER IF NOT EXISTS identifier($mics_username)
        TYPE              = SERVICE
        DEFAULT_WAREHOUSE = $mics_default_warehouse
        DEFAULT_NAMESPACE = $mics_default_namespace
        DEFAULT_ROLE      = $mics_default_role;
    
    -- =============================================================
    -- Role assignments
    -- =============================================================
    GRANT ROLE identifier($mics_default_role) TO ROLE SYSADMIN;
    GRANT ROLE identifier($mics_default_role) TO USER identifier($mics_username);
    
    -- =============================================================
    -- Warehouse access
    -- =============================================================
    GRANT USAGE ON WAREHOUSE identifier($mics_default_warehouse) TO ROLE identifier($mics_default_role);
    
    -- =============================================================
    -- Read-only access on the database, schemas, tables and views
    -- (includes future objects to cover tables/views created later)
    -- =============================================================
    GRANT USAGE  ON DATABASE identifier($mics_database)                       TO ROLE identifier($mics_default_role);
    GRANT USAGE  ON ALL SCHEMAS       IN DATABASE identifier($mics_database)  TO ROLE identifier($mics_default_role);
    GRANT SELECT ON ALL TABLES        IN DATABASE identifier($mics_database)  TO ROLE identifier($mics_default_role);
    GRANT SELECT ON ALL VIEWS         IN DATABASE identifier($mics_database)  TO ROLE identifier($mics_default_role);
    GRANT SELECT ON FUTURE TABLES     IN DATABASE identifier($mics_database)  TO ROLE identifier($mics_default_role);
    GRANT SELECT ON FUTURE VIEWS      IN DATABASE identifier($mics_database)  TO ROLE identifier($mics_default_role);
    -- =============================================================
    -- Dedicated schemas with full ownership
    -- =============================================================
    SET mics_database = '<database>';
    
    USE ROLE ACCOUNTADMIN;
    USE DATABASE IDENTIFIER($mics_database);
    
    CREATE SCHEMA IF NOT EXISTS mics_workspace;
    GRANT OWNERSHIP ON SCHEMA mics_workspace TO ROLE MICS_USER_ROLE;
    
    CREATE SCHEMA IF NOT EXISTS mics_output;
    GRANT OWNERSHIP ON SCHEMA mics_output TO ROLE MICS_USER_ROLE;
    openssl genrsa 2048 | openssl pkcs8 -topk8 -inform PEM -out rsa_key.p8 -nocrypt
    openssl rsa -in rsa_key.p8 -pubout -out rsa_key.pub
    ALTER USER <MICS_USER> SET RSA_PUBLIC_KEY='MIIBIjANBgkqh...';
    {
    "user" : "MICS_USER",
    "account" : "ORGANIZATION_NAME-ACCOUNT_NAME",
    "database" : "DATABASE",
    "private_key" : "-----BEGIN PRIVATE KEY-----\nMII..."
    }
    Request object
    {
        "date_ranges": [
            {
                "start_date": "2021-09-26T00:00:00",
                "end_date": "2021-10-28T23:59:59"
            }
        ],
        "dimensions": [],
        "metrics": [
             {
                "expression": "users"
            }
        ]
    }
    Response
     "report_view": {
        "items_per_page": 100,
        "total_items": 1,
        "columns_headers": [
            "users"
        ],
        "rows": [
            [
                114353272
            ]
        ]
    }
    Request object
    {
        "date_ranges": [
            {
                "start_date": "2021-10-20T00:00:00",
                "end_date": "2021-10-28T23:59:59"
            }
        ],
        "dimensions": [
            {"name": "date_yyyymmdd"}
        ],
        "metrics": [
             {
                "expression": "sessions"
            }
        ]
    }
    Response
      "report_view": {
        "items_per_page": 100,
        "total_items": 9,
        "columns_headers": [
            "date_yyyymmdd",
            "sessions"
        ],
        "rows": [
            [
                "20211020",
                1372624
            ],
            [
                "20211021",
                1368085
            ],
            ...
        ]
    }
    Request object
    {
        "date_ranges": [
            {
                "start_date": "2021-10-20T00:00:00",
                "end_date": "2021-10-28T23:59:59"
            }
        ],
        "dimensions": [
            {"name": "type"}
        ],
        "metrics": [
        ]
    }
    Response
    "report_view": {
        "items_per_page": 100,
        "total_items": 4,
        "columns_headers": [
            "type"
        ],
        "rows": [
            [
                "DISPLAY_AD"
            ],
            [
                "SITE_VISIT"
            ],
            [
                "USER_SCENARIO_NODE_ENTER"
            ],
            [
                "USER_SCENARIO_NODE_EXIT"
            ]
        ]
    }
    Request object
    {
        "date_ranges": [
            {
                "start_date": "2021-10-20T00:00:00",
                "end_date": "2021-10-28T23:59:59"
            }
        ],
        "dimensions": [
            {"name": "date_yyyymmdd"},
            {"name": "device_form_factor"}
        ],
         "dimension_filter_clauses": {
            "operator": "AND",
            "filters": [
                {
                    "dimension_name": "channel_id",
                    "operator": "EXACT",
                    "not": false,
                    "expressions": [
                        "666"
                    ]
                }
            ]
        },
        "metrics": [
            {"expression": "users"},
            {"expression": "revenue"}
        ]
    }
    Response
    "report_view": {
        "items_per_page": 100,
        "total_items": 54,
        "columns_headers": [
            "date_yyyymmdd",
            "device_form_factor",
            "users",
            "revenue"
        ],
        "rows": [
            [
                "20211020",
                "OTHER",
                141,
                222.74
            ],
            [
                "20211020",
                "PERSONAL_COMPUTER",
                821923,
                87656567.1
            ],
            [
                "20211020",
                "SMART_TV",
                11,
                null
            ]
            [
                "20211020",
                "SMARTPHONE",
                1901978,
                98435875.79
            ],
            ...
        ]
    }
                    
    {
        // Response
    }
    # As explained above, user activities query is always for a particular datamart (1649) & userpoint (dff34408-6cc1-4531-86c5-bac8da9ebac9)
    # Retrieve all activities 
    curl -k -H "Authorization: <MICS_API_KEY>" -H "content-Type: application/json" "https://api.mediarithmics.com/v1/datamarts/1649/user_timelines/dff34408-6cc1-4531-86c5-bac8da9ebac9/user_activities"
    
    # Retrieve all activities for a given channel (4307)
    curl -k -H "Authorization: <MICS_API_KEY>" -H "content-Type: application/json" "https://api.mediarithmics.com/v1/datamarts/1649/user_timelines/dff34408-6cc1-4531-86c5-bac8da9ebac9/user_activities?filters=$channel_id==4307"
    
    # Retrieve all activities for a given activity type (SITE_VISIT)
    curl -k -H "Authorization: <MICS_API_KEY>" -H "content-Type: application/json" "https://api.mediarithmics.com/v1/datamarts/1649/user_timelines/dff34408-6cc1-4531-86c5-bac8da9ebac9/user_activities?filters=$type==SITE_VISIT"
    
    # Retrieve all activities for several activity types (SITE_VISIT & APP_VISIT)
    curl -k -H "Authorization: <MICS_API_KEY>" -H "content-Type: application/json" "https://api.mediarithmics.com/v1/datamarts/1649/user_timelines/dff34408-6cc1-4531-86c5-bac8da9ebac9/user_activities?filters=$type==SITE_VISIT|APP_VISIT"
    
    # Retrieve a given activity (17928440-e72f-11ec-aad0-d12e54ffd215)
    curl -k -H "Authorization: <MICS_API_KEY>" -H "content-Type: application/json" "https://api.mediarithmics.com/v1/datamarts/1649/user_timelines/dff34408-6cc1-4531-86c5-bac8da9ebac9/user_activities?filters=$unique_key==17928440-e72f-11ec-aad0-d12e54ffd215"
    
    # Retrieve all activities ingested after a particular date (14/06/2022 10:38:47)
    curl -k -H "Authorization: <MICS_API_KEY>" -H "content-Type: application/json" "https://api.mediarithmics.com/v1/datamarts/1649/user_timelines/dff34408-6cc1-4531-86c5-bac8da9ebac9/user_activities?filters=start_ts==1655195927000"
    
    # Retrieve all activities ingested before a particular date (13/07/2022 13:15:00)
    curl -k -H "Authorization: <MICS_API_KEY>" -H "content-Type: application/json" "https://api.mediarithmics.com/v1/datamarts/1649/user_timelines/dff34408-6cc1-4531-86c5-bac8da9ebac9/user_activities?filters=end_ts==1657717207000"
    
    # Retrieve all activities ingested between 2 dates (between 14/06/2022 10:38:47 & 13/07/2022 13:15:00)
    curl -k -H "Authorization: <MICS_API_KEY>" -H "content-Type: application/json" "https://api.mediarithmics.com/v1/datamarts/1649/user_timelines/dff34408-6cc1-4531-86c5-bac8da9ebac9/user_activities?filters=start_ts==1655195927000,end_ts==1657717207000"
    
    # Retrieve all activities ingested between 2 dates for a given channel (between 14/06/2022 10:38:47 & 13/07/2022 13:15:00 for channel 4307)
    curl -k -H "Authorization: <MICS_API_KEY>" -H "content-Type: application/json" "https://api.mediarithmics.com/v1/datamarts/1649/user_timelines/dff34408-6cc1-4531-86c5-bac8da9ebac9/user_activities?filters=start_ts==1655195927000,end_ts==1657717207000,$channel_id==4307"
    
    # Delete a given activity (17928440-e72f-11ec-aad0-d12e54ffd215)
    curl -X DELETE -k -H "Authorization: <MICS_API_KEY>" -H "content-Type: application/json" "https://api.mediarithmics.com/v1/datamarts/1649/user_timelines/dff34408-6cc1-4531-86c5-bac8da9ebac9/user_activities?filters=$unique_key==17928440-e72f-11ec-aad0-d12e54ffd215"
    

    user_account_id

    String (Optional)

    The User Account ID, acting as an in correlation with compartment_id

    email_hash

    String (Optional)

    The Email Hash, acting as an

    user_agent_id

    String (Optional)

    The User Agent ID, acting as an

    force_replace

    Boolean (Optional)

    Mandatory when the operation is UPSERT. If true, then the User Choice will be completely replaced by the object passed in the user_choice field.

    If false, the object passed in the user_choice field will be merged with the existing User Choice of the UserPoint.

    user_choice

    JSON Object (Optional)

    Mandatory when operation is UPSERT.

    This is a JSON Object representing the User Choice.

    Please refer to the for more

    information.

    Note that the $processing_id field is always mandatory, and $choice_ts is mandatory when operation is UPSERT

    field

    type

    description

    operation

    Enum

    Either UPSERT or DELETE

    compartment_id

    String (Optional)

    # Create the document import
    curl -X POST \
      https://api.mediarithmics.com/v1/datamarts/<DATAMART_ID>/document_imports \
      -H 'Authorization: <YOUR_API_TOKEN>' \
      -H 'Content-Type: application/json' \
      -d '{
    	"document_type": "USER_CHOICE",
    	"mime_type": "APPLICATION_X_NDJSON",
    	"encoding": "utf-8",
    	"name": "<YOUR_DOCUMENT_IMPORT_NAME>"
    }'
    # Create the execution
    curl -X POST \
      https://api.mediarithmics.com/v1/datamarts/1162/document_imports/<DOCUMENT_IMPORT_ID>/executions \
      -H 'Authorization: <API_TOKEN>' \
      -H 'Content-Type: application/x-ndjson' \
      -d '{ 
            "operation": "UPSERT",
            "compartment_id": "<COMPARTMENT_ID>", 
            "user_account_id": "<USER_ACCOUNT_ID>",
            "force_replace": true,
            "user_choice": {
                  "$processing_id": "<PROCESSING_ID>",
                  "$choice_ts": "<CHOICE_TS>"
            }
          }'

    Example

    You can, of course, upload multiple user choices at once. Note the uploaded data is in ndjson format and not json. That means the different choices are not separated by commas, but by a line separator \n

    When importing choices with identifiers, only one identifier is allowed per line. For example, you shouldn't specify the user agent ID if the Email Hash is already used in a line.

    The Compartment ID, acting as a user in correlation with user_account_id

    Create an execution with your user segment commands formatted in ndjson or csv depending on the mime type you chose.

    Each line in the uploaded file can have the following properties:

    operation

    Enum (Mandatory)

    Either UPDATE or DELETE

    compartment_id

    String (Optional)

    The Compartment ID acting as a in correlation with the user account ID

    user_account_id

    How-to

    UserPoint
    segments
    bulk import
    document import
    # Create the document import
    curl -X POST \
      https://api.mediarithmics.com/v1/datamarts/<DATAMART_ID>/document_imports \
      -H 'Authorization: <YOUR_API_TOKEN>' \
      -H 'Content-Type: application/json' \
      -d '{
    	"document_type": "USER_SEGMENT",
    	"mime_type": "APPLICATION_X_NDJSON",
    	"encoding": "utf-8",
    	"name": "<YOUR_DOCUMENT_IMPORT_NAME>"
    }'
    # Create the execution
    curl -X POST \
      https://api.mediarithmics.com/v1/datamarts/<DATAMART_ID>/document_imports/<DOCUMENT_IMPORT_ID>/executions \
      -H 'Authorization: <API_TOKEN>' \
      -H 'Content-Type: application/x-ndjson' \
      -d '{ 
            "operation": "UPDATE",
            "expiration_duration": <INTEGER>,
            "compartment_id": "<COMPARTMENT_ID>", 
            "user_account_id": "<USER_ACCOUNT_ID>",
            "segment_id": "<SEGMENT_ID>"
          }'

    User segment command

    Example

    You can have UPDATE and DELETE operations in the same file upload.

    Please note, if not using csv, that the uploaded data is in ndjson and not json. That means the different profiles are not separated by commas, but by a line separator \n

    Use segment_ids or segment_technical_names if you need to handle multiple segments for a single user.

    User identifiers deletion

    This document import allows you to mark user identifiers for deletion. Each line in the document represents a different object to remove from the platform.

    This is only supported for datamarts using a UserPoint system version of v201901 or later.

    It only deletes the user identifier but not the associated UserPoint.

    How-to

    1. Use the bulk import endpoints to create a document import with theUSER_IDENTIFIERS_DELETIONdocument type and APPLICATION_X_NDJSON mime type. Only ndjson data is supported for user activities.

    2. Create anwith your commands formatted in ndjson. Each command can either be a user account deletion, a user email deletion or a user agent deletion.

    Example:

    User identifiers association

    This document import allows you to merge UserPoint by associating their user identifiers. Each line in the document represents a different user identifiers association

    This is only supported for datamarts using a UserPoint system version of v201812 or later.

    How-to

    1. Use the bulk import endpoints to create a document import with theUSER_IDENTIFIERS_ASSOCIATION_DECLARATIONSdocument type and APPLICATION_X_NDJSON mime type. Only ndjson data is supported for user activities.

    2. Create anwith your commands formatted in ndjson .

    Each line will create/merge a UserPoint that has all the specified identifiers

    User identifier resource can be of three shapes. Either email or user agent or user account id. They correspond with the different types of .

    Quickstart

    This page shows you how to start with API-based and advanced mode dashboard creation in mediarithmics.

    You can manage charts using and . Manipulating dashboards by API and in advanced mode can be useful in some advanced integrations, but will take longer.

    Advanced mode

    Full dashboard edition

    1. Run your query in the query tool and save it as a technical query. Note the ID of the query.

    2. In the computing console, go to dashboards and add/edit a dashboard

    3. Choose a name and save your dashboard.

    4. Switch to the Advanced tab.

    5. Edit the JSON

    See the object for a quick reference.

    1. Run your query and save it as a technical query. Note the ID of the query.

    2. In the computing console, go to dashboards and add/edit a dashboard

    3. Add or edit a chart and go to the Advanced tab

    See the object for a quick reference.

    This quickstart guide uses the authentication method. Choose and configure your own authentication method. For more information, see .

    Your dashboard could use or to retrieve data. We will use both in this tutorial, and OTQL queries need to be registered using the endpoint.

    POST https://api.mediarithmics.com/v1/datamarts/:datamartId/queries

    Register an OTQL query in the platform

    We will create two OTQL queries for this tutorial. The first one counts the UserPoint in the datamart, the second one lists the devices they use.

    You first create a object to reference your dashboard and define where it is visible.

    POST https://api.mediarithmics.com/v1/dashboards

    Here is a sample body payload for a home dashboard with all the important properties

    You can now upload content in your dashboard using the object.

    PUT https://api.mediarithmics.com/v1/dashboards/:id/content?organisation_id=:organisation_id

    Here is a sample body payload for a content using the queries we previously created.

    Go to your datamart's home page, and your dashboard is now displayed with the two charts we created !

    Charts

    DashboardContent has sections and cards, which organize charts. Each chart has a title, colors (optional), a type, a dataset and options (optional).

    A Bars chart
    A Pie chart with legend

    Here is the JSON representation of a chart.

     {
        "title": "Device form factors", // Could be an empty string
        "type": "Bars", // Bars || Pie || Metric || Radar
        "dataset": { // See Datasets and datasources page
            "type": "OTQL",
            "query_id": "50171"
        },
        "options": {} // Options depending on the type of chart
    }

    Bars charts

    Here are the different states of a Bars chart depending on its options and the dataset

    Columns and bars charts

    The available options for the bars chart are

    See for the data_labels.filter format.

    Here are the different states of an Area chart depending on its options and the dataset

    The available options for the area chart are

    See for the data_labels.filter format.

    Here are the different states of the Pie charts depending on its options and the dataset

    The available options for the pie charts are

    See for the data_labels.filter format.

    Here are the different states of the Radar charts depending on its options and the dataset.

    The available options for the Radar charts are

    See for the data_labels.filter format.

    Metric charts are either displayed as percentages or as count, depending on its options.

    Here are the available options for the e charts

    General setup

    To configure Contextual targeting feature (contextual extraction & semantic analysis), please follow the next steps IN ORDER:

    1. Schema update

    2. Event rule configuration

    Schema update

    Contextual targeting only works as of now with standard schema. Please reach out to your Account manager if you do not have UserEvent type in your schema.

    For Panel-based as well as Semantic contextual targeting, you'll need to update your runtime schema to add the following line in UserEvent type:

    contextual_key:String @TreeIndex(index:"USER_INDEX")

    $url attribute needs to be populated with a proper URL in order to extract the contextual_key (URL without protocol nor query stings).

    As well, ensure that the field ts in UserEvent is indexed:

    ts:Timestamp! @TreeIndex(index:"USER_INDEX")

    For Semantic contextual targeting, and particularly if you want to create Audience segments based on semantic information, you'll need to add the following lines in UserEvent type:

    semantic_tagging:[SemanticTagging] @Property(path:"$properties.$semantic_tagging")
    targeting_list_ids:[String] @TreeIndex(index:"USER_INDEX") @ReferenceTable(type:"CORE_OBJECT", model_type:"CONTEXTUAL_TARGETING_LISTS") @Property(path:"$properties.$targeting_list_ids")

    As well as the following types:

    type SemanticTagging  {
       provider_id:String @Property(path:"$provider_id") @TreeIndex(index:"USER_INDEX")
       provider_version:String @Property(path:"$provider_version") @TreeIndex(index:"USER_INDEX")
    
       entities:[SemanticEntity] @Property(path:"$entities")
       iab_categories:[SemanticIABCategory] @Property(path:"$iab_categories")
    }
    
    type SemanticEntity  {
       entity_id:String @Property(path:"$entity_id") @TreeIndex(index:"USER_INDEX")
       name:String @Property(path:"$name") @TreeIndex(index:"USER_INDEX")
       type:String @Property(path:"$type")
       wikidata_id:String @Property(path:"$wikidata_id")
    }
    
    type SemanticIABCategory  {
       category_id:String @TreeIndex(index:"USER_INDEX") @Property(path:"$category_id")
       name:String @TreeIndex(index:"USER_INDEX") @Property(path:"$name")
    }

    Don't forget to add @EdgeAvailability on semantic_tagging & targeting_list_ids properties if you want to use those characteristics for building Edge segments. .

    Event rule configuration

    You need to add Contextual Targeting Extractor event rule to channels on which you want to use the contextual targeting feature. This event rule will have various objectives:

    • Specify which JavaScript tag will be responsible for URL & hit collection:

      • User event tag: uses the URL explicitly passed in the event. In that case, you will need to install the .

      • Contextual targeting tag: automatically captures the page URL from the browser. In that case, you will need to install the .

    Add a URL to blacklist per line. ALL URLs provided should NOT have protocol in it (http://, https://). For example:

    Add a regexp to blacklist per line. Note that only * is authorized and * will automatically be applied before and after the input regexp. For example:

    Will blacklist the following URLs:

    • www.mediarithmics.io/homepage

    • mediarithmicsTEST.io/homepage

    • mediarithmics*io/homepage/page.

    Email views and clicks

    You can track read and click actions in emails sent to your customers.

    • To track the opening of the emails, you have to include a pixel

    • To track the clicks on the links included in your emails, you have to replace each of your links with a Click Tracking URL

    GraphQL queries

    The GraphQL API gives you the ability to query all kinds of UserPoint data as collected by the platform (profile, activities, segments, identifiers, etc.) with a single request.

    Each GraphQL query is meant to fetch a single UserPoint data. To query multiple UserPoint in a single query, depending on your use case, please refer to the and/or to the .

    The schema used in the GraphQL endpoint is based on the . To add/remove fields from the GraphQL API, the schema has to be updated accordingly.

    POST /v1/datamarts/:datamartId/query_executions/graphql

    Integration batch

    The integration batch is a plugin type used for customers' integrations. It can be periodic or non-periodic plugin. You can choose to pause a recurring plugin so that all the coming executions are canceled.

    Imagine you want to create a script that imports data every night for a customer :

    • You declare a new integration batch plugin called import-data-for-customer

    .
    identifier
    identifier
    identifier
    identifier
    User choices page

    String (Optional)

    The User Account ID acting as a user identifier in correlation with the user account ID.

    email_hash

    String (Optional)

    The Email Hash acting as a user identifier.

    user_agent_id

    String (Optional)

    The User Agent ID acting as a user identifier.

    segment_id

    String (Optional)

    The Id of the segment in which the User is inserted/deleted.

    segment_ids

    List of strings (Optional)

    The list of ids of segments in which the User is inserted/deleted. For instance ["segment_id_1","segment_id_2"]

    segment_technical_name

    String (Optional)

    The technical name of the segment in which the User is inserted/deleted.

    segment_technical_names

    List of strings (Optional)

    The list of technical names of segments in which the User is inserted/deleted. For instance ["technical_name_1","technical_name_2"]

    expiration_duration

    Integer (Mandatory)

    The number of minutes before the user will be removed from the segment. 0 means that the User will never leave the segment

    expiration_ts

    Number (Optional)

    The timestamp of the expiration date of the User in the segment. A value of 0 means that the user will never leave the segment

    data_bag

    Escaped JSON String (Optional)

    The data bag associated with the user/segment relationship

    user identifier

    A hash of the email. The hashing function should be unique per datamart.

    email

    String (optional)

    the email address

    The user agent ID

    The User Account ID

    compartment_id

    String (optional)

    The Compartment ID. If you don't input the compartment id it will fall back on the default one

    field

    type

    description

    identifiers

    UserIdentifierResource[]

    An array of User Identifier Resource of any type

    field

    type

    description

    type

    "USER_EMAIL"

    The type of the identifier.

    hash

    field

    type

    description

    type

    "USER_AGENT"

    The type of the identifier.

    user_agent_id

    field

    type

    description

    type

    "USER_ACCOUNT"

    The type of the identifier.

    user_account_id

    User identifiers association command

    Email

    User Agent

    User Account

    Example

    You can, of course, add different identifier types at the same time. Please note that the uploaded data is in ndjson and not json. That means the different additions are not separated by commas, but by a line separator \n

    execution
    user identifiers

    String

    String

    String

    Calculate and add the contextual key in the event. This is done automatically when adding the event rule.

  • Add the semantic information extracted from a URL in the event . This is required if you want to create Audience segments based on semantic information. Check Tag event with semantic extract in that case

  • Specify URLs (Blacklist URLs) or group of URLs (Blacklist RegEx) to blacklist. No semantic extraction nor targeting will be perfomed on those URLs. If we take the example of a news website, we recommend blacklisting pages that list articles, usually related to the same theme (e.g. "politics") and that are frequently refreshed.

  • Blacklist URL

    Blacklist Regexp

    tracking snippet
    contextual snippet
    More information about Edge segments
    Name
    Type
    Description

    datamartId

    string

    The datamartId in which the UserPoint data will be looked up

    Name
    Type
    Description

    query

    string

    This parameter should include your GraphQL query, starting with "query MyQuery {...". Do not forget to escape double quotes if needed.

    {
        "data": { ...GraphQL response... }
    }
    {
        "error": "..."
    }

    To test and write GraphQL queries, we recommend you using our GraphQL editor:

    1. Head to the Computing Console

    2. Click on GraphQL menu under DATA STUDIO section

    Through the GraphQL endpoint, only queries (reads) are supported. Mutations (writes) are not supported.

    This endpoint is being rate-limited and will respond with 429 HTTP status code if the QPS exceed its limits. Please discuss with your account manager to have more information about this rate limiting and to request any limit increase.

    You can select a UserPoint by any identifier using different functions.

    For more information, see User identifiers

    To only select elements matching a specific clause, use @filter. This clause is a WHERE object tree expressions, so you can use any thing like it was this kind of expression.

    If you're not familiar with GraphQL and how to interact with such APIs, please refer to the official documentation: https://graphql.org/

    GraphQL schema

    GraphQL endpoint

    Path Parameters

    OTQL queries
    Query exports
    customer defined schema

    Request Body

    GraphQL editor

    Limits

    The user activities number retuned is also limited. A query return to maximum 100 activities. Be careful, there is not warning and you can't change this limit yet.

    Moreover, an user event is always in an activity so, this limitation is indirectly apply on the events. The query will return only the event in the hundred first activities.

    Query examples

    Selecting a UserPoint

    Filters

    Be carful the @filter is applied after the limitation of the activities. So if your query does not return activities it only mean there isn't activities which respect your condition in the hundred first of the UserPoint select.

    You declare a first 1.0.0 version for this plugin with the code of the script and the declaration of the script parameters
  • Your script is now available for usage

  • To execute the script, you can :

    • Create an integration batch instance that will use the code from the 1.0.0 version with specific input parameters

    • Either program the instance to automatically create executions at a specified cron, or manually create a new execution to start now or later.

    Use the plugin creation endpoints to create a new plugin with the plugin type as INTEGRATION_BATCH. Everything else remains the same.

    Use the plugin version creation endpoints to create a new plugin version with all the properties. The call and format are the same than usual.

    For the integration batch plugin, the instance is called integration_batch_instances.

    There are five properties that are used for this plugin type: cron , cron_status, ram_size, cpu_size and disk_size.

    The cron and the cron_status are not mandatory as you can create non-periodic jobs. If used, you should use them together.

    The ram_size , cpu_size and disk_size are mandatory and the default values are set to LOW.

    You can perform the operations POST / PUT / GET and DELETE on the instances.

    Executions can be created either automatically by the scheduler using the cron defined in the instance or manually using the API or the interface.

    When creating an execution you have to set the execution_type and expected_start_date properties.

    You can perform the operations POST / PUT / GET and DELETE on the executions.

    The execution_type can be either MANUAL when created using the interface or CRON when created by the instance using the cron value set in the instance.

    The expected_start_date is set by the timestamp chosen in the interface or by the cron set in the instance.

    You can check plugins key concepts to understand the hierarchy between a plugin, the versions, the instances and the executions.

    How-to

    Plugin creation

    Example

    Plugin version creation

    Example

    Plugin instance creation

    Example

    Integration batch execution creation

    # Create the document import
    curl -X POST \
      https://api.mediarithmics.com/v1/datamarts/<DATAMART_ID>/document_imports \
      -H 'Authorization: <YOUR_API_TOKEN>' \
      -H 'Content-Type: application/json' \
      -d '{
    	"document_type": "USER_IDENTIFIERS_ASSOCIATION_DECLARATIONS",
    	"mime_type": "APPLICATION_X_NDJSON",
    	"encoding": "utf-8",
    	"name": "<YOUR_DOCUMENT_IMPORT_NAME>"
    }'
    # Create the execution
    curl -X POST \
      https://api.mediarithmics.com/v1/datamarts/1162/document_imports/<DOCUMENT_IMPORT_ID>/executions \
      -H 'Authorization: <API_TOKEN>' \
      -H 'Content-Type: application/x-ndjson' \
      -d '
        { 
          "identifiers":[
            { "type": "USER_EMAIL", "hash":"<EMAIL_HASH>" }, 
            { "type": "USER_AGENT", "user_agent_id": "<USER_AGENT_ID>" }, 
            { "type": "USER_ACCOUNT", "user_account_id": "<USER_ACCOUNT_ID>",  "compartment_id": "<COMPARTMENT_ID>" }
          ]
        }
      '
    www.mediarithmics.io/homepage
    actu.mediarithmics.io/
    mediarithmics.io/actu
    mediarithmics*.io/homepage
    # Return the UserPoint creation_ts field
    query MyQuery {
      user_point(user_point_id: "xxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx") {
        creation_ts
      }
    }
    # Return profiles, accounts, segments and scenarios data of a UserPoint
    # Warning: This query relies on a customer defined schema so it may not
    # work as-is on your datamart.
    query MyQuery {
      user_point(user_point_id: "xxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx") {
        id
        creation_ts
        profiles {
          gender
          birth_date
        }
        accounts {
          compartment_id
          user_account_id
        }
        segments {
          id
        }
        scenarios {
          scenario_id
        }
      }
    }
    # Select by UserPoint ID
    query MyQuery {
      user_point(user_point_id: "xxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx") {
        id
        creation_ts
      }
    }
    
    # Select by email hash
    query MyQuery {
      user_point_by_email_hash(email_hash: "xxxxxxxxxxxxxxxxxxx") {
        id
        creation_ts
      }
    }
    
    # Select by user account
    # Both compartment ID and user account ID are mandatory
    query MyQuery {
      user_point_by_user_account_id(
        compartment_id: "XXXX",
        user_account_id: "xxxx-xxx-xx-xxxxx"
        ) {
        id
        creation_ts
      }
    }
    
    # Select by user agent ID
    query MyQuery {
      user_point_by_user_agent_id(user_agent_id: "xxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx"){
        id
        creation_ts
      }
    }
    query micsQuery {
      user_point(user_point_id:"xxx") {
        activities {
          #only return events with the name "$home_view"
          events @filter(clause: "name == \"$home_view\""){ 
            ts
          }
        }
      }
    }
    # Create the plugin definition
    curl -X POST \
      https://api.mediarithmics.com/v1/plugins \
      -H 'Authorization: <YOUR_API_TOKEN>' \
      -H 'Content-Type: application/json' \
      -d '{
    	"organisation_id": "my_organisation_id",
            "plugin_type": "INTEGRATION_BATCH",
            "group_id": "com.my-client.integration_batch",
            "artifact_id": "integration-batch-my-client"
    }'
    # Create the plugin version
    curl -X POST \
      https://api.mediarithmics.com/v1/plugins/<PLUGIN_ID>/versions \
      -H 'Authorization: <YOUR_API_TOKEN>' \
      -H 'Content-Type: application/json' \
      -d '{
    	  "version_id":"1.0.0",
              "plugin_properties":[
            	  	{
            	     "technical_name": "one_more_property",
            	     "value": {
            	       "value": ""
            	     },
            	     "property_type": "STRING",
            	     "origin": "PLUGIN",
            	     "writable": true,
            	     "deletable": true
            	   },
                    {
                        "technical_name": "provider",
                        "value": {
                            "value": "mediarithmics"
                        },
                        "property_type": "STRING",
                        "origin": "PLUGIN_STATIC",
                        "writable": false,
                        "deletable": false
                    },
                    {
                        "technical_name": "name",
                        "value": {
                            "value": "My Plugin Name"
                        },
                        "property_type": "STRING",
                        "origin": "PLUGIN_STATIC",
                        "writable": false,
                        "deletable": false
                    }
            ]
    }'
    # Create the plugin instance
    curl -X POST \
      https://api.mediarithmics.com/v1/integration_batch_instances \
      -H 'Authorization: <YOUR_API_TOKEN>' \
      -H 'Content-Type: application/json' \
      -d '{
    	"group_id": "com.my-client.integration_batch",
            "artifact_id": "integration-batch-my-client",
            "version_id": "my-version-id",
            "organisation_id": "my-plugin-id",
            "name": "The name of my instance",
            "archived": false, 
            "cron" :"* * * 7 *",
            "cron_status": "ACTIVE | PAUSED",
            "ram_size": "LOW | MEDIUM | LARGE | EXTRA_LARGE",
            "disk_size": "LOW | MEDIUM | LARGE | EXTRA_LARGE",
            "cpu_size": "LOW | MEDIUM | LARGE | EXTRA_LARGE"
    }'
    // Create an execution
    curl -X POST \
      https://api.mediarithmics.com/v1/integration_batch_instances/<INSTANCE_ID>/executions \
      -H 'Authorization: <YOUR_API_TOKEN>' \
      -H 'Content-Type: application/json' \
      -d '{
               "parameters": {
    		execution_type: "MANUAL | CRON", 
    		expected_start_date: 1562595783663
                },
               "organisation_id": "1185",
               "user_id": "1007",
               "error": null,
               "status": "PENDING",
               "external_model_id: "42",
               "external_model_name": "PUBLIC_INTEGRATION_BATCH",
               "start_date": 1562595789171,
               "job_type": "BATCH_INTEGRATION",
      }
    

    The User Account Id.

    compartment_id

    Number (Optional)

    The Compartment Id associated with the User Account Id.

    Hash of the Email address.

    A other than a device point id. Ex: "vec:123456" or "net:9:12345".

    # Create the document import
    curl -X POST \
      https://api.mediarithmics.com/v1/datamarts/<DATAMART_ID>/document_imports \
      -H 'Authorization: <YOUR_API_TOKEN>' \
      -H 'Content-Type: application/json' \
      -d '{
    	"document_type": "USER_IDENTIFIERS_DELETION",
    	"mime_type": "APPLICATION_X_NDJSON",
    	"encoding": "utf-8",
    	"name": "<YOUR_DOCUMENT_IMPORT_NAME>"
    }'
    # Create the execution
    curl -X POST \
      https://api.mediarithmics.com/v1/datamarts/1162/document_imports/<DOCUMENT_IMPORT_ID>/executions \
      -H 'Authorization: <API_TOKEN>' \
      -H 'Content-Type: application/x-ndjson' \
      -d '
        {
          "type": "USER_ACCOUNT",
          "compartment_id": "1000",
          "user_account_id": "8541254132"
        }
        {
          "type": "USER_EMAIL",
          "hash": "982f50d88d437d13bdbd541edfv4fe5176cc8d862f8cbe7ca4f0dc8ea"
        }
        { "type": "USER_AGENT", "user_agent_id": "vec:89998434" }
      '

    field

    type

    description

    type

    String

    USER_ACCOUNT

    user_account_id

    {
      "type": "USER_ACCOUNT",
      "compartment_id": "1000",
      "user_account_id": "8541254132"
    }

    field

    type

    description

    type

    String

    USER_EMAIL

    hash

    {
      "type": "USER_EMAIL",
      "hash": "982f50d88d437d13bdbd541edfv4fe5176cc8d862f8cbe7ca4f0dc8ea"
    }

    field

    type

    description

    type

    String

    USER_AGENT

    user_agent_id

    { "type": "USER_AGENT", "user_agent_id": "vec:89998434" }

    Example

    You can, of course, remove different identifier types at the same time. Please note that the uploaded data is in ndjson and not json. That means the different deletions are not separated by commas, but by a line separator \n

    User Account deletion command

    Example:

    User Email deletion command

    Example:

    User Agent deletion command

    User device point ids ("udp:123456") are not supported by this document import job and will cause the job to be rejected.

    Use the Device points deletionjob type if you want to delete device points along with all their associated technical ids.

    execution

    String

    String

    String

    Edit the JSON and preview your changes.

    BODY payload for query 1
    {
        "datamart_id": {{datamartId}},
        "query_language": "OTQL",
        "query_text": "select @count{} FROM UserPoint"
    }
    BODY payload for query 2
    {
        "datamart_id": {{datamartId}},
        "query_language": "OTQL",
        "query_text": "SELECT {agents {user_agent_info{form_factor @map}}} FROM UserPoint"
    }
    {
        "title": "My awesome dashboards",
        "scopes": [
            "home"
        ],
        "segment_ids": [],
        "builder_ids": [],
        "archived": false,
        "organisation_id": "{{orgId}}",
        "community_id": "{{communityId}}"
    }
    {
        "sections": [
            {
                "title": "",
                "cards": [
                    {
                        "x": 0,
                        "y": 0,
                        "h": 3,
                        "layout": "vertical",
                        "w": 8,
                        "charts": [
                            {
                                "title": "User points",
                                "type": "Metric",
                                "dataset": {
                                    "type": "OTQL",
                                    "query_id": "{{ID of query 1}}"
                                }
                            },
                            {
                                "title": "Device form factors",
                                "type": "Bars",
                                "dataset": {
                                    "type": "OTQL",
                                    "query_id": "{{ID of query 2}}"
                                },
                                "options": {}
                            }
                        ]
                    }
                ]
            }
        ]
    }

    Chart edition

    By API

    Step 1: Configure authentication

    Step 2 : Prepare the OTQL queries you will use on your dashboard

    Creating a query

    For each query, note their ID.

    You should adapt those queries to your data model if required.

    Step 3 : Create a dashboard registration

    Create a dashboard registration

    Step 4 : Put content in your dashboard

    Edit the content of a dashboard

    DashboardContent
    in the query tool
    Chart
    Long term access tokens
    Authentication
    OTQL queries
    activities analytics queries
    Creating a query
    DashboardRegistration
    DashboardContent
    the query tool
    edit dashboards in the UI
    Dashboard advanced mode
    Chart advanced mode
    For each event, the datamart will identify the users reading/clicking the email by:
    • Recommended option: using the user's Email Hash, included by you in the pixel/tracking URL

    • Reading their cookies if possible:

      • It is always working when the users are clicking (e.g. Click Tracking URL)

      • It is sometimes possible when the users are opening the emails, depending on their email client (e.g. Pixel)

    Calls to those URLs generate events.

    or if your are using the $uids field (see Passing user identifiers in pixel-based tracking)

    or if you are using a custom domain:

    It is possible to set custom properties

    Field
    Type
    Description

    $ev

    String

    The event name. $email_view for email opening tracking

    $dat_token

    String

    Calls to those URLs generate click events

    It is also possible to set custom properties.

    The $redirect parameter is used to define the destination of the url redirection. The URL put in the $redirect parameter should be URL Encoded (RFC 3986).

    Field
    Type
    Description

    $ev

    String

    The event name. $email_click for email opening tracking

    $dat_token

    String

    https://events.mediarithmics.com/v1/touches/pixel?  
      $ev=$email_view&  
      $dat_token=<DATAMART_TOKEN>&  
      $email_hash=78b04074e616166938cf672f70f41b4d&  
      Any Custom Properties ...
    https://events.mediarithmics.com/v1/touches/pixel?  
      $ev=$email_view&  
      $dat_token=<DATAMART_TOKEN>&  
      $uids=jso-[{"$tpe":"EM","$eh":"78b04074e616166938cf672f70f41b4d"}]&
      Any Custom Properties ...
    https://analytics.custom-domain.com/v1/touches/pixel? 
        $ev=$email_view& 
        $dat_token=<DATAMART_TOKEN>& 
        $email_hash=78b04074e616166938cf672f70f41b4d& 
        Any Custom Properties ...
    https://events.mediarithmics.com/v1/touches/click?
        $ev=$email_click&
        $dat_token=<DATAMART_TOKEN>&
        $email_hash=78b04074e616166938cf672f70f41b4d&
        Any Custom Properties &
        $redirect=<CLICK_URL>

    Activities tracked through this method will be of EMAIL $type and NO_SESSION $session_status. See for more information.

    Pixel Touch for Email Opening

    Click Tracking for Emails

    "options": {
        "legend": {
             enabled: boolean; # Show or hide the legend. Defaults to FALSE.
             position: ‘bottom’ | ‘right’; # Display legend on the bottom or on the right of the chart. Defaults to bottom
         },
         "colors": string[]; # Defaults to current theme colors
         "format": ‘count’ | ‘percentage’ | ‘index’; # Defaults to count. Pass percentage or index if dataset is compatible (comes from a percentage or index transformation) to automatically change labels, and tooltips and have more info.
         "drilldown": boolean; # Enables drill down if dataset is compatible. Defaults to FALSE
         "stacking": boolean; # Enables stacking if dataset is compatible. Prioritized over drilldown. Defaults to FALSE
         "type": ‘bar’ || ‘column’; # Set to ‘bar’ to display horizontal bars instead of columns. Defaults to ‘column’
         "plot_line_value": int; # Set to draw a line at the specified value
         "hide_x_axis": boolean; # TRUE to hide X axis. Defaults to FALSE
         "hide_y_axis": boolean; # TRUE to hide Y axis. Defaults to FALSE
         "tooltip": {format: string} # Highcharts tooltip pointFormat. Defaults to “{point.y}” if dataset don’t have a -count field, “{point.y}% ({point.count})” otherwise.
         "big_bars": boolean; # TRUE displays large bars close to each other, FALSE smaller bars with more space between them. Defaults to TRUE
    }
    "options": {
        "legend": {
             enabled: boolean; # Show or hide the legend. Defaults to FALSE.
             position: ‘bottom’ | ‘right’; # Display legend on the bottom or on the right of the chart. Defaults to bottom
         },
         "colors": string[]; # Defaults to current theme colors
         "format": ‘count’ | ‘percentage’; # Defaults to count. Pass percentage if dataset is compatible (comes from a percentage transformation) to automatically change labels, and tooltips and have more info.
         "type": ‘area’ || ‘line’; # Set to ‘line’ to only display lines and no area. Defaults to ‘area’
         "plot_line_value": int; # Set to draw a line at the specified value
         "hide_x_axis": boolean; # TRUE to hide X axis. Defaults to FALSE
         "hide_y_axis": boolean; # TRUE to hide Y axis. Defaults to FALSE
         "double_y_axis": boolean; # TRUE for each serie to have its own scale (and shows 2 vertical axis). Defaults to FALSE
         "tooltip": {format: string} # Highcharts tooltip pointFormat. Defaults to “{point.y}” if dataset don’t have a -count field, “{point.y}% ({point.count})” otherwise.
    }
    "options": {
        "legend": {
            "enabled": boolean; # Show or hide the legend. Defaults to FALSE.
            "position": ‘bottom’ | ‘right’; # Display legend on the bottom or on the right of the chart. Defaults to bottom
        },
        "colors": string[]; # Defaults to current theme colors
        "drilldown": boolean; # Enables drill down if dataset is compatible. Defaults to FALSE
        "inner_radius": boolean; # True displays the chart as a Donut, false as a Pie. Defaults to TRUE
        "is_half": boolean; # True to only display half of a donut or half of a pie. Defaults to FALSE.
        "size": number | string | undefined; # The diameter of the pie relative to the plot area. Can be a percentage (75%) or a value.
        "data_labels": {
            "enabled": boolean; # If labels are displayed or not, default to TRUE
            "distance": int; # Distance between labels and the figure. Defaults to 10 if isHalf:true, else 0
            "format": string; # Labels text. See Labels and string format. Defaults to “{point.percentage:.2f}%” if legend.enable:false, “{point.name} {point.percentage:.2f}%” otherwise.
            "filter": Highcharts.filter; # To hide labels under certain values. Defaults to undefined. 
        };
        "tooltip": {"format": string} # Highcharts tooltip pointFormat. Defaults to “{point.percentage:.2f}%” if legend.enable:false, “{point.name} {point.percentage:.2f}%” otherwise.
    }
    "options": {
        "legend": {
            "enabled": boolean; # Show or hide the legend. Defaults to FALSE.
            "position": ‘bottom’ | ‘right’; # Display legend on the bottom or on the right of the chart. Defaults to bottom
        },
        "colors": string[]; # Defaults to current theme colors
        "format": ‘count’ | ‘percentage’; # Defaults to count. Pass percentage if dataset is compatible to automatically change labels, and tooltips.
        "data_labels": {
            "enabled": boolean; # If labels are displayed or not, default to TRUE
            "format": string; # Labels text. See Labels and string format.  Defaults to “{point.y}” if dataset don’t have a -count field, “{point.y}%” otherwise
            "filter": Highcharts.filter; # To hide labels under certain values. Defaults to undefined. 
        };
        "tooltip": {"format": string} # Highcharts tooltip pointFormat. Defaults to “{point.y}” if dataset don’t have a -count field, “{point.y}% ({point.count})” otherwise.
    }
    "options": {
        "format": ‘count’ | ‘percentage’ | 'float'; # Defaults to count. If count, simply displays the number, else displays the number with %
    }

    Area charts

    Pie charts

    Radar charts

    Metric charts

    Hicharts.filter
    Hicharts.filter
    Hicharts.filter
    Hicharts.filter
    Area and line charts
    With percentage format
    With count format

    Alert configurations

    Alert Configurations allow customization of settings for different alert types within the Alerting module.

    Configurations are used to define specific behavior, thresholds, and rules associated with each alert type. They are dedicated resources.

    Each alert type can have a different set of configurations. By configuring alert types, you can tailor the behavior of the alerts to meet specific requirements.

    Alert configurations can be personalized for a specific organization. This means that each organization can have its own set of configuration values for the alert types. If a configuration is not set, a default value set by mediarithmics will be used.

    Allowed configurations

    Alert configurations are identified by combining three values: config_key, organisation_id, and alert_type. The config_key uniquely identifies a specific configuration setting, while the organisation_id and alert_type specify the organization and alert type to which the configuration belongs.

    Here is a list of available configuration keys and their sample values:

    config
    config_value
    Editable in the UI

    You can list/edit configurations for your organizations by API.

    GET https://api.mediarithmics.com/v1/alert_type_configs

    If a configuration from the allowed list is not setup, it won't be returned by this call but fall back to the default platform value in usage.

    Name
    Type
    Description

    POST https://api.mediarithmics.com/v1/alert_type_configs/config_key=:configKey/organisation_id=:organisationId/alert_type=:alertType

    Name
    Type
    Description
    Name
    Type
    Description

    PUT https://api.mediarithmics.com/v1/alert_type_configs/config_key=:configKey/organisation_id=:organisationId/alert_type=:alertType

    Name
    Type
    Description
    Name
    Type
    Description

    DELETE https://api.mediarithmics.com/v1/alert_type_configs/config_key=:configKey/organisation_id=:organisationId/alert_type=:alertType

    Name
    Type
    Description

    Configurations can be archived using the PUT request. An archived configuration is not used anymore by the platform (fallback to default value) but is easier to reactivate later.

    API Quickstart

    This page shows you how to get started using the activities analytics API to query your data in mediarithmics.

    Step 1 : Configure authentication

    This quickstart guide uses the Long term access tokens authentication method. Choose and configure your own authentication method. For more information, see Authentication.

    Step 2 : API call

    POST https://api.mediarithmics.com/v1/datamarts/:datamartId/user_activities_analytics

    Query Parameters

    Name
    Type
    Description
    Name
    Type
    Description

    Here is a sample as body payload with all the important properties

    The API will answer with a containing a .

    Congratulations! You've sent your first request to the Activities analytics API.

    Event rules

    Every time an event is sent, we run the event rules associated with its channel. They are predefined actions to extract properties, reshape data or identify a user from a property.

    If the action you wish to do on each event is not possible with an event rule, you should have a look at .

    How to add event rules

    You can go to a channel's settings, edit, and then scroll down to event rules.

    Available event rules

    Property To Origin Copy

    This Event Rule will help you take an existing property from an event and copy it into the origin of the activity. You can copy:

    • The URL of the Event

    • The Referrer of the Event

    • Any Event Property

    This Event Rule allows you to write a pattern that will be matched against all the $url values of incoming $page_view events. The pattern can extract some values from the Url Path and from the Url Query String.

    If you want more information about the different parts of an URL,

    Url Match only works for $page_view events. Any other event won't be processed by the Url Match event rule.

    Useful if for technical and/or organizational reasons, you can't customize the Tracking JS Snippet on a web page to retrieve information from the data layer.

    1. Use the that will automatically track $page_view events with the URL of the page.

    2. Use the Url Match event rule to extract properties from the page's URL and add them to the event.

    For example, if a $page_view event is tracked with the URL https://foo.bar/category/0001/article/super-awesome-article, you would be able to generate this kind of event

    The URL Match is taking 2 parameters:

    1. The URL Pattern that will be used to match the $url value of $page_view events

    2. The event template that will be used to generate the event if the $url is matching the URL pattern

    Patterns are URL in which you can add:

    • A variable extraction rule for path parameters with:variableName

    • A wildcard with *

    Example *//foo.bar/category/:categoryId/article/:articleId

    • * at the beginning will match both URLs in and in http in the URL

    • :categoryId will extract the value in the URL corresponding to the categoryId. As it is a named variable, it can be used as a value in the event that will be generated.

    • :articleId works as:categoryId

    The Query String values are automatically extracted in variables that have the name of the parameter in the Query String. https://foo.bar/a/b/c?var=value&var2=value2 extracts both value and value2 in variables named var and var2.

    The event template is containing the following information:

    • The $event_name that will be used for the generated event as a static string

    • A list of properties in a key-value way that will be added in the event properties

    In the properties values you can either pass:

    • A static string directly. Ex: sport

    • A string in the format {{variableName}} that will be replaced by a value extracted in the URL pattern

    Let's take the following event rule:

    • Url pattern: *//foo.bar/category/:categoryId/article/:articleId

    • Event template:

    Property
    Value

    $page_view event with Url: https://foo.bar/category/0001/article/super-awesome-article?origin=email will generate

    $page_view event with Url http://foo.bar/category/0001/article/super-awesome-article will generate

    $page_view event with Url https://oof.bar/category/0001/article/super-awesome-article will generate nothing as the Url domain (oof.bar) is not matching the pattern.

    page_view event with Url https://foo.bar/category/0001/article/super-awesome-article will generate nothing as the "source" event name is not $page_view.

    This event rule allows you to extract a property from an event to convert it into a user identifier, such as an Email Hash or a User account ID.

    You can apply a hash on this extraction. We currently support the following hash methods:

    • SHA_256

    • SHA_1

    • SHA_384

    This event rule is useful when you don't want to pass an identifier as a global property of the activity, but rather have it computed directly by your datamart.

    If several values of an identifier are found within an activity, we keep only the last one.

    In the scenario above, you will be able to extract the user_id, store it as a User account ID.

    This event rule is used for Contextual targeting purpose. You can find more information about it in the section

    Cohort-based Lookalike

    Please refer to our to learn more about this feature.

    To configure this feature, please follow the next steps IN ORDER:

    1. Attributes definition

    Attributes definition

    Attributes

    Attributes selection

    A designated cohort is assigned to a user depending on attributes (also named features in DataScience) you have defined to characterize your users. You will need to format those attributes using JSON format (see below).

    We recommend to :

    • Pick attributes that can be used to segment users and that are relevant to the business

    • Pick attributes that are available on all your users (logged / unlogged)

    JSON format

    For instance, let's imagine that you want to create cohorts based on:

    • os_family - defined on UserAgentInfo nested in UserAgent

    • age - defined on UserProfile

    • city - defned on UserEvent

    You will therefore define the following JSON:

    There are 3 types of attributes available:

    • FREQUENCY_ENUM: use this type for a finite list of values like operating systems.

    • FREQUENCY_NUMBER: use this type for classifying number buckets like age. Using the above example:

      • First bucket: >= 0 & < 10

    The field_path must contain the path of the attribute from the UserPoint definition (see for more info)

    A ML function requires a query to fetch data used in its configuration. In the case of cohort-based lookalike, it requires an appropriate query to fetch fields used as attributes and specified in the JSON.

    Following our previous example, the graphQL query will be :

    Please follow the next steps to instantiate the ML function developed by mediarithmics to assign a cohort to your userpoints:

    1. Head to Settings > Datamart > ML Functions

    2. Click on New Ml Function, pick the datamart where to apply the ML function then choose simhash-cohorts-calulation

    3. Enter the following information on the ML function configuration panel:

    Once the ML function has been instantiated, you will need to update batch_mode parameter to true and activate the ML function by running the following API :

    Two changes have to be made in your runtime schema :

    • Add a field clustering_cohort in UserPoint as follow :

    • Create a new ClusertingCohort type as follow :

    You can ask your Account manager to run an initial loading on your datamart to calculate cohorts on existing userpoints.

    Using a data file data source

    You can use raw data stored in a file using the data_file datasource.

    It works this way :

    1. You upload a data file in the platform using the data_file API

    DashboardContent
    user agent id

    The id of the audience datamart in the mediarithmics platform.

    $cuid

    String (Optional)

    The user account id.

    $email

    String (Optional)

    The user email.

    $email_hash

    String (Optional)

    The user email hash.

    $cb

    String (Optional)

    The cache buster parameter. It should contain a random string.

    $uids

    JSON as string (Optional)

    The list of user identifiers of the user.

    any custom property name

    Any Type

    Any custom property

    The id of the audience datamart in the mediarithmics platform.

    $redirect

    String

    The redirect url. This string should url encoded. (RFC 3986). Warning: this parameters must be placed at the end of the URL. Any parameters that will be placed after the $redirect parameters will not be saved.

    $cuid

    String (Optional)

    The user account id.

    $email

    String (Optional)

    The user email.

    $email_hash

    String (Optional)

    The user email hash.

    $cb

    String (Optional)

    The cache buster parameter. It should contain a random string.

    $uids

    JSON as string (Optional)

    The list of user identifiers of the user.

    any custom property name

    Any Type (Optional)

    Any custom property.

    UserActivity object

    Second bucket: >= 10 & < 100

  • Third bucket: anything that didn't fell into the 2 defined buckets

  • FREQUENCY_TEXT: use this type an infinite (or long) liste of values like keywords, cities, ... Choose wisely the vector_size parameter as it will be used as a modulo on values to reduce the disparity of values to a fixed number

  • General Informations

    • Name: Cohort ML Function

    • Hosting Object Type: UserPoint

    • Field Type Name: ClusteringCohort

    • Field Name: clustering_cohort

    • Query: <Insert here the graphQL query that need to be run to extract attributes used to calculate your cohort>

  • Properties

    • Features: <Insert here the one-line JSON>

    • Cohort Id Bit Size: <Wil be used to define number of cohorts in your datamart as 2^(Cohort Id Bit Size)>

  • Click on Save button

  • ML function creation
  • ML function activation

  • Schema update

  • ML function initial loading

  • Pick attributes from various typology (UserEvent, UserProfile, …)

  • Select between 3 & 10 attributes

  • Have between 50 & 300 values of attributes (from all various attributes)

  • Keep the default of 1024 cohorts (Cohort Id Bit Size = 10, see below for more information about this)

  • Configuration help

    GraphQL Query

    ML function creation

    Note that only one Cohort-based Lookalike model can be set up at a time in an organisation.

    ML function activation

    Schema update

    Don't hesitate to have a look at schema update documentation to learn more about how to update your schema.

    ML function initial loading

    schema documentation
    user guide documentation
    You reference this file in the dashboard as a dataset
  • This source can then be transformed and display like all other data sources.

  • Use the data_file API to upload any JSON file containing your raw data. Its structure is not fixed.

    There are two types of datasets that you can use :

    A default key / value dataset is an array of key / value objects.

    The whole structure of the dashboard is exactly the same as with other data sources.

    • For more information on datasets and datasources, see Datasets and data sources.

    • For a quick start on how to upload a dashboard, see Quickstart.

    The data source declaration is :

    Here is an example with the JSON file we used previously

    You can use a {SEGMENT_ID} token in uri and/or JSON_path properties. It will be replaced by the current segment if the dashboard is loaded on a segment's page. If the dashboard is loaded at any other scope, the token will not be replaced.

    Upload your raw data in the platform

    Key / value dataset

    The value property could be named differently, such as count or value-1 by using the series_title property of the data source.

    Number dataset

    Reference this file in your charts

    [
      {
        "type": "FREQUENCY_ENUM",
        "field_path": "agents.user_agent_info.os_family",
        "values": [
          "OTHER",
          "WINDOWS",
          "MAC_OS",
          "LINUX",
          "ANDROID",
          "IOS"
        ]
      },
      {
        "type": "FREQUENCY_NUMBER",
        "field_path": "profiles.age",
        "intervals": [
          {
            "from": 0,
            "to": 10
          },
          {
            "from": 10,
            "to": 100
          }
        ]
      },
      {
        "type": "FREQUENCY_TEXT",
        "field_path": "events.city",
        "vector_size": 100
      }
    ]
    {agents {user_agent_info {os_family}} profiles {age} events{city}}
    PUT https://api.mediarithmics.com/v1/ml_functions/<id_ml_function>
     {
      "batch_mode": true,
      "status": "ACTIVE"
     }
    type UserPoint  @TreeIndexRoot(index:"USER_INDEX") {
       ...
       clustering_cohort:ClusteringCohort
       ...
    }
    type ClusteringCohort  {
       id:ID! @TreeIndex(index:"USER_INDEX")
       expiration_ts:Timestamp @TreeIndex(index:"USER_INDEX")
       cohort_id:String! @TreeIndex(index:"USER_INDEX")
       last_modified_ts:Timestamp! @TreeIndex(index:"USER_INDEX")
    }
    Sample JSON
      {
          "id": "1",
          "name": "Demographics",
          "other_metadata_as_you_wish": "SEGMENT",
          "genders": [
              {
                "key": "male",
                "value": 358
              },
              {
                "key": "female",
                "value": 66
              }
          ],
          "ages": [
            {
              "key": "18-24",
              "count": 277
            },
            {
              "key": "45-54",
              "count": 8
            },
            {
              "key": "65+",
              "count": 9
            },
            {
              "key": "25-34",
              "count": 12
            },
            {
              "key": "35-44",
              "count": 9
            },
            {
              "key": "55-64",
              "count": 3
            }
        ],
        "total": 666
    }
    {
        "key_value_dataset": [
            {
                "key": "Dimension 1",
                "value": 666
            }
            ...
            {
                "key": "Dimension X",
                "value": 999
            }
        ]
    }
    {
        ...
        "total": 666
    }
    {
          "type": "data_file",
          // URI of the JSON data file containing data
          // Format "mics://data_file/tenants/1426/dashboard-1.json"
          "uri": String,
          // Path of the property in the JSON that should be used as dataset
          // This allows you to have multiple datasets in the same JSON file
          // Should use the JSONPath syntax. See https://jsonpath.com/
          // For example, "$[0].components[1].component.data"
          "JSON_path": String,
          // Optional. Title of the series for tooltips and legends
          "series_title": String
    }
    {
        "sections": [
            {
                "title": "Section",
                "cards": [
                    {
                        "x": 0,
                        "charts": [
                            {
                                "title": "Gender",
                                "type": "Bars",
                                "dataset": {
                                    "type": "data_file",
                                    "uri": "mics://data_file/tenants/XXX/dashboard-1.json",
                                    "JSON_path": "$.genders"
                                }
                            }
                        ],
                        "y": 0,
                        "h": 3,
                        "layout": "vertical",
                        "w": 4
                    },
                    {
                        "x": 4,
                        "charts": [
                            {
                                "options": {
                                    "legend": {
                                        "enabled": true,
                                        "position": "right"
                                    }
                                },
                                "dataset": {
                                    "type": "data_file",
                                    "uri": "mics://data_file/tenants/XXX/dashboard-1.json",
                                    "JSON_path": "$.ages",
                                    "series_title": "count"
                                },
                                "title": "Age range",
                                "type": "Pie"
                            }
                        ],
                        "y": 0,
                        "h": 3,
                        "layout": "vertical",
                        "w": 5
                    },
                    {
                        "x": 9,
                        "charts": [
                            {
                                "title": "Totals",
                                "type": "Metric",
                                "dataset": {
                                    "type": "data_file",
                                    "uri": "mics://data_file/tenants/XXX/dashboard-1.json",
                                    "JSON_path": "$.total"
                                }
                            }
                        ],
                        "y": 0,
                        "h": 3,
                        "layout": "vertical",
                        "w": 3
                    }
                ]
            }
        ]
    }

    volume_drops_threshold alert_type: SEGMENT_VOLUME_DROP Percentage of volume drop in a segment that triggers the alert.

    Value is an integer such as 15. Defaults to 10

    initial_loading_not_starting_hours_threshold

    alert_type: SEGMENT_INITIAL_LOADING Threshold in hours after which an alert will be triggered if the initial loading hasn't started

    Value is an integer & reprents a number of hours Defaults to 24

    initial_loading_running_too_long_hours_threshold

    alert_type: SEGMENT_INITIAL_LOADING Threshold in hours after which an alert will be triggered if the initial loading is taking more time than expected

    Value is an integer & reprents a number of hours Defaults to 24

    initial_loading_records_error_threshold

    alert_type: SEGMENT_INITIAL_LOADING An alert will be triggered if the percentage of errors is above the one defined in this config.

    Value is an integer. Defaults to 10

    alertType*

    string

    . Use the list of allowed configurations.

    alertType*

    string

    . Use the list of allowed configurations.

    alertType*

    string

    . Use the list of allowed configurations.

    volume_drops_segment_labels_mode: alert_type: SEGMENT_VOLUME_DROP Defines whether segment labels in volume_drops_segment_labels_ids config are whitelisted or blacklisted. To edit in the UI, go to alerts on the segment list. For more information, see Using the Segments page.

    blacklist | whitelist. Volume drops apply to all segments if not defined

    volume_drops_segment_labels_ids: alert_type: SEGMENT_VOLUME_DROP List of segment labels that will or won't receive volume drop alerts depending on the volume_drops_segment_labels_mode configuration To edit in the UI, go to alerts on the segment list. For more information, see Using the Segments page.

    organisation_id*

    Int

    ID of the organisation

    configKey*

    string

    Configuration key. Use the list of allowed configurations. Other keys won't have an impact.

    organisationId*

    string

    ID of the organisation for which to create the configuration

    config_value*

    string

    The value of the configuration. Use the list of allowed configurations for the correct value format, depending on your configuration.

    configKey*

    string

    Configuration key. Use the list of allowed configurations. Other keys won't have an impact.

    organisationId*

    string

    ID of the organisation for which to create the configuration

    config_value*

    string

    The value of the configuration. Use the list of allowed configurations for the correct value format, depending on your configuration.

    archived

    Boolean

    true to archive a configuration. false to reactivate it. For more information, see Archived configurations.

    configKey*

    string

    Configuration key. Use the list of allowed configurations. Other keys won't have an impact.

    organisationId*

    string

    ID of the organisation for which to create the configuration

    Accessing configurations

    It is much easier to edit configurations through the UI when available.

    Get all configurations set up for an organisation

    Query Parameters

    Creates a new configuration entry

    Path Parameters

    Request Body

    Change the value or archive a configuration

    Path Parameters

    Request Body

    Deletes a config

    Path Parameters

    Archived configurations

    Sample value: 1,2,3

    Volume drops apply to all segments if not defined

    dimensions*

    array

    to group metrics by.

    date_ranges*

    array

    Periods to analyze. Each date range is an object with a start_date and an end_date. See .

    datamartId*

    number

    The ID of the datamart to query

    metrics*

    array

    Array of Metric to retrieve.

    dimension_filter_clauses

    object

    Filters to apply on dimensions before calculating the metric. For more information, see FilterClause.

    {
        // Retrieve the data in the specified date range
        // Mandatory. The data is only queryable for the last 4 months
        // Only one range is allowed now, but the API is prepared to accept
        // multiple ranges in the future.
        // Tip : you can use dates in "now-Xd/d" format as in OTQL queries
        "date_ranges": [
            {
                "start_date": "2021-10-10T00:00:00",
                "end_date": "2021-10-25T23:59:59"
            }
        ],
        // List of dimensions to retrieve
        "dimensions": [
            {
                "name": "date_yyyy_mm_dd"
            },
            {
                "name": "channel_id"
            }
        ],
        // Filters on dimensions
        "dimension_filter_clauses": {
            "operator": "OR",
            "filters": [
                {
                    "dimension_name": "type",
                    "operator": "EXACT",
                    "expressions": [
                        "SITE_VISIT"
                    ]
                }
            ]
        },
        // Order by dates, beginning with the most recent
        "order_by": {
                "field_name": "-date_yyyy_mm_dd"
        },
        // List of metrics to retrieve
        "metrics": [
            {
                "expression": "users"
            },
              {
                "expression": "number_of_transactions"
            }
        ]
    }
    {
        "status": "ok",
        "data": {
            "report_view": {
                // Note : pagination not implemented yet
                "items_per_page": 100,
                "total_items": 100,
                // To know which data is in which column
                "columns_headers": [
                    "date_yyyy_mm_dd",
                    "channel_id",
                    "users",
                    "number_of_transactions"
                ],
                // Data
                "rows": [
                    [
                        "2021-10-10",
                        666,
                        3881,
                        17800.0
                    ],
                    [
                        "2021-10-10",
                        555,
                        1838,
                        4200.0
                    ],
                    [
                        "2021-10-11",
                        666,
                        532,
                        3900.0
                    ],
                    [
                        "2021-10-11",
                        555,
                        8,
                        100.0
                    ]
                    // ...[
                ]
            }
        }
    }

    Request Body

    report request
    Single resource wrapper
    ReportView
    {
        "status": "ok",
        "data": {
            "report_view": {
                "items_per_page": 100,
                "total_items": 7,
                "columns_headers": [
                    "type"
                ],
                "rows": [
                    [
                        "DISPLAY_AD"
                    ],
                    [
                        "EMAIL"
                    ],
                    [
                        "SITE_VISIT"
                    ],
                    [
                        "USER_SCENARIO_NODE_ENTER"
                    ],
                    [
                        "USER_SCENARIO_NODE_EXIT"
                    ],
                    [
                        "USER_SCENARIO_START"
                    ],
                    [
                        "USER_SCENARIO_STOP"
                    ]
                ]
            }
        }
    }

    source_event_rule

    1

    SHA_512
  • MD5

  • MD2

  • {
        "$ts": 1568296040000,
        "$event_name": "article_view",
        "$properties": {
            "category": "0001",
            "article_id": "super-awesome-article",
            "source": "web"
        }
    }

    article_id

    {{articleId}}

    category_id

    {{categoryId}}

    visit_origin

    {
        "$ts": 1568296040000,
        "$event_name": "article_view",
        "$properties": {
            "category": "0001",
            "article_id": "super-awesome-article",
            "visit_origin": "email",
            "source_event_rule": "1"
        }
    }
    {
        "$ts": 1568296040000,
        "$event_name": "article_view",
        "$properties": {
            "category": "0001",
            "article_id": "super-awesome-article",
            "visit_origin": "{{origin}}",
            "source_event_rule": "1"
        }
    }
    {
        "$event_name": "PageView",
        "$properties": {
            "user_id": "<USER_ID>"
        }
    }

    Url Match

    Limitations

    Please note that $page_view events will be deleted at the end of the activity processing stage.

    Use case

    How to

    Wildcards can be placed several times in the URL pattern. For instance, you can do https://foo.bar/*.* which will match for a route shaped as https://foo.bar/a/b/c.xls

    If a variable used in the event template is not extracted from the URL (either from the path or from the Query String), it's value will be {{variableName}} in the generated event.

    Examples

    User Identifier Insertion

    Contextual Targeting Extractor

    please read this article.
    default JS Snippet
    Contextual targeting > Setup
    Activity Analyzers

    {{origin}}

    Alerting

    mediarithmics modules can trigger alerts to grab the attention of users/integrators on specific points to improve or fix.

    Alerts are displayed in the UI, but can also be accessed by API if you want to automate actions or grab them in your own reports.

    Alert types

    Here are the various alert types that exist:

    Type
    Trigger

    SEGMENT_DEFINITION_ERROR

    Alerts have several properties associated:

    • type: The type of the alert (e.g., SEGMENT_COMPUTATION_ERROR, SEGMENT_VOLUME_DROP...)

    • id: The unique identifier of the alert

    • datamart_id: The identifier of the datamart associated with the alert

    The alerting system supports polymorphism to accommodate specific fields for various alert types.

    Alert type
    Property name
    Value

    To provide a familiar terminology to users, alerts can be opened or closed. However, in the system, the open/closed state is represented by the archived field. Opening an alert sets the archived field to false, while closing an alert sets it to true. The closed state implies that the alert is no longer active or visible to users.

    To avoid having multiple instances of the same alert, the system employs a prevention mechanism. Each alert has count and count_last_ts properties. When triggering a new alert, we check if there is already an active alert for the same target. If such an alert exists, the system increments the count property and updates the count_last_ts to reflect the latest trigger. This prevents the proliferation of identical alerts and ensures that only one alert remains active with an incremented counter.

    For example, if a segment has a query error and the issue persists without resolution, the system will increment the count property of the existing alert rather than creating multiple duplicate alerts.

    The count_last_ts property stores the timestamp of the most recent trigger, while the created_ts property stores the timestamp of the initial trigger.

    To manage the storage of alerts and ensure their relevance, the system implements an expiration mechanism. Alerts have an expiration duration associated with them. It is set to the created_ts + 1 month. You can't modify this behavior.

    A cleaning job runs regularly to identify and delete all expired alerts from the database. This prevents the accumulation of unnecessary historical data.

    The API allows users and integrators to interact with alerts through the following functionalities:API

    GET https://api.mediarithmics.com/v1/alerts

    .

    You have to fill in either the organisation_id, datamart_id or community_id parameters.

    Archived alerts are not returned by default. You need to ask them through the archived parameter.

    Name
    Type
    Description

    PUT https://api.mediarithmics.com/v1/alerts/:alertId

    Name
    Type
    Description
    Name
    Type
    Description

    DELETE https://api.mediarithmics.com/v1/alerts/:alertId

    Name
    Type
    Description

    No other operations or modifications are permitted through the API.

    Users and integrators are restricted from editing any field other than the archived flag for an alert.

    Destination file

    A destination file defines where and how data files generated by the platform are delivered (for example via SFTP or cloud storage). It is configured directly in the computing console.

    On its own, a destination file does not actively export data. It becomes effective when a feed (through the stream-to-file capability) references the destination file using its token (auto-generated). In that case, the feed exports data chunks to the delivery file system, which aggregates them into a single file and delivers it to the targeted destination.

    Typical use cases include:

    • Sending audience segment's user identifiers to an external partner for activation.

    AlertType
    AlertType
    AlertType
    Dimensions
    DateRange
  • organisation_id: The identifier of the organisation associated with the alert

  • community_id: The identifier of the community associated with the alert

  • created_ts: The timestamp indicating when the alert was created

  • archived: A flag indicating whether the alert is closed/archived (true) or open (false)

  • archived_ts: The timestamp indicating when the alert was closed/archived

  • archived_by: The identifier of the user that closed/archived the alert

  • expiration: The expiration timestamp for the alert

  • count: The number of times the alert has been triggered

  • last_count_ts: The timestamp of the most recent trigger of the alert

  • SEGMENT_INITIAL_LOADING

    feed_id

    ID of the feed concerned by the error

    SEGMENT_VOLUME_DROP

    drop_rate

    Total drop (in percentage) of the segment volume since the alert was first triggered

    community_id

    Int

    ID of the community in which to find alerts

    type

    AlertType

    Such as SEGMENT_COMPUTATION_ERROR. See .

    archived

    Boolean

    true to return archived alerts.

    Error in the segment definition. More information here

    SEGMENT_VOLUME_DROP

    Segment volume drops by more than a configured threshold (in percentage).

    In the segment computation process, after it has been computed, we check

    • If volumes have dropped by more than XX%

    • If none of the segment labels are in the blocklist when in blocklist mode

    • If any of the segment labels are in the allowlist when in allowlist mode

    INITIAL_LOADING_ERROR

    Error during initial loading of a feed attached to a segment More information here

    SEGMENT_COMPUTATION_ERROR

    Error during the calculation of a segment More information here

    -

    segment

    {

    'segment_id': 'xxx',

    'segment_name': 'The segment name',

    'segment_type': 'USER_QUERY',

    'user_points_count': 71989,

    'feeds_count': 0

    }

    SEGMENT_INITIAL_LOADING

    alert_sub_type

    organisation_id

    Int

    ID of the organisation in which to find alerts

    datamart_id

    Int

    ID of the datamart in which to find alerts

    alertId

    Int

    ID of the alert to edit

    archive

    boolean

    true to close an alert, false to open it.

    alertId

    Int

    ID of the alert to delete

    Alert properties

    Polymorphism

    For Segment alert

    Open/Close

    Preventing duplicates

    Expiration

    API

    Retrieve a list of alerts based on specific criteria

    Query Parameters

    Change the status of an alert from open to closed or vice versa

    Path Parameters

    Query Parameters

    Path Parameters

    Paginated API

    sub-type of the error:

    • INITIAL_LOADING_EXECUTION_ON_ERROR

    • INITIAL_LOADING_RECORDS_ERROR

    • INITIAL_LOADING_NOT_STARTING

    Supporting custom connectors relying on file-based delivery.

    A destination file can target one of the following systems:

    • SFTP – Secure file transfer over SSH

    • S3 – Amazon S3 buckets

    • Google Cloud Storage – mediarithmics GCS buckets

    The destination type property defines how and where the files are physically uploaded.

    The setup is done in the Computing console > File destinations.

    1

    Create the destination file

    1. Click on New file delivery destination button.

    2. Fill in the required configuration fields.

    3. Save.

    2
    1. In the action menu of the created file delivery destination, select the Credentials option.

    2. Copy the provided template (different for each storage type) and fill it in with the required fields.

    3. Save.

    3

    In the action menu of the created file delivery destination, select the Validate option.

    4

    Use the token to reference the destination file.

    Field
    Description

    Name

    Human-readable name used in the UI.

    Technical name

    Internal identifier used by connectors. This value is referenced in plugin code but has no functional impact by itself.

    Type

    Protocols or object storage type: SFTP, S3, or GOOGLE_CLOUD_STORAGE.

    Field
    Description

    File path macro

    Path (from the root of the destination) where the file will be written. Must not start with / and must end with /. Supports dynamic macros.

    File name macro

    File name to generate. Supports dynamic macros.

    Compression

    File compression mode: NONE, GZIP, or ZIP.

    You must select one of the trigger types:

    1. Size-based: Files are uploaded immediately when they reach the specified size limit. Otherwise, a secondary time-based interval ensures data is delivered even if the size limit is not reached.

    2. Frequency-based: Files are uploaded based on a strict daily limit. This restricts the maximum number of files sent to the destination within a rolling 24-hour period.

    If you have selected Size-based, fill in the following fields:

    Field
    Description

    File max size (KB)

    As soon as the aggregated data reaches this size, the file is immediately uploaded to the destination.

    Recommended value: 100,000 KB (≈100 MB).

    Min upload per day

    Controls the upload frequency (number of upload windows per rolling 24h period). Acts as a secondary trigger when file size is not reached.

    If you have selected Frequency-based, fill in the following field:

    Field
    Description

    Max upload per day

    Divides a rolling 24-hour period into equal upload windows to cap the daily file count. Uploads are only delayed if the destination server is still processing the previous file

    All macros rely on Freemarker templating. Macros can be used in:

    • File path

    • File name

    • File header

    They allow dynamic file organization based on time, segments, or feeds configuration.

    Macro
    Description

    DATE

    Evaluates the date at which the file is generated.

    PROPERTY

    Evaluates a property defined in the plugin configuration.

    SEGMENT.ID

    Returns the segment ID.

    Freemarker date formatting can be used to structure folders:

    This example generates a hierarchical path such as:

    The grouping key is a concept used exclusively in plugins (during the user_segment_update phase) to control how records are aggregated.

    It defines which records belong to the same logical file stream. Records sharing the same grouping key value are grouped together and written into the same file(s).

    The grouping key is defined in the plugin code, not in the destination file configuration. The destination file can then reference it through the ${GROUPING_KEY} macro.

    • Grouping by segment_id Accumulates records belonging to the same segment.

      • Can mix data coming from multiple plugin instances as long as they target the same segment.

      • Useful for segment-centric exports.

    • Grouping by datamart_id Accumulates records coming from all plugin instances within the same datamart.

      • Produces consolidated exports at the datamart level.

    • Grouping by feed_id Accumulates records coming from a single plugin instance only.

      • Ensures strict isolation between feeds.

    File uploads are controlled by two effective parameters. A file is uploaded as soon as one of the active conditions is met.

    • The file max size is always the main limiting factor.

    • While writing records, as soon as the file reaches the configured size limit, it is immediately uploaded to the destination.

    • This behavior applies regardless of time-based settings.

    Despite its name, this parameter should be understood as:

    Number of upload windows per rolling 24-hour period

    • It defines a time-based flush interval.

    • Even if the file size limit is not reached, the file will be uploaded at the end of each interval.

    • The period is rolling, not aligned to fixed clock boundaries.

    The interval duration is calculated as:

    It divides a rolling 24-hour period into equal upload windows to cap the daily file count.

    The interval duration is calculated as:

    Then, it uploads the files to respect the maximum number of files set on the time period.

    If a same file (names match exactly) is present on the destination server, we a delay the upload and aggregate the coming data to send in the next file upload.

    Example 1

    Behavior:

    • Files are uploaded immediately when they reach 100 MB.

    • If the size is not reached, the file is uploaded at the end of a rolling 24-hour period.

    This configuration:

    • Does not guarantee daily delivery (in case of no data coming from the feed).

    • Is suitable when file volume is unpredictable and may require more than one file per day.

    Example 2

    Behavior:

    • Files are uploaded immediately when they reach 100 MB.

    • If the size is not reached, the file is uploaded at the end of a rolling 1-hour period.

    This configuration:

    • Caps delivery to at most one file per hour.

    • Is not suitable if more than one file per hour is required.

    • Use compression for large exports to optimize transfer and storage costs.

    • Prefer date-based partitioning in paths to simplify downstream processing and retention.

    Overview

    data/partner/events/${DATE?string["yyyy/MM/dd"]}/
    data/partner/events/2025/03/18/
    24 hours / min_upload_per_day
    24 hours / max_upload_per_day
    File max size (in kB) = 100000
    Min upload per day = 1
    File max size (in kB) = 100000
    Min upload per day = 24

    Supported protocols & object storages

    Destination file setup

    To validate the connection, the integration user must have an Editor role on the object storage (or equivalent) with permissions to create and delete a temporary empty file for verification.

    Configuration fields

    General information

    File information

    Upload trigger

    Technical appendix

    Macros and templating

    Commonly used variable in macros

    Date formatting example

    Example configuration

    File path macro

    File name macro

    This setup produces compressed, monthly-partitioned files, uniquely identified per execution.

    Grouping key

    Common Grouping Strategies

    File size & upload frequency behavior

    File max size (primary trigger)

    Min upload per day (secondary Trigger)

    Max upload per day

    Examples

    Key notes & best practices

    Reference

    REST resources

    Dashboard registration

    Dashboard registration endpoints let you manage dashboards and where they are displayed. Those endpoint usually take or return DashboardRegistration objects.

    List all dashboard registrations for a specific organisation

    GET https://api.mediarithmics.com/v1/dashboards?organisation_id=:organisation_id

    Returns a paginated resource list wrapper of DashboardRegistration objects.

    Create a dashboard registration.

    POST https://api.mediarithmics.com/v1/dashboards

    Receives a object as body.

    PUT https://api.mediarithmics.com/v1/dashboards/:id?organisation_id=:organisation_id

    Receives a object as body.

    GET https://api.mediarithmics.com/v1/dashboards/:id?organisation_id=:organisation_id

    Returns a object.

    DELETE https://api.mediarithmics.com/v1/dashboards/:id?organisation_id=:organisation_id

    Dashboard content endpoints let you manage the sections, cards and charts in a specific dashboard.

    GET https://api.mediarithmics.com/v1/dashboards/:id/content?organisation_id=:organisation_id

    PUT https://api.mediarithmics.com/v1/dashboards/:id/content?organisation_id=:organisation_id

    This object represents a dashboard and where it should be displayed.

    title string

    The title of the dashboard, as displayed in the UI

    scopes[] enum(home,segments,builders)

    The list of scopes where the dashboard is visible. Mandatory, but can be an empty array.

    segment_ids[] string

    When scopes property contains segments, you can specify a list of segment IDs to only display the dashboard on those specific segments. Mandatory, but can be an empty array.

    builder_ids[] string

    When scopes property contains builders, you can specify a list of standard segment builder IDs to only display the dashboard on those specific builders. Mandatory, but can be an empty array.

    archived boolean

    Set to true to hide a dashboard from the UI without deleting it.

    dashboard_content_id string

    Identifier of the that's been associated with the dashboard registration.

    community_id string

    ID of the community on which the dashboard is visible.

    organisation_id string

    ID of the organisation on which the dashboard is visible. Must be on the community_id community.

    created_ts timestamp

    When the dashboard registration was created. ReadOnly.

    created_by user ID

    By who the dashboard registration was created. ReadOnly.

    last_modified_ts timestamp

    When the dashboard registration was last modified. Not updated when dashboard content is updated as DashboardContent object has its own created_ts field. ReadOnly.

    last_modified_by user ID

    By who the dashboard was last modified. Not updated when dashboard content is updated as DashboardContent object has its own created_by field. ReadOnly.

    This object is returned when doing a GET request to get the content of a dashboard. It returns useful metadata as well as dashboard's content

    id string

    Content's identifier, used in to associate a dashboard and its content.

    content object()

    Dashboard's JSON representation.

    organisation_id string

    ID of the organisation on which the dashboard is visible.

    created_ts timestamp

    When the dashboard content was created. ReadOnly.

    created_by user ID

    By who the dashboard content was created. ReadOnly.

    This object represents the sections, cards and charts displayed in a dashboard.

    available_filters[] object()

    The list of filters activated for the dashboard.

    sections[] object()

    The list of sections inside a dashboard.

    A filter is displayed at the top of a dashboard. The user can select a value and all the queries in the dashboard adapt to the selected value

    A query fragment tells the dashboard how to adapt each query to the value(s) selected by the user.

    A section gives you a title and a new grid to display cards.

    title string

    The title of the section, displayed in the UI.

    cards[] object()

    The list of cards to display in the section.

    A white zone in the section, that displays and organizes charts.

    x,y,h,w int

    The position of the card in the section's grid. See for a guide on how to use it.

    layout enum(vertical, horizontal)

    Wether charts in the card will stack horizontally or vertically.

    charts[] object()

    The list of charts to display in the card.

    A chart displayed in a card.

    title string

    The chart's title, displayed in the UI.

    type enum(Pie, Bars, Radar, Metric)

    The type of chart to display

    colors[] string

    Optional. You can use this property to override default chart colors, which are defined by the theme of the site. Define as many color codes (in #FFFFFF format) as needed by the chart.

    dataset object(Dataset)

    How to get data for the chart

    options object(, , , , )

    Optional. Options specific to the type of chart that has been selected.

    INITIAL_LOADING_RUNNING_TOO_LONG

    More information here
    Alert types

    Edit a dashboard registration

    Get a specific dashboard registration

    Delete a dashboard registration

    Dashboard content

    Get the content of a dashboard. Returns a DashboardContentWrapper.

    Edit the content of a dashboard with the specified DashboardContent.

    DashboardRegistration

    Fields

    DashboardContentWrapper

    Fields

    Each time you do a PUT request to update a dashboard's content, a new DashboardContentWrapper resource is created with a new ID, and the new resource is associated with the dashboard registration. That means the created_ts and created_by fields also represent the last_modified_ts and last_modified_by fields you are used to see.

    DashboardContent

    Filter

    Section

    Card

    Chart

    • For more information on the different chart types and there options, see Charts.

    • For more information on how datasets are built, see Datasets and data sources.

    DashboardRegistration
    DashboardRegistration
    DashboardRegistration
    DashboardContentWrapper
    DashboardRegistration
    DashboardContent
    Filter
    Section
    Card
    Sections, cards and charts
    Chart
    PieOptions
    BarsOptions
    RadarOptions
    MetricOptions
    AreaOptions

    Deduplicate

    When enabled, removes perfect duplicates within a file (two rows that are strictly identical).

    Encoding

    Character encoding. Recommended and supported value: UTF-8.

    File header macro

    Optional header written at the top of the file (for example column names). Can be left empty. Supports macros.

    SEGMENT.TECHNICAL_NAME

    Returns the segment technical name.

    GROUPING_KEY

    Evaluates the grouping_key defined in the plugin code. Used only in the context of a plugin.

    RANDOM_UUID

    Generates a random UUID for uniqueness.

    Add the credentials

    Once saved, you won't be able to read the credential file again. But you will be able to overwrite it.

    Validate the connection

    Use it

    JSON representation
    {
        "title": String,
        "scopes": [Scope]
        "segment_ids": [String],
        "builder_ids": [String],
        "archived": Boolean,
        "dashboard_content_id": String,
        "organisation_id": String,
        "community_id": String,
        // Readonly fields
        "created_ts": Timestamp,
        "created_by": String,
        "last_modified_ts": Timestamp,
        "last_modified_by": String
    }
    JSON representation
    {
        "id": String,
        "content": DashboardContent
        "organisation_id": String,
        "created_ts": Timestamp,
        "created_by": String
    }
    JSON representation
    {
        "available_filters": [Filter]
        "sections": [Section]
    }
    JSON representation
    {
        // Using technical names of compartments, segments or channels 
        // will result in IDs being automatically replaced by names in the UI
        "technical_name": String, 
        "title": String,
        "values_retrieve_method": 'Query', // Only available value at the moment
        // OTQL query to retrieve list of selectable values
        // Use a query string, not the ID of a query
        "values_query": String, 
        // How to adapt queries in the dashboard to the selected value(s)
        "query_fragments": [QueryFragment], 
        "multi_select": Boolean, // If the user can select multiple values
    }
    JSON representation
    {
        // Any available data source such as 'activities_analytics' or 'OTQL'
        "type": String, 
        // Only for OTQL type, chooses which queries should be transformed
        // Select 'ActivityEvent' to transform queries FROM ActivityEvent
        "starting_object_type": String,
        // The query part to add 
        "fragment": String,
    }
    JSON representation
    {
        "title": String,
        "cards": [Card],
    }
    JSON representation
    {
        "x": Int,
        "y": Int,
        "h": Int,
        "w": Int,
        "layout": "vertical" || "horizontal",
        "charts": [Chart],
    }
    JSON representation
     {
        "title": String,
        "type": "Pie" || "Bars" || "Radar" || "Metric" || "Area", 
        "dataset": Dataset,
        "options": PieOptions || BarsOptions || RadarOptions || MetricOptions || AreaOptions
    }
    data/exports/${SEGMENT.TECHNICAL_NAME}/${DATE?string["yyyy/MM"]}/
    events_${GROUPING_KEY}_${RANDOM_UUID}.csv

    Transformations

    Transformations process the result of the inner sources before it is passed to the dataset or to the next transformation.

    "dataset": {
        "type": "transformation-1",
        // Transformations always take a list of sources
        // Even if only one is used
        "sources": [
            {
                // Transformations can be chained
                "type": "transformation-2"
                "sources": [
                    {
                        // End the end we have one more 
                        // query data sources
                        "type": "OTQL"
                        ...
                    }
                ]
            }
        ]
    }

    to-list

    This puts multiple numbers from multiple queries into a key / value dataset. It is important to set the key of each number with the series_title property. It takes from one to any number of sources.

    "dataset": {
        "type": "to-list",
        "sources": [
            {
                "type": "OTQL",
                "query_id": "666", // SELECT @count{} FROM UserPoint WHERE...
                "series_title": "Unknown"
            },
            {
                "type": "OTQL",
                "query_id": "777", // SELECT @count{} FROM UserPoint WHERE...
                "series_title": "With online account"
            },
            {
                "type": "OTQL",
                "query_id": "888", // SELECT @count{} FROM UserPoint WHERE...
                "series_title": "With fidelity program"
            }
        ]
    }

    join

    This joins two key / value datasets into a key / values dataset. It is important to set the name of each series with the series_title property. It takes from one to any number of sources.

    "dataset": {
        "type": "join",
        "sources": [
            {
                "type": "OTQL",
                "query_id": 666, // Select {interests @map} FROM UserPoint WHERE...
                "series_title": "Unkwnown"
            },
            {
                "type": "OTQL",
                "query_id": 777, // Select {interests @map} FROM UserPoint WHERE...
                "series_title": "With fidelity program"
            }
        ]
    }

    to-percentages

    This calculates the representation of each value in the complete dataset. Only one sources is accepted.

    You usually want to use the format: percentage option of the associated data visualisation to automatically change the labels and tooltips and formats to display percentage% (count)

    This calculates the ratio between two numbers (source 1 / source 2 * 100). It only accepts two sources that should each return numbers.

    This calculates the representation of values from a in comparison to an other .

    For example, if 10% of the users in a segment viewed content associated with tag 1, while 5% of the users in the whole datamart viewed content associated with this same tag, the index of tag 1 in segment in comparison to the whole datamart is 10 / 5 * 100 = 200.

    This is typically used to see which values are more/less represented in the first data source compared to the second one. An index above 100 means the value is more represented in the first data source than in the second, a value under 100 means the value is less represented in the first data source than in the second.

    This is usually represented in a Bars chart with a plot_line_value of 100 and an index format :

    For each value in the first dataset, it automatically calculates its percentage representation in the first and the second source, then does the formula source value (in percentages) / comparison value (in percentages) * 100 .

    This formats timestamps and date fields to the specified date format. Available date formats are .

    Use this transformation to allow the display of friendly dates to the user or to allow joining multiple data sources into the same dataset by putting returning dates in the same format.

    Dates must be in the 2021-11-05T00:00:00.000Z format or in timestamp to be formatted. Typical compatible queries are :

    • returning timestamps or @date_histogram.

    • queries returning the date_time dimension

    • queries returning the date_time dimension.

    This transforms a key / value or key / values dataset into a single number to be displayed in .

    • avg calculates the average of values

    • count calculates the number of values

    • first returns the first value

    This transforms identifiers such as channel IDs, compartment IDs and segment IDs into the corresponding channel names, compartment names and segment names.

    Funnel API

    The Data Studio > Funnel page in the navigator uses an API that you can leverage to analyze funnel conversions in your own tools. For more information on the feature, see .

    POST https://api.mediarithmics.com/v1/datamarts/:datamartId/user_activities_analytics

    Use this call to get suggestions or autocomplete values for a dimension

    Name

    Dimensions and metrics

    The dimensions and metrics allowed in the activities analytics API.

    The following dimensions can be requested in reports

    Name
    Title
    Description
  • last returns the last value

  • max returns the maximum value

  • min returns the minimum value

  • sum returns the sum of all values

  • "type": "Radar",
    "dataset": {
        "type": "to-percentages",
        "sources": [{
            "type": "OTQL",
            "query_id": 666 // Select {interests @map} FROM UserPoint WHERE...
        }]
    },
    "options": {
        "format": "percentage"
    }
    "dataset": {
         "type": "ratio",
         "sources": [
              {
              "type": "OTQL",
              "query_id": "666" // SELECT @count{} FROM UserPoint WHERE...
              }, // Returns 100k
              {
              "type": "OTQL",
              "query_id": "777" // SELECT @count{} FROM UserPoint
              } // Returns 200k
         ]
    }
    // Result is 100k/200k*100 = 50
    "type": "Bars",
    "dataset": {
        "type": "index",
        // Use limits like "limit:20" wisely
        // as the index will be calculated for each return value, then ordered.
        // If you only do a @map with a limit of 10 elements returned and you are asking
        // to show the top 10 indexes, you will have the top 10 indexes from the top 10 values
        // A value could be in position 20 by numbers, but in position 2 by index
        "sources": [
            {
                // This query adapts to the current segment
                "type": "OTQL",
                "query_id": 666, // SELECT {interests @map} FROM UserPoint
                "series_title": "Segment"
            },
            {
                // Same query without adapting to the current segment
                // and always returns data for the whole datamart
                "type": "OTQL",
                "query_id": 666,
                "series_title": "Datamart"
                "adapt_to_scope": false
            }
        ],
        "options": {
            "limit": 10 // Number of elements to display. 10 by default
            "order": "Ascending" | "Descending" // Descending by default
            // This means that indexes will only be calculated for values 
            // representing 0.65% of values in source 1.
            "minimum_percentage" : 0.65 // 0 by default. Values between 0 and 100
        }
    },
    "options": {
        "type": "bar",
        "plotLineValue": 100,
        "format": "index" // So that the index is correctly displayed in tooltips
    }
    "dataset": {
         "type": "format-dates",
         "sources": [ // Only one source allowed
              {
                   "type": "OTQL",
                   "query_id": "666" // SELECT {date @date_histogram} FROM UserEvent WHERE...
              },
         ],
          "date_options": {
          "format": "YYYY-MM-DD"
        }
    }
    "type": "Metric",
    "dataset": {
        "type": "reduce",
        "sources": [{
            "type": "OTQL",
            "query_id": 666 // Select {interests @map} FROM UserPoint WHERE...
        }],
        "reduce_options": {
            // avg || count || first || last || max || min || sum
            "type": "count" 
        }
    },
    // This returns channel IDs associated with the value
    "dataset":
         {
              "type": "OTQL",
              "query_id": "666" // SELECT {channel_id @map} FROM UserEvent WHERE...
         }
    }
    
    // This returns channel names associated with the value
    "dataset": {
         "type": "get-decorators",
         "sources": [ // Only one source allowed
              {
                   "type": "OTQL",
                   "query_id": "666" // SELECT {channel_id @map} FROM UserEvent WHERE...
              },
         ],
         "decorators_options": {
              "model_type": "CHANNELS", // CHANNELS || COMPARTMENTS || SEGMENTS
              // Optional if the data source returns sub buckets, 
              // to define the transformation for those sub buckets
              "buckets": { 
                   // Recursive
              	"buckets": {
                		"model_type": "SEGMENTS"
              	}
              }
         }
    }

    ratio

    index

    format-dates

    reduce

    get-decorators

    key / value dataset
    key / value dataset
    Moment.js date formats
    OTQL queries
    Activities analytics
    Collection volumes
    Metric charts
    Type
    Description

    datamartId

    number

    The ID of the datamart

    Name
    Type
    Description

    metrics

    array

    Empty array

    dimension_filter_clauses

    object

    Dimensions filters clause to apply.

    {
        "status": "ok
    

    Here is a sample body payload

    POST https://api.mediarithmics.com/v1/datamarts/:datamartId/user_activities_funnel

    Name
    Type
    Description

    datamartId

    number

    The ID of the datamart

    Name
    Type
    Description

    limit

    number

    When spliting a step on a specific field, sets the maximum values to be retrieved to optimize the query with what would be displayed.For example, set to 5 if you only show the 5 best channel IDs in the UI when splitting by channel ID to optimize the query.

    in

    object

    Period to query the funnel. Should be in the last 4 months maximum.

    {
        "status": "ok",
        "data": {
            "global": {
                "total": 879879879,
                "steps": [
                    {
                        "name": "Step 1",
                        "count": 546546546,
                        "interaction_duration": 0
                    },
                    {
                        "name": "Step 2",
                        "count": 897987984651,
                        "amount": 1213213.27,
                        "conversion": 11221,
                        "interaction_duration": 515151
                    }
                ]
            },
            "grouped_by": []
        }
    }

    Here is a sample payload:

    You can build queries with the following dimensions:

    • Activity Date DATE_TIME

    • Activity Type TYPE

    • Ad Group Id ORIGIN_SUB_CAMPAIGN_ID

    • Brand BRAND

    • Channel Id CHANNEL_ID

    • Campaign Id ORIGIN_CAMPAIGN_ID

    • Category 1 CATEGORY1

    • Category 2 CATEGORY2

    • Category 3 CATEGORY3

    • Category 4 CATEGORY4

    • Creative Id ORIGIN_CREATIVE_ID

    • Device Brand DEVICE_BRAND

    • Device Browser DEVICE_BROWSER_FAMILY

    • Device Carrier DEVICE_CARRIER

    • Device Form Factor DEVICE_FORM_FACTOR

    • Device Model DEVICE_MODEL

    • Device OS DEVICE_OS_FAMILY

    • Has conversion HAS_CONVERSION

    • Has clicked HAS_CLICKED

    • Has bounced HAS_BOUNCED

    • Event type EVENT_TYPE

    • Is in segment SEGMENT_ID

    • Campaign Id CAMPAIGN_ID

    • Goal Id GOAL_ID

    • Product Id PRODUCT_ID

    This object represents a group of filters to apply in a request.

    It has:

    • An operator field to apply either an AND or an OR between the filters

    • A filters array for the list filters to apply. For more information, see Dimensions filters.

    This object represents a filter in a filters clause.

    It has;

    • A dimensions_name field to select the dimension it applies on. For more information, see Dimensions.

    • A not boolean field to apply boolean logic

    • An operator field to select one of the following queries:

      • EXACT will force the dimension to match the first expression set

      • LIKE will allow the dimension to only contain the first expression set

      • IN_LIST

    • A list of expressions representing the keywords to search for.

    Retrieve dimensions values autocomplete

    Query Parameters

    Funnel
    {
      "date_ranges": [
        {
          "start_date": "2021-04-22T00:00:00",
          "end_date": "2021-04-29T23:59:59"
        }
      ],
      "dimensions": [
        {
          "name": "TYPE"
        }
      ],
      "dimension_filter_clauses": {
        "operator": "OR", // OR or AND
        "filters": [
          {
            "dimension_name": "TYPE",
            "operator": "LIKE", // LIKE, EXACT or IN_LIST
            "expressions": [
              ""
            ]
          }
        ]
      },
      "metrics": []
    }
    {
      "for": [
        {
          "name": "Step 1",
          "filter_clause": {
            "operator": "OR",
            "filters": [
              {
                "dimension_name": "TYPE",
                "not": false,
                "operator": "EXACT",
                "expressions": [
                  "DISPLAY_AD"
                ]
              }
            ]
          }
        },
        {
          "name": "Step 2",
          "filter_clause": {
            "operator": "AND",
            "filters": [
              {
                "dimension_name": "EVENT_TYPE",
                "not": false,
                "operator": "EXACT",
                "expressions": [
                  "$transaction_confirmed"
                ]
              },
              {
                "dimension_name": "CHANNEL_ID",
                "not": false,
                "operator": "IN_LIST",
                "expressions": [
                  "8888",
                  "6666"
                ]
              }
            ]
          }
        }
      ],
      "in": {
        "type": "DATES",
        "start_date": "2021-04-23",
        "end_date": "2021-05-01"
      },
      "limit": 5
    }
    "filter_clause": {
      "operator": "OR", // OR or AND
      "filters": [
        ...
      ]
    }
     // TYPE should be DISPLAY_AD
     {
        "dimension_name": "TYPE",
        "not": false,
        "operator": "EXACT",
        "expressions": [
          "DISPLAY_AD"
        ]
      }
    
    // TYPE should contain SITE
    // SITE_VISIT activities will be used
     {
        "dimension_name": "TYPE",
        "not": false,
        "operator": "LIKE",
        "expressions": [
          "SITE"
        ]
      }
    
    // TYPE should not contain SITE
    {
      "dimension_name": "TYPE",
      "not": true,
      "operator": "LIKE",
      "expressions": [
        "SITE"
      ]
    }
    
    // CHANNEL_ID should be either 8888 or 6666
    {
      "dimension_name": "CHANNEL_ID",
      "not": false,
      "operator": "IN_LIST",
      "expressions": [
        "8888",
        "6666"
      ]
    }

    Request Body

    Submit a funnel for results

    Path Parameters

    Request Body

    Dimensions

    Dimensions filters clause

    Dimensions filter

    Examples

    date_time

    Date + time

    The combined value of date and time of the activity in timestamp format

    channel_id

    Channel ID

    The ID of the channel on which the activity was registered

    session_duration

    Session duration

    Duration of the session in seconds

    segment_id

    Segment ID

    IDs of the segments in which the user was when doing the activity. Note : querying this dimension can throw an error if date ranges of the query are too big.

    date_yyyymmdd

    Date

    Date in the YYYYMMDD format

    date_yyyymmddhh

    Date + Hour

    Date in the YYYYMMDDHH format

    date_yyyy_mm_dd

    Date

    Date in the YYYY_MM_DD format

    date_yyyy_mm_dd_hh_mm

    Date + Hour + minutes

    Date in the YYYY_MM_DD_HH_mm format

    has_conversion

    Has conversion

    Boolean. If a $conversion event happened during the activity. For more information, see .

    goal_id

    Goal ID

    IDs of the goals triggered during the activity

    has_bounced

    Has bounced

    Boolean. If the user only visited one page during the activity.

    transaction_amount

    Transaction amount

    Amount spent by the user during the activity.

    number_of_user_events

    Number of events

    Total number of the user triggered during the activity.

    All events (custom and predefined) are counted in this total, except : $conversion $ad_click $ad_view $email_view $email_click $email_sent $email_delivered $email_soft_bounce

    number_of_ad_views

    Number of $ad_view events

    Total number of named $ad_view during the activity.

    number_of_ad_clicks

    Number of $ad_click events

    Total number of named $ad_click during the activity.

    number_of_email_views

    Number of $email_view events

    Total number of named $email_view during the activity.

    number_of_email_clicks

    Number of $email_click events

    Total number of named $email_click during the activity.

    number_of_confirmed_transactions

    Number of $transaction_confirmed events

    Total number of named $transaction_confirmed during the activity

    You can query dimensions specific to the events that happened during each activity.

    event_type

    Event type. Only $transaction_confirmed $item_view $list_item_view $basket_view events are stored at the moment

    brand

    Brands of items related to the events

    category1

    Category 1 of items related to the events

    Informations about the device used during each activity.

    device_form_factor

    Type of device : PERSONAL_COMPUTER SMART_TV GAME_CONSOLE SMARTPHONE TABLET WEARABLE_COMPUTER OTHE

    device_os_family

    OS of the device : WINDOWS MAC_OS LINUX ANDROID IOS OTHER

    device_os_versions

    Version of the OS, for example Windows 8 ios10

    The following dimensions are populated by the Activity origin :

    • origin_campaign_name / origin_campaign_technical_name / origin_campaign_id

    • origin_sub_campaign_technical_name / origin_sub_campaign_id

    • origin_message_id / origin_message_technical_name

    • origin_keywords

    • origin_creative_name / origin_creative_technical_name / origin_creative_id

    • origin_engagement_content_id

    • origin_social_network

    • origin_referral_path

    The following dimensions are populated by the Activity location :

    • location_source

    • location_country

    • location_region

    • location_iso_region

    • location_city

    • location_iso_city

    • location_latitude

    • location_longitude

    The following metrics can be displayed in reports.

    Name
    Title
    Description

    users

    Active users

    The number of distinct active users

    sessions

    Activities / Sessions

    type

    Activity type

    Dimensions

    General dimensions

    See for a list of all activity types.

    Event dimensions

    Only specific predefined events are registered at the moment. See to integrate your events in these dimensions.

    Device dimensions

    Origin dimensions

    Location dimensions

    Metrics

    Audience segment metrics

    Important If you're using the new segment metrics system, please check the dedicated documentation page for up-to-date information:

    Audience segment metrics are a way to offer custom metrics on segments to users. They are visible on the segment listing and segment details pages.

    The value of each metric is calculated regularly for each segment and saved to offer a historic view of its values.

    Segment details page on a datamart with 2 custom audience segment metrics

    The total number of UserPoint is always calculated and displayed, even if there are no custom metrics.

    A segment view without custom metrics

    How to configure metrics

    Audience segment metrics are configured per datamart and built on top of OTQL queries.

    Each metric has:

    • An associated

    • A technical name, possible values being emails, user_accounts, desktop_cookie_ids, mobile_cookie_ids or mobile_ad_ids. You can't use a custom value, and each of these values can only be used once per datamart.

    • A display name shown in the UI

    • A status: DRAFT, LIVE or ARCHIVED.

    • An icon, from a set of possible icons.

    A metric goes from DRAFT status to LIVE and from LIVE status to ARCHIVED. You cannot republish an ARCHIVED metric. You can only remove it.

    GET https://api.mediarithmics.com/v1/datamarts/:datamartId/audience_segment_metrics

    Name
    Type
    Description

    POST https://api.mediarithmics.com/v1/datamarts/:datamartId/audience_segment_metrics

    This creates a DRAFT metric.

    Name
    Type
    Description
    Name
    Type
    Description

    Here is a sample body payload:

    POST https://api.mediarithmics.com/v1/datamarts/:datamartId/audience_segment_metrics/:metricId/action

    This action transitions the metric go from DRAFT to LIVE.status. Any existing metric in LIVE status with the same technical name is ARCHIVED.

    Name
    Type
    Description
    Name
    Type
    Description

    DELETE https://api.mediarithmics.com/v1/datamarts/:datamartId/audience_segment_metrics/:metricId

    Name
    Type
    Description
    1. Only five custom audience segment metrics per datamart are allowed—one per available technical name.

    2. are not supported in the queries.

    Each metric is associated with an icon taken from the following catalogue.

    • display

    • users

    • email-inverted

    • adGroups

    • ads

    • automation

    Tracking API

    You can import y using our dedicated API endpoint.

    POST https://api.mediarithmics.com/v1/datamarts/:datamartId/user_activities

    The body of the request must be a UserActivity object.

    Name
    Type
    Description

    Query Exports

    The platform allows you to export data as ndjson, based on . This action is available in the navigator or through API to automate the process.

    An export is a definition with:

    • a name

    • an output format (always

    Activity analyzers

    An Activity Analyzer is a that allows you to modify an activity on the fly before storing it. It runs as a part of , for each activity of the channel it is associated with.

    This feature is useful for:

    • Reformatting data (adapting the ingestion data model to the datamart schema)

    • Enriching events (for instance by fetching product information based on a product id)

    will allow the dimension to be one of the expressions set
    "
    ,
    "data": {
    "report_view": {
    "items_per_page": 100,
    "total_items": 7,
    "columns_headers": [
    "type"
    ],
    "rows": [
    [
    "DISPLAY_AD"
    ],
    [
    "EMAIL"
    ],
    [
    "SITE_VISIT"
    ],
    [
    "USER_SCENARIO_NODE_ENTER"
    ],
    [
    "USER_SCENARIO_NODE_EXIT"
    ],
    [
    "USER_SCENARIO_START"
    ],
    [
    "USER_SCENARIO_STOP"
    ]
    ]
    }
    }
    }

    dimensions

    array

    Names of the dimensions to retrieve. Usually only one dimension.Use multiple dimensions to get possible values of a dimension if the other dimension is set. For example, using the dimensions TYPE and EVENT_TYPE we can ask for the possible values of EVENT_TYPE if TYPE is SITE_VISIT.

    date_ranges

    array

    Periods to analyze. Each date range is an object with a start_date and an end_date.

    for

    object

    List of steps in the funnel

    $email_hard_bounce
    $email_unsubscribe
    $email_complaint
    $set_user_profile_properties
    $set_user_consent
    $content_correction
    $quit_while_running
    $cleaned_referrer

    category2

    Category 2 of items related to the events

    category3

    Category 3 of items related to the events

    category4

    Category 4 of items related to the events

    device_browser_family

    Browser used during the activity : CHROME IE FIREFOX OPERA STOCK_ANDROID BOT EMAIL_CLIENT MICROSO_EDGE OTHER

    device_browser_version

    Browser's version. For example 10.3.4, 2.2

    device_brand

    Device brand. For example Acer Free

    device_model

    Device model. For example 10 plus 4K Ultraslim

    device_agent_type

    Agent type : MOBILE_APP WEB_BROWSER

    The number of activities / sessions

    conversion_rate

    Conversion rate

    Calculated with (Number of activities with conversions / Total number of activities)

    avg_number_of_sessions_per_user_point

    Average number of sessions per UserPoint

    Calculated from the number of sessions and the number of UserPoint.

    Note : this metric cannot be used with other metrics

    avg_revenue_per_user_point

    Average revenue per UserPoint

    Revenue divided by the number of distinct UserPoint

    Note : this metric cannot be used with other metrics

    avg_number_of_transactions_per_user_poit

    Average number of transactions per UserPoint

    Number of transactions devided by the number of distinct UserPoint

    Note : this metric cannot be used with other metrics

    avg_session_duration

    Average session duration

    Calculated by doing an average of the session_duration dimension.

    revenue

    Revenue

    Sum of transaction_amount dimension

    avg_transaction_amount

    Average transaction amount per activity

    Sum of transaction_amount dimension divided by the number of transactions.

    Note : this metric cannot be used with other metrics

    avg_number_of_user_events

    Average number of user events per activity

    Sum of number_of_user_events dimension divided by the number of activities.

    number_of_user_events

    Total number of user events

    Sum of number_of_user_events dimension

    User activity object
    Predefined event names
    User events
    User events
    User events
    User events
    User events
    User events
    Event transformations
    JSON
    for now)
  • a type (always QUERY for now)

  • an associated query

  • an associated organisation

  • an associated datamart

  • Each export has executions representing its result at a given time.

    An execution goes through different stages:

    • Pending if the export is not started

    • Running if the export is started

    • Succeeded or Failed once the export has been completed

    The resulting file is formatted in ndjson, and contains the properties you selected in the SELECT part of the OTQL query.

    GET https://api.mediarithmics.com/v1/exports?organisation_id=:orgId

    Name
    Type
    Description

    orgId

    integer

    The ID of the organisation for which you want to list exports

    GET https://api.mediarithmics.com/v1/exports/:exportId?organisation_id=:orgId

    Name
    Type
    Description

    exportId

    integer

    The ID of the export

    orgId

    integer

    The ID of the organisation containing the export

    You will first need to create a query for your export.

    POST https://api.mediarithmics.com/v1/exports?organisation_id=:orgId

    Name
    Type
    Description

    orgId

    integer

    The ID of the organisation

    Name
    Type
    Description

    Body

    string

    the request payload

    POST https://api.mediarithmics.com/v1/exports/:exportId/executions

    Name
    Type
    Description

    exportId

    integer

    The ID of the export

    Name
    Type
    Description

    Body

    object

    Must be an empty JSON object : {}

    GET https://api.mediarithmics.com/v1/exports/:exportId/executions

    Name
    Type
    Description

    exportId

    integer

    The ID of the export

    The result of an export is saved as a data file in the platform.

    You have two methods to retrieve it :

    • Using the exports API (recommended)

    • Using the data_file API

    GET https://api.mediarithmics.com/v1/exports/:exportId/executions/:executionId/files/technical_name=:technicalName

    Name
    Type
    Description

    exportId

    integer

    The ID of the export

    executionId

    integer

    The ID of the execution for which to download the report

    Name
    Type
    Description

    technical_name

    string

    The name of the file(s) in the result.output_files of the execution. Usually export when there is a single file.

    GET https://api.mediarithmics.com/v1/data_file/data?uri=mics://data_file/tenants/:organisationId/jobs/executions/:executionId/result/export.data

    Name
    Type
    Description

    executionId

    string

    The ID of the execution

    organisationId

    integer

    The ID of the organisation

    GET https://api.mediarithmics.com/v1/data_file/data?uri=mics://data_file/tenants/:organisationId/jobs/executions/:executionId/result/export.error

    Use this endpoint in case of a FAILED execution status.

    Name
    Type
    Description

    executionId

    string

    The ID of the execution

    organisationId

    integer

    The ID of the organisation

    For punctual exports, you may want to use the navigator (in Data Studio > Exports) rather than our API for more simplicity.

    OTQL queries

    Listing exports

    Path Parameters

    Details of an export

    Path Parameters

    Create an export

    You should check your query and verify its results before creating an export. It is easier to do at this step, as the export would only return an empty file and no message.

    Create an export

    Path Parameters

    Request Body

    Generate an execution

    Path Parameters

    Request Body

    Execution status

    Path Parameters

    If available, the technical name of the file to download is in the result.output_files array

    Download the result of an export

    Download using the exports API

    Path Parameters

    Query Parameters

    Download using the data_file API

    Query Parameters

    Download the error file

    Query Parameters

    {
        "status": "ok",
        "data": [
            {
                "type": "QUERY",
                "id": "9879",
                "organisation_id": "1426",
                "name": "2018-08-29 - Export test segments for Facebook and Adwords",
                "query_id": "65987",
                "datamart_id": "1509",
                "output_format": "JSON"
            },
            {
                "type": "QUERY",
                "id": "9872",
                "organisation_id": "1426",
                "name": "export-visiteurs",
                "query_id": "45987",
                "datamart_id": "1509",
                "output_format": "JSON"
            },
           ...
        ],
        "count": 50,
        "total": 163,
        "first_result": 0,
        "max_result": 50,
        "max_results": 50
    }
    {
        "status": "ok",
        "data": {
            "type": "QUERY",
            "id": "8978",
            "organisation_id": "1426",
            "name": "2018-08-29 - Export test segments for Facebook and Adwords",
            "query_id": "98798",
            "datamart_id": "1509",
            "output_format": "JSON"
        }
    }
    {
        "status":"ok",
        "data":
            {
              "type": "QUERY",
              "id": "8205",
              "organisation_id": "1426",
              "name": "test",
              "query_id": "50409",
              "datamart_id": "1509",
              "output_format": "JSON"
            }
    }
    {
        "status": "ok",
        "data": {
            "parameters": {},
            "organisation_id": "1426",
            "user_id": "2886",
            "result": null,
            "error": null,
            "id": "879879879",
            "status": "PENDING",
            "creation_date": 1612789702668,
            "start_date": null,
            "duration": null,
            "cancel_status": null,
            "debug": null,
            "is_retryable": false,
            "permalink_uri": "MTowOjA65985NjYyOQ==",
            "num_tasks": null,
            "completed_tasks": null,
            "erroneous_tasks": null,
            "retry_count": 0,
            "job_type": "DATAMART_QUERY_EXPORT"
        }
    }
    {
        "status": "ok",
        "data": [
            {
                "parameters": {},
                "organisation_id": "1426",
                "user_id": "8987",
                "result": {
                    "output_files": [
                        "export"
                    ]
                },
                "error": null,
                "id": "7897897",
                "status": "SUCCEEDED",
                "creation_date": 1562595783663,
                "start_date": 1562595789171,
                "duration": 292617,
                "cancel_status": null,
                "debug": null,
                "is_retryable": false,
                "permalink_uri": "",
                "num_tasks": 299808,
                "completed_tasks": 277105,
                "erroneous_tasks": 22703,
                "retry_count": 0,
                "job_type": "DATAMART_QUERY_EXPORT",
                "end_date": 1562596081788
            },
            {
                "parameters": {},
                "organisation_id": "1426",
                "user_id": "8987",
                "result": {
                    "output_files": [
                        "export"
                    ]
                },
                "error": null,
                "id": "9879879",
                "status": "SUCCEEDED",
                "creation_date": 1561655188369,
                "start_date": 1561655192158,
                "duration": 413140,
                "cancel_status": null,
                "debug": null,
                "is_retryable": false,
                "permalink_uri": "",
                "num_tasks": 284602,
                "completed_tasks": 263822,
                "erroneous_tasks": 20780,
                "retry_count": 0,
                "job_type": "DATAMART_QUERY_EXPORT",
                "end_date": 1561655605298
            },
            {
                "parameters": {},
                "organisation_id": "1426",
                "user_id": "9879",
                "result": {
                    "output_files": [
                        "export"
                    ]
                },
                "error": null,
                "id": "4564564",
                "status": "SUCCEEDED",
                "creation_date": 1535555844642,
                "start_date": 1535555850435,
                "duration": 337507,
                "cancel_status": null,
                "debug": null,
                "is_retryable": false,
                "permalink_uri": "",
                "num_tasks": null,
                "completed_tasks": null,
                "erroneous_tasks": null,
                "retry_count": 0,
                "job_type": "DATAMART_QUERY_EXPORT",
                "end_date": 1535556187942
            }
        ],
        "count": 3,
        "total": 3,
        "first_result": 0,
        "max_result": 10,
        "max_results": 10
    }
    // For query SELECT {emails {id}} FROM UserPoint WHERE segments {id="<SEGMENTID>"}
    {"emails":[{"id":"87987987985465432198"}]}
    {"emails":[]}
    {"emails":[]}
    {"emails":[{"id":"46546549879879845654"},{"id":"564654987987465465465"}]}
    {
        "status": "error",
        "error": "Resource Not Found",
        "error_id": "9eedef5f-dfe3-4354-9a2f-d79760113386"
    }
    // Creating an export payload
    {
        "name": "<YOUR_EXPORT_NAME>",
        "output_format": "JSON",
        "query_id": "<ID_OF_QUERY_CREATED_IN_PREVIOUS_STEP>",
        "type": "QUERY"
    }
    phone
    bell
  • bolt

  • check-rounded-inverted

  • check-rounded

  • check

  • chevron-right

  • chevron

  • close-big

  • close-rounded

  • close

  • code

  • creative

  • data

  • delete

  • display

  • dots

  • download

  • email-inverted

  • email

  • extend

  • filters

  • full-users

  • file

  • gears

  • goals-rounded

  • goals

  • image

  • info

  • laptop

  • library

  • magnifier

  • menu-close

  • minus

  • optimization

  • options

  • partitions

  • pause

  • pen

  • phone

  • play

  • plus

  • query

  • question

  • refresh

  • settings

  • smartphone

  • status

  • tablet

  • user

  • users

  • user-query

  • user-pixel

  • user-list

  • video

  • warning

  • datamartId

    string

    The ID of the datamart

    {
        "status": "ok",
        "data": [
            {
                "id": "1555",
                "datafarm_key": "DF_EU_2020_02",
                "datamart_id": "1509",
                "query_id": "50659",
                "technical_name": "user_accounts",
                "display_name": "User Profiles",
                "icon": "users",
                "status": "LIVE",
                "creation_date": 1613125152462,
                "last_modified_date": 1613125152462,
                "last_published_date": null
            },
            {
                "id": "1558",
                "datafarm_key": "DF_EU_2020_02",
                "datamart_id": "1509",
                "query_id": "50659",
                "technical_name": "mobile_cookie_ids",
                "display_name": "User Profiles",
                "icon": "users",
                "status": "LIVE",
                "creation_date": 1613125314757,
                "last_modified_date": 1613125314757,
                "last_published_date": null
            },
            {
                "id": "1566",
                "datafarm_key": "DF_EU_2020_02",
                "datamart_id": "1509",
                "query_id": "50659",
                "technical_name": "mobile_ad_ids",
                "display_name": "User Profiles 7",
                "icon": "users",
                "status": "ARCHIVED",
                "creation_date": 1613128930707,
                "last_modified_date": 1613128930707,
                "last_published_date": null
            },
            {
                "id": "1569",
                "datafarm_key": "DF_EU_2020_02",
                "datamart_id": "1509",
                "query_id": "50659",
                "technical_name": "desktop_cookie_ids",
                "display_name": "User Profiles 4",
                "icon": "gears",
                "status": "LIVE",
                "creation_date": 1613129103522,
                "last_modified_date": 1613129103522,
                "last_published_date": null
            },
            {
                "id": "1570",
                "datafarm_key": "DF_EU_2020_02",
                "datamart_id": "1509",
                "query_id": "50659",
                "technical_name": "desktop_cookie_ids",
                "display_name": "User Profiles 4",
                "icon": "gears",
                "status": "DRAFT",
                "creation_date": 1613129261878,
                "last_modified_date": 1613129261878,
                "last_published_date": null
            }
        ],
        "count": 5,
        "total": 5,
        "first_result": 0,
        "max_result": 50,
        "max_results": 50
    }

    datamartId

    integer

    The ID of the datamart

    Body

    object

    The metric you wish to create

    {
        "status": "ok",
        "data": {
            "id": "1571",
            "datafarm_key": "DF_EU_2020_02",
            "datamart_id": "1509",
            "query_id": "50659",
            "technical_name": "emails",
            "display_name": "User Profiles 7",
            "icon": "users",
            "status": "DRAFT",
            "creation_date": 1613130322659,
            "last_modified_date": 1613130322659,
            "last_published_date": null
        }
    }
    {
        "status": "error",
        "error": "Json object is not structured as expected",
        "error_code": "BAD_REQUEST_FORMAT",
        "error_id": "e18c26a1-7497-470d-8480-2bcb66fc8f16"
    }
    {
        "datamart_id": "<<DATAMART ID>>",
        "query_id": "<OTQL QUERY ID>", 
        "technical_name": "<TECHNICAL_NAME>", 
        "display_name": "User Profiles",
        "icon": "users"
    }

    datamartId

    integer

    The ID of the datamart

    metricId

    integer

    The ID of the metric to publish

    Body

    object

    { "action": "PUBLISH" }

    datamartId

    integer

    The ID of the datamart

    metricId

    integer

    The ID of the metric to remove

    The metrics calculate how many UserPoint in the segment have at least one record. It doesn't count the number of records in the segment.

    If you add a metric that counts the number of cookies and a UserPoint is associated with multiple cookies in the platform, it will be counted as only a +1 and not a +2.

    The metrics values will always be lower or equal to the number of UserPoint in the segment.

    Listing existing metrics

    Path Parameters

    Create an audience metric

    Path Parameters

    Request Body

    You must first create an OTQL query, returning a number corresponding to your metric. As each datamart can have its very own schema, those queries should be tested for each datamart (by API or in the Data Studio) and should return a number. The configured query will be "merged" with the query of each segment to calculate the proper metric.

    Here are some common query examples:

    • SELECT @count{id} FROM UserPoint WHERE agents{} counts the number of UserPoint having at least 1 cookie or mobile ID (user agent)

    • SELECT @count{id} FROM UserPoint WHERE profiles{} counts the number of UserPoint having at least 1 profile

    • SELECT @count{id} FROM UserPoint WHERE emails{} counts the number of UserPoint having at least 1 email

    Activate the audience metric

    Path Parameters

    Request Body

    Remove an audience metric

    Path Parameters

    Limitations

    Available icons

    Most used icons

    Other icons

    OTQL Query
    @cardinality aggregations
    segment metrics documentation

    datamartId

    integer

    The ID of the datamart in which the UserActivity should be imported

    Name
    Type
    Description

    Content-Type

    string

    application/json

    Name
    Type
    Description

    body

    object

    The UserActivity object to import

    The body must be a valid UserActivity object.

    Identification of the user or of the device is achieved through the $user_identifiers property. We encourage you to use as many identifiers as available in your environment at the time of the capture.

    A UserProfile can be created / updated by registering a UserActivity containing a $set_user_profile_properties event. In that case you would need to use $user_account_id and $compartment_id inside $properties to identify the UserProfile to update:

    A UserChoice can be created / updated by registering a UserActivity containing a $set_user_choice event.

    The attribute :userPointSelector is used to select the UserPoint on which apply the query. You can provide the following values :

    An other way to create / update a UserProfile is to use the user_profiles API endpoint . Prefer this method if you are able to integrate various API endpoints and if you don't need to track the UserProfile update as an event for further retrieval.

    PUT https://api.mediarithmics.com/v1/datamarts/:datamartId/user_points/:userPointSelector/user_profiles/compartment_id=:compartmentId/user_account_id=:userAccount

    The body of the request must be a UserProfile object.

    Name
    Type
    Description

    userAccount

    string

    The user_account_id linked to the user_profile that should be imported

    compartmentId

    integer

    The ID of the compartment in which the UserProfile should be imported

    Name
    Type
    Description

    update_strategy

    Enum (Optional)

    Values are PARTIAL_UPDATE, PARTIAL_DELETE, FORCE_REPLACE ()

    Legacy parameters (use update_strategy instead)

    Name
    Type
    Description

    force_replace

    boolean (optional)

    If true, then the UserProfile will be completely replaced by the object passed in the user_profile field. If false, the object passed in the user_profile field will be merged with the existing UserProfile of the UserPoint.

    merge_objects

    boolean (optional)

    Only considered if force_replace is false.

    Manage the comportement between two objects with a same property.

    If false (default value), the new object overrides the existing one.

    If true the new object is merged in deep to the existing one (see ).

    Name
    Type
    Description

    Content-Type

    string

    application/json

    Name
    Type
    Description

    body

    object

    The UserProfile object to import

    The body must be a valid UserProfile object.

    An other way to create / update a UserChoice is to use the user_choices API endpoint . Prefer this method if you are able to integrate various API endpoints.

    PUT https://api.mediarithmics.com/v1/datamarts/:datamartId/user_points/:userSelector/user_choices/processing_id=:processingId

    Name
    Type
    Description

    datamartId

    integer

    The datamart ID

    userSelector

    integer

    An identifier to the UserPoint for which the UserChoice should be added.

    Name
    Type
    Description

    Body

    object

    The payload

    GET https://api.mediarithmics.com/v1/datamarts/:datamartId/user_points/:userSelector/user_choices/processing_id=:processingId

    Name
    Type
    Description

    datamartId

    integer

    The datamart ID

    userSelector

    integer

    An identifier to the UserPoint for which the UserChoice should be added.

    Name
    Type
    Description

    Body

    object

    The payload

    GET https://api.mediarithmics.com/v1/datamarts/:datamartId/user_points/:userSelector/user_choices/processing_id=:processingId/change_log

    Name
    Type
    Description

    datamartId

    integer

    The datamart ID

    userSelector

    integer

    An identifier to the UserPoint for which the UserChoice should be added.

    Name
    Type
    Description

    Body

    object

    The payload

    Beware of the authentication method you choose, so that it is adapted to the context running API calls.

    UserActivity API

    General information

    Import a UserActivity

    Path Parameters

    UserActivit
    { 
    	"$ts" : 3489009384393,
    	"$type" : "APP_VISIT",
    	"$session_status" : "IN_SESSION",
    	"$user_identifiers" : [{
    		"$type": "USER_ACCOUNT",
    		"$compartment_id" : "<COMPARTMENT_ID-1>",
    		"$user_account_id" : "<ACCOUNT_ID-1>"
    	},
    	{
    		"$type": "USER_ACCOUNT",
    		"$compartment_id" : "<COMPARTMENT_ID-1>",
    		"$user_account_id" : "<ACCOUNT_ID-2>"
    	},
    	{
    		"$type": "USER_AGENT",
    		"$user_agent_id" : "<USER_AGENT_ID>"
    	},
    	{
    		"$type": "USER_EMAIL",
    		"$hash" : "<USER_EMAIl_HASH>",
    		"$email" : "<USER_EMAIl>"
    	}],
    	"$app_id" : "1023",
    	"$events" : [
    	{
    		"$ts" : 3489009384393,
    		"$event_name" : "$app_open",
    		"$properties" : {}
    	}]
    }
    { 
    	"$ts" : 3489009384393,
    	"$type" : "APP_VISIT",
    	"$session_status" : "IN_SESSION",
    	"$user_agent_id" : "<USER_AGENT_ID>",
    	"$compartment_id" : "<COMPARTMENT_ID>",
    	"$user_account_id" : "<ACCOUNT_ID>",
    	"$app_id" : "1023",
    	"$events" : [
    	{
    		"$ts" : 3489009384393,
    		"$event_name" : "$app_open",
    		"$properties" : {}
    	}]
    }
    { 
    	"$ts" : 3489009384393,
    	"$type" : "APP_VISIT",
    	"$session_status" : "IN_SESSION",
    	"$user_identifiers" : [{
    		"$type": "USER_ACCOUNT",
    		"$compartment_id" : "<COMPARTMENT_ID>",
    		"$user_account_id" : "<ACCOUNT_ID>"
    	}],
    	"$app_id" : "1023",
    	"$events" :[{
            	"$ts" : 1679588413000,
    	        "$event_name" : "$set_user_profile_properties",
            	"$properties" : {
                   		"$compartment_id" : "<COMPARTMENT_ID>",
                   		"$user_account_id" : "<ACCOUNT_ID>",
                   		"gender" : "Male",
    	               	"zipcode" : "78000"
            	}
    	}]
    }
    // Sample UserActivity to add using the tracking API
    {
        "$user_account_id":"<your_user_account_id>",
        "$compartment_id":<your_compartement_id>,
        "$type":"<your_activity_type (ex: SITE_VISIT)",
        "$site_id": "<your_site_id>",
        "$session_status":"NO_SESSION",
        "$ts":<a_timestamp (ex:1572947762)>,
        "$events": [
            {
            "$event_name":"$set_user_choice",
            "$ts":<a_timestamp (ex:1572948120)>,
            "$properties":{
                "$processing_id": "<your_processing_id>", // Mandatory
                "$choice_acceptance_value":<true/false>, // Mandatory
                "<your_custom_field>" : "<your_custom field_value>"
                }
            }
        ]
    }
    // Select a UserPoint using a user_point_id
    /v1/datamarts/<DATAMART_ID>/user_points/<USER_POINT_ID>/user_profiles/compartment_id=:compartmentId/user_account_id=:userAccountId
    /v1/datamarts/<DATAMART_ID>/user_points/user_point_id=<USER_POINT_ID>/user_profiles/compartment_id=:compartmentId/user_account_id=:userAccountId
    
    // Select a UserPoint using a user_agent_id
    /v1/datamarts/<DATAMART_ID>/user_points/user_agent_id=<USER_AGENT_ID>/user_profiles/compartment_id=:compartmentId/user_account_id=:userAccountId
    
    // Select a UserPoint using a user_account_id + compartment_id
    /v1/datamarts/<DATAMART_ID>/user_points/compartment_id=<COMPARTMENT_ID>,user_account_id=<USER_ACCOUNT_ID>/user_profiles/compartment_id=:compartmentId/user_account_id=:userAccountId
    
    // Select a UserPoint using an email_hash
    /v1/datamarts/<DATAMART_ID>/user_points/email_hash=<EMAIL_HASH>/user_profiles/compartment_id=:compartmentId/user_account_id=:userAccountId
    { 
    	"$compartment_id" : ":compartment_id",
    	"$user_account_id" : ":user_account_id",
    	"gender" : "female",
    	"zipcode" : "75001"
    }
    // Sample payload
    {
        "$choice_ts": "<a_timestamp (ex:1573135588140)>", // Mandatory
        "$choice_acceptance_value":<true/false>, // Mandatory
        "<your_custom_field>" : "<your_custom field_value> // Optional
    }

    Headers

    Request Body

    It is still possible to use the identifiers properties at the activity root level ($user_agent_id, $user_account_id + $compartment_id, $email_hash), however these are to be considered as legacy.

    $user_identifiers property is to be preferred.

    Create / Update a UserProfile from within an activity

    Note that you can used any identifier available on the UserPoint in the UserActivity object

    Create / Update a UserChoice from within an activity

    This method is used when you want to achieve real-time tracking but can't use the mediarithmics JavaScript Tag. In mobile applications for example.

    Please note that those events will go through the before being stored as a UserChoice. You must ensure no is removing them during that process.

    UserPoint API

    UserPoint selector

    Create / Update a UserProfile

    Create/Update a UserProfile

    Path Parameters

    Query Parameters

    Headers

    Request Body

    $compartment_id & $user_account_id in the payload are not mandatory since they are already provided as query parameters.

    Beware of :

    • <COMPARTMENT_ID> & <USER_ACCOUNT_ID> which are used to select the UserPoint

    Create / Update a UserChoice

    Create/Update UserChoice

    Path Parameters

    Request Body

    List UserChoice

    Path Parameters

    Request Body

    UserChoice history

    Path Parameters

    Request Body

    Improving data quality (filtering unwanted events, matching input values to standard catalogs, parsing URLs into categories etc.)

    Activity analyzers have only one predefined endpoint to implement

    POST myworker/v1/activity_analysis

    This entry point is called any time an activity is processed by the platform. The activity analyzer receives an activity and responds to the request by returning a new activity. It cannot modify the identifiers that are passed in the incoming activities.

    Name
    Type
    Description

    activity_analyzer_id

    string

    The ID of the activity analyzer instance that should be used to process the activity. Used to retrieve the instance properties.

    datamart_id

    string

    The ID of the datamart

    {
        "status": "ok",
        "data": { 
            // New UserActivity object
        }
    }
    {
      "status": "error",
      "error": "Your error message"
    }

    See Plugin Instances to learn why you should use the activity_analyzer_id parameter to retrieve the instance properties.

    The code of the activity analyzer can call the following API endpoints to retrieve its instance context.

    GET https://api.mediarithmics.com/v1/activity_analyzers/:id

    Use the activity_analyzer_id from the incoming request to retrieve the activity analyzer instance that has been called.

    Name
    Type
    Description

    id

    string

    ID of the activity analyzer, typically the activity_analyzer_id from the incoming request.

    {
      "status": "ok",
      "data": {
        "id": "1000",
        "name": "my analyzer",
        "organisation_id": "1000",
        "visit_analyzer_plugin_id": "1001",
        "group_id": "com.mediarithmics.visit-analyzer",
        "artifact_id": "default"
      }
    }

    GET https://api.mediarithmics.com/v1/activity_analyzers/:id/properties

    Get the properties associated with the activity analyzer instance

    Name
    Type
    Description

    id

    string

    ID of the activity analyzer, typically theactivity_analyzer_id from the incoming request

    {
      "status": "ok",
      "data": [
        {
          "technical_name": "debug",
          "value": { "value": false },
          "property_type": "BOOLEAN",
          "origin": "PLUGIN",
          "writable": true,
          "deletable": false
        },
        {
          "technical_name": "topic_properties",
          "value": { "value": "vertical" },
          "property_type": "STRING",
          "origin": "PLUGIN",
          "writable": true,
          "deletable": false
        }
      ],
      "count": 2
    }

    See the plugins documentation to see how plugins are created and deployed.

    Use our Plugins SDK to create your activity analyzer in nodejs : the required routes are already defined and you only have to override specific functions.

    We can provide you with a hello world project using our SDK. Please contact your Account manager in order to have access to it.

    The project structure and files work as with every other plugin.

    Your should extend ActivityAnalyzerPlugin class and implement the instanceContextBuilder and onActivityAnalysisfunctions from the plugins SDK.

    onActivityAnalysis function is called every time an activity runs through the activity analyzer. It is responsible for the activity transformation.

    The instance context built in instanceContextBuilder is cached to improve performances. It should retrieve and store the plugin properties and configuration files used by the code.

    Your instance context interface should extend ActivityAnalyzerBaseInstanceContext

    Like other plugins, activity analyzer need to be instantiated. To create an instance, connect to Navigator and head toward Settings > Datamart > Activity Analyzers. You will get a list of existing instances and a button to create new ones.

    Click on New Activity Analyzer.

    Select the activity analyzer you want to instantiate.

    Enter a name to easily recognize the instance, select an Error recovery strategy and fill Properties if you need to overwrite some of them. Save your modifications to create a new instance of your activity analyzer.

    The error recovery strategy determines how the activity is processed when the plugin fails.

    error_recovery_strategy
    Failure reaction

    STORE_WITH_ERROR_ID

    The activity will be sent without any modification to the next activity analyzer.

    STORE_WITH_ERROR_ID_AND_SKIP_UPCOMING_ANALYZERS

    The activity will be saved without modification of the activity analyzer in failure. It doesn't be sent to the next plugin.

    DROP

    Once your activity analyzer instance is created, you can link it to one or multiple channels. To do so, connect to Navigator and head toward Settings > Datamart > Channels and select the channel where you want your activity analyzer to be executed.

    Go to the Activity Analyzers category.

    Click on Add an Activity Analyzer and select your instance.

    Several activity analyzers can be used on the same channel. In this case, they will process the same activity in a sequence of your choice: the second analyzer will process the activity as rendered by the first one and so on...

    Make sure to define the right order and error recovery strategies.

    As activity analyzers are plugin, you can monitor them as you do with all plugins.

    1. Go to the navigator > monitoring and search for the UserPoint associated with the activity.

    2. Click on the view json button on any activity on a timeline

    3. You can check if all the properties are OK and if your activity analyzers processed the activity as expect

    In case of problem, you can look at two properties added to the activity. processed_by will tell you if the activity has been processed by your activity analyzer, and $error_analyzer_id will give you an error ID if the activity analyzer returned an error response.

    Plugin
    the processing pipeline
    import { core } from "@mediarithmics/plugins-nodejs-sdk";
    import { CustomInstanceContext } from "./interfaces/InstanceContextInterface";
    
    export class ActivityAnalyzerPlugin extends core.ActivityAnalyzerPlugin {
        // Called to update a UserActivity
        // Uses the instance context built with instanceContextBuilder
        // to adapt to the properties and technical files
        protected async onActivityAnalysis(
            request: core.ActivityAnalyzerRequest,
            instanceContext: CustomInstanceContext)
                : Promise<core.ActivityAnalyzerPluginResponse> {
    
            try{
                const updatedActivity = request.activity;
    
                // Your code to modify the activity.
                // Exemple adding product infos in each event
                // If the technical configuration allows it
                if (instanceContext.technicalConfig.updateActivities){
                    updatedActivity.$events.forEach(event => {
                        if (event.$properties && event.$properties.$items && event.$properties.$items.length > 0) {
                          event.$properties.$items.forEach((item: any) => {
                            var product = Products.find(p => p.$id == item.$id);
                            item.$name = product.$name;
                            item.categories = product.categories;
                            item.inStock = product.inStock;
                          });
                        }
                    });
                }
    
    
                const response: core.ActivityAnalyzerPluginResponse = {
                    status: "ok",
                    data: updatedActivity
                };
    
                return Promise.resolve(response);
            }
            catch (err) {
              const errorResponse: core.ActivityAnalyzerPluginResponse = {
                status: 'error',
                data: request.activity
              };
              this.logger.error(`TRANSFORMATION ERROR while processing activity: ${JSON.stringify(request.activity)}`);
              return Promise.resolve(errorResponse)
            }
        }
    
        // Build the instance context
        // by fetching properties and configuration files
        protected async instanceContextBuilder(activityAnalyzerId: string)
            : Promise<CustomInstanceContext> {
            const baseInstanceContext = await super.instanceContextBuilder(activityAnalyzerId);
            try {
    
               // Retrieve a technical configuration file
               const validator = new Jsonschema.Validator();
               const technicalConfig: ITechnicalConfig = await this.validateJSONSchema(TECH_CONFIG_FILE, validator, technicalConfigurationSchema, activityAnalyzerId);
    
               // Retrieve a property from the plugin instance
               const eventExclusionList = baseInstanceContext.properties.findStringProperty("events_exclusion_list");
    
               // Return the completed instance context
                const result: CustomInstanceContext = {
                    ...baseInstanceContext,
                    event_exclusion_list: eventExclusionList,
                    technicalConfig: technicalConfig
                };
    
                this.logger.debug(`Loaded InstanceContext with: ${JSON.stringify(result,null,4)}`);
                return Promise.resolve(result);
            } catch (err) {
                this.logger.error(`Something bad happened during the build of the Instance Context ${err}`);
                return Promise.reject(`Something bad happened during the build of the Instance Context ${err}`);
            }
        };
    }
    import { core } from "@mediarithmics/plugins-nodejs-sdk";
    
    export interface CustomInstanceContext 
      extends core.ActivityAnalyzerBaseInstanceContext 
      {
        event_exclusion_list: string[];
        technicalConfig: ITechnicalConfig;
    }
    {
      "processed_by": "<YOUR_ANALYZER_ID>",
      "$error_analyzer_id": "<ERROR_ID>"
    }

    If you don't know what a plugin is, you can find the

    An activity analyzer is only executed for activities tracked in real time, e.g. via the user_activity API, javascript tag or pixel tracking (see ). If you want to upload bulk activities, make sure they are already formatted before starting the upload as the activity analyzer won't run.

    The standard group ID for an activity analyzer is {domain}.{organisation}.activity-analyzer, for example com.mediarithmics.activity-analyzer

    Endpoints to implement

    Process an activity

    Request Body

    If you need to create or update user profiles using the dedicated event $set_user_profile_properties , please refer to .

    Specifically note that you must use properties $compartment_id and (optionnally) $user_account_id.

    Properties $set_user_profile_comp_token / $set_user_profile_user_account_id

    Available outbound services

    Retrieve the instance

    Path Parameters

    Retrieve the instance properties

    Path Parameters

    Creating an activity analyzer

    An activity analyzer has the ACTIVITY_ANALYZER plugin type. Its group id should be {domain.organisation.activity-analyzer} (for example com.mediarithmics.activity-analyzer). Its artifact id should be the name of the activity analyzer, ie update-product-infos.

    You can find a sample activity analyzer .

    Interfaces to implement

    Don't forget to catch your errors. You should log / respond with the appropriate message to facilitate debugging.

    Creating an instance

    Linking an instance to a channel

    Currently, you can't get more than 5 activity analyzers. If you need more, please contact your Account manager.

    Debugging

    Plugin logs and metrics

    Verifying an activity

    UserActivity that run through activity analyzers are generally aggregated into sessions. You won't see your UserActivity until it has been put into a session and gone through the whole activity processing pipeline. See to understand when you should see your activity or how you could fasten the process.

    Cookbook

    This page references recipes you can use to speed up your data visualization learning curve.

    Use the to display dates in a user-friendly way.

    You can do the same with the result of a join

    With this technique, you can also combine data from different data sources where the date would be returned in different formats.

    A nice way to display collection volumes is by showing the actual number of elements in the collection with a quick history of the volumes.

    :compartmentId & :userAccountId which are used to select the profile to update

    datamartId

    integer

    The ID of the datamart in which the UserProfile should be imported

    userSelector

    string

    The identifier of the user for whom the UserProfile should be imported. see the options of the user selector.

    processingId

    integer

    The ID of the associated processing

    processingId

    integer

    Optional. The ID of the processing for which you want to list UserChoices.

    processingId

    integer

    The ID of the processing for which you want to get UserChoice history.

    Detailed examples
    example
    processing pipeline
    activity analyzers
    are reserved for the case when the event is
    . They are translated into the above ones before the activity analyzer is called and should not be used in it.

    activity

    object

    The UserActivity Object to analyze

    The activity won’t be saved

    complete documentation in the specific section.
    real time user tracking guide
    Create / Update a UserProfile from within an activity
    in the examples folder of the plugins SDK
    how sessions are built
    triggerred from a website via our javascript tag

    This can be achieved with two Charts in the same Card :

    • A Metric chart using an OTQL query in its dataset, such as SELECT @count{} FROM UserPoint

    • A Bars chart using a Collection volumes query in its dataset.

    Another tip when showing collection volumes is to replace lists of metrics with bar charts. This makes it easier to visualize proportions, especially if you have a reference number like the total number of UserPoint.

    You may want to compare a particular audience you are building or that's been built to the whole datamart or to a specific reference audience.

    For example to answer the question Do users in this audience have different viewing modes than all users ? you can build a dashboard at the builders and/or the segments scope with :

    • The number of UserPoint visiting through each viewing mode for your audience

    • The number of UserPoint visiting through each viewing mode for all users

    • Index calculation to visualize which viewing modes are more/less used in your audience

    In the following example, people in the audience are more likely to get touched in LIVE events that in replays.

    When doing any chart that returns channels, compartments or segments, you will usually want to display names instead of IDs in the UI.

    For this, use the get-decorators transformation to replace IDs with names.

    Display channel names instead of channel IDs

    @cardinality OTQL queries return a key / value dataset. In lots of cases, this dataset only has one value but can't be displayed as a metric as it is not in the correct format.

    We can use the reduce transformation to put the dataset in the correct format.

    Chart's JSON
     {
        "title": "Application events (last 6 months)",
        "type": "Bars",
        "dataset": {
            "type": "format-dates",
            "sources": [
                {
                    // @date_histogram query
                    "type": "OTQL",
                    "query_id": "666"
                }
            ],
            "date_options": {
                "format": "YYYY-MM-DD"
            }
        }
    }
    Chart's JSON
    {
        "title": "Montly events per channel or type-",
        "type": "Bars",
        "dataset": {
            "type": "format-dates",
            "sources": [
                {
                    // This works with a join but this can also work from a single source
                    // without the join
                    "type": "join",
                    "sources": [
                        {
                            "type": "OTQL",
                            // Select {date @date_histogram } FROM UserEvent
                            // WHERE channel_id = XXX
                            "query_id": "666", 
                            "series_title": "Group 1"
                        },
                        {
                            "type": "OTQL",
                            // Select {date @date_histogram } FROM UserEvent
                            // WHERE channel_id = YYY
                            "query_id": "777",
                            "series_title": "Group 2"
                        },
                        {
                            "type": "OTQL",
                            // Select {date @date_histogram } FROM UserEvent
                            // WHERE channel_id = ZZZ
                            "query_id": "888",
                            "series_title": "Group 3"
                        }
                    ]
                }
            ],
            "date_options": {
                "format": "YYYY-MM-DD" // The date format we want to return
            }
        },
        // Show the legend for a better event display
        "options": {
            "legend": {
                "enabled": true,
                "position": "bottom"
            },
            "big_bars": false // Allow space between dates
        }
    }
    Chart's JSON
    {
        "title": "Events",
        "type": "Bars",
        "dataset": {
            "type": "join",
            "sources": [
                // Get some counts from activities analytics by month
                {
                    "type": "activities_analytics",
                    "query_json": {
                        "dimensions": [
                            {
                                "name": "date_YYYYMMDD"
                            }
                        ],
                        "metrics": [
                            {
                                "expression": "number_of_user_events"
                            }
                        ]
                    },
                    "series_title": "activities_analytics"
                },
                // Get other counts from OTQL by month with @date_histogram
                // and format the result in the same format as activities analytics
                {
                    "type": "format-dates",
                    "sources": [
                        {
                            "type": "OTQL",
                            "query_id": "666"
                        }
                    ],
                    "series_title": "OTQL",
                    "date_options": {
                        "format": "YYYYMMDD"
                    }
                }
            ]
        },
        "options": {
            "hide_x_axis": true // We hide the x axis as there are a lot of values
        }
    }

    Working with dates

    Single series

    Multiple series

    Combining different data sources

    Collection volumes

    format-dates transformation
    Card's JSON
    {
        // Card display options.
        // Here we show a small card with a vertical layout
        "x": 0,
        "y": 0,
        "h": 2,
        "w": 3,
        "layout": "vertical",
        // The two charts in the card
        "charts": [
            {
                // The number of UserPoint as a metric
                "title": "UserPoint",
                "type": "Metric",
                "dataset": {
                    "type": "OTQL",
                    "query_id": "666" // SELECT @count FROM UserPoint
                }
            },
            {
                // Bars showing a history of the number of UserPoint
                "title": "",
                "type": "Bars",
                "dataset": {
                    // We do use the format-dates transformation to display
                    // friendly dates instead of timestamps
                    "type": "format-dates",
                    "sources": [
                        {
                            "type": "collection_volumes",
                            "query_json": {
                                "dimensions": [
                                    {
                                        "name": "date_time"
                                    },
                                    {
                                        "name": "collection"
                                    }
                                ],
                                "dimension_filter_clauses": {
                                    "operator": "AND",
                                    "filters": [
                                        {
                                            "dimension_name": "datamart_id",
                                            "operator": "EXACT",
                                            "expressions": [
                                                YOUR_DATAMART_ID
                                            ]
                                        },
                                        {
                                            "dimension_name": "collection",
                                            "operator": "EXACT",
                                            "expressions": [
                                                "UserPoint"
                                            ]
                                        }
                                    ]
                                },
                                "metrics": [
                                    {
                                        "expression": "count"
                                    }
                                ]
                            }
                        }
                    ],
                    "date_options": {
                        "format": "YYYY-MM-DD HH:mm"
                    }
                },
                // We hide axis to have a nice little chart only showing trends
                // with the ability for the user to get values by hovering the bars
                "options": {
                    "hide_x_axis": true,
                    "hide_y_axis": true
                }
            }
        ]                
    }
    Card's JSON
    {
        "x": 0,
        "charts": [
            {
                "title": "UserPoint",
                "type": "Metric",
                "dataset": {
                    "type": "OTQL",
                    "query_id": "666"
                }
            },
            {
                "title": "Activability",
                "type": "Bars",
                "dataset": {
                    "type": "to-list",
                    "sources": [
                        {
                            "type": "OTQL",
                            "query_id": "111",
                            "series_title": "Total UserPoint"
                        },
                        {
                            "type": "OTQL",
                            "query_id": "222",
                            "series_title": "With accounts"
                        },
                        {
                            "type": "OTQL",
                            "query_id": "333",
                            "series_title": "With emails"
                        },
                        {
                            "type": "OTQL",
                            "query_id": "444",
                            "series_title": "With web cookies"
                        },
                        {
                            "type": "OTQL",
                            "query_id": "555",
                            "series_title": "With apple Mobile ID"
                        },
                        {
                            "type": "OTQL",
                            "query_id": "666",
                            "series_title": "With google Mobile ID"
                        }
                    ]
                },
                "options": {
                    "type": "bar",
                    "hide_y_axis": true,
                    "colors": [
                        "#333333"
                    ]
                }
            }
        ],
        "y": 0,
        "h": 5,
        "layout": "vertical",
        "w": 4
    }
    {
        "title": "Viewing modes",
        "type": "Bars",
        "dataset": {
            "type": "index",
            "sources": [
                {
                    "type": "OTQL",
                    "query_id": "666", // SELECT {events {session_mode @map}} FROM UserPoint
                    "series_title": "Segment"
                },
                {
                    "type": "OTQL",
                    "query_id": "666", // SELECT {events {session_mode @map}} FROM UserPoint
                    "series_title": "Datamart",
                    "adapt_to_scope": false
                }
            ],
            "options": {
                "limit": 10,
                "minimum_percentage": 1,
                "sort": "Descending"
            }
        },
        "options": {
            "type": "bar",
            "plot_line_value": 100,
            "format": "index"
        }
    }
    {
        "title": "Data by channels",
        "type": "Bars",
        "dataset": {
            "type": "get-decorators",
            "sources": [
                {
                    "type": "to-percentages",
                    "sources": [
                        {
                            "type": "OTQL",
                            "query_id": "666" // SELECT { channel_id @map} FROM UserEvent WHERE ...
                        }
                    ]
                }
            ],
            "decorators_options": {
                "model_type": "CHANNELS"
            }
        },
        "options": {
            "format": "percentage"
        }
    }
    {
        "title": "Number of different event names retrieved",
        "type": "Metric",
        "dataset": {
            "type": "reduce",
            "sources": [
                {
                    "type": "OTQL",
                    "query_id": "666" // SELECT {nature @cardinality} FROM ActivityEvent
                }
            ],
            "reduce_options": {
                "type": "first"
            }
        }
    }

    Comparing audiences

    Working with channel, compartments and segments

    Using the reduce transformation to display a @cardinality OTQL query as a metric

    Datasets and data sources

    A dataset is built based on at least one data source, and optional transformations and processed for visualisation in Charts.

    You can retrieve data from the following data sources :

    • OTQL queries

    • Activities analytics data cube

    • data cube

    • data cube

    • data cube

    Depending on the query you run and the transformations you apply, you can build different types of datasets. Here is a recap of which datasets are created from which data sources and transformations and the available visualisations for each.

    Dataset
    Created from
    Compatible with

    Here is an example dataset with only one data source, that returns a number :

    You can build the same kind of dataset with a different data source, like :

    Use this type of dataset in charts to display a single number.

    Queries in the preceding paragraph were only returning numbers, but you can build key / value datasets with more complex queries like and .

    You can pass this kind of dataset in , and charts to visualize the content.

    Key / value datasets also come from transformations like to-list, to create a list from multiple numbers. You can note the series_title property that gives you control over the title that will be displayed in tooltips and legends.

    You can go further by adding up to three levels of buckets in your dataset with and .

    This can then be displayed with and charts, with drill down or multiple / stacking bars.

    The join transformation with multiple key / value datasets with common keys creates a single dataset with multiple values associated with each key.

    The two groups can be displayed together in and charts to efficienly compare their data.

    A dataset is formed with a tree of data sources and transformations chained.

    All data sources have a series_title property. This is useful when combining multiple sources together to set the title associated with each source. This will be reflected in tooltips and legends. Here is an example of a Datamart and a Segment data sources combined together.

    All data sources have a datamart_id property allowing you to specify the datamart on which to run the query. It defaults to current datamart. This allows you to bring data for an other datamart or to create a dashboard at the community level that aggragates data from sub organisations.

    The user loading the dashboard should have the permissions to query the specified datamart or the chart will throw an error for this user.

    By defaults, all data sources will try to adapt to the page on they are executed, with the adapt_to_scope property set to TRUE.

    The goal is to :

    • Filter data for the current segment when a dashboard is displayed on a segments page

    • Filter data based on the current query when a dashboard is displayed on a builder.

    For OTQL data sources :

    • On home scopes, nothing is changed and the query is run as is.

    • On segments scopes, the current segment's query is added at the end of the OTQL query. That means that only OTQL queries FROM UserPoint will adapt to the scope.

    For activities analytics data sources :

    • On home and builders scopes, nothing changes and the query is run as is.

    • On segments scopes, activities are filters so that only those of users that were in the segment while having the activity will be kept.

    Defining your schema

    Schemas are associated with datamarts by managing objects with the following properties:

    Make sure you learned about .

    // DRAFT Schema
    {
        "id": "1385",
        "datamart_id": "1509",
        "status": "DRAFT",
        "creation_date": 1609888013947,
        "last_modification_date": 1610443926552,
        "publication_date": null,
        "suspension_date": null
    }
    
    // LIVE Schema
    {
        "id": "1281",
        "datamart_id": "1509",
        "status": "LIVE",
        "creation_date": 1603198414771,
        "last_modification_date": 1603198415117,
        "publication_date": 1603198415733,
        "suspension_date": null
    }
            
    // ARCHIVED Schema
    {
        "id": "1276",
        "datamart_id": "1509",
        "status": "ARCHIVED",
        "creation_date": 1603102827888,
        "last_modification_date": 1603102828087,
        "publication_date": 1603102828479,
        "suspension_date": 1603102848269
    }

    Schema publication workflow

    The process for publishing a schema is as follows:

    1. Create a new schema definition

    2. Upload the schema associated with the definition

    3. Validate the schema

    4. Publish the schema

    After updating a schema, you can immediately use all its properties into the select part of your and any operator that doesn't require indexing.

    If you add a new indexed property, only new elements going into your datamart will be indexed. You will be able to run WHERE queries and operators needing indexing, but your queries will not return values for elements already in your datamart. You can add a new indexed property by either adding a new property with or adding the @TreeIndex directive to an existing property.

    If you remove an indexed property, you will instantly stop being able to run WHERE queries and operators needing indexing for this query.

    You can use the to power up your schema definitions workflow.

    Retrieve the LIVE schema or the specified one for a given datamart, and save it as a .gql file named schema-<DATAMARTID>-<SCHEMAID>.gql.

    Use it to download the schema you want to start with, usually the current LIVE version.

    If you want to show the schema in the output, use the --stdout flag.

    Create a draft, upload a file, validate it, and publish the schema with this all-in-one command.

    Automatically handles status and :

    • If a draft schema already exists, update it before publishing.

    • Latest LIVE schema is cloned, if available, and --noClone flag is not set

    You can keep your schema as a DRAFT and not publish it using the --skipPublishflag.

    GET https://api.mediarithmics.com/v1/datamarts/:datamartId/graphdb_runtime_schemas

    Returns all schemas and their status.

    Name
    Type
    Description

    GET https://api.mediarithmics.com/v1/datamarts/:datamartId/graphdb_runtime_schemas/:schemaId

    Name
    Type
    Description

    GET https://api.mediarithmics.com/v1/datamarts/:datamartId/graphdb_runtime_schemas/:schemaId/text

    Allows you to visualize how your schema is in the current version, or how it has been in archived versions

    Name
    Type
    Description

    POST https://api.mediarithmics.com/v1/datamarts/:datamartId/graphdb_runtime_schemas/:schemaId/clone

    Creates a new DRAFT schema if there's no existing one, by cloning an existing one.

    Name
    Type
    Description

    POST https://api.mediarithmics.com/v1/datamarts/:datamartId/graphdb_runtime_schemas

    Creates a new DRAFT schema if there's no existing one without cloning.

    Name
    Type
    Description

    PUT https://api.mediarithmics.com/v1/datamarts/:datamartId/graphdb_runtime_schemas/:schemaId/text

    Add the schema to content to the raw body of the request

    Name
    Type
    Description
    Name
    Type
    Description

    POST https://api.mediarithmics.com/v1/datamarts/:datamartId/graphdb_runtime_schemas/:schemaId/validation

    Tells you if the uploaded schema is valid, and shows errors if there are any.

    Name
    Type
    Description

    POST https://api.mediarithmics.com/v1/datamarts/:datamartId/graphdb_runtime_schemas/:schemaId/publication

    The selected schema goes LIVE, and the actual LIVE schema is ARCHIVED. Will show an error if you didn't validate the schema.

    Name
    Type
    Description

    Ads exposure tracking

    You can track the exposition of users to the different kind of Ads format that exist today:

    • Display Ads: All Ads that are either static image/animations or HTML5 animated Ads

    • Video Ads: All Video Ads that the User can see through a marketing campaign

    All Ads tracking is done using Pixels and Click Tracking URLs

    Activities analytics

    Data coming into your datamart is stored in a multi-model database, optimizing it for different usages. To display performance analytics for elements like session duration, conversions, and funnel, the platform duplicates some and information and optimizes them.

    Here is a sample event that can be used in analytics:

    The list of predefined events that are used in analytics are as follows.

    Charts

    Transformations

    Key / value / buckets

    Queries

    • queries with multiple dimensions

    • queries with multiple dimensions

    Charts

    Transformations

    Key / values

    Queries

    None

    Transformations

    Charts

    Transformations

    On builders scopes, the current query selected in the builder is added at the end of the OTQL query. That means that only OTQL queries FROM UserPoint will adapt to the scope.

    Single number

    Queries

    • OTQL @count and metrics directives

    • Activities analytics without dimensions

    • Collection volumes without dimensions

    Transformations

    None

    Charts

    Metric

    Transformations

    ratio to-list

    Key / value

    "dataset": {
        "type": "OTQL",
        "query_id": 666 // SELECT @count FROM UserPoint
    }
    "dataset": {
        "type": "activities_analytics",
        "query_json":  { // This query returns the number of active users
            "dimensions": [],
            "metrics": [
                {
                    "expression": "users"
                }
            ]
        }
    }
    // key-value dataset built with an OTQL query
    "dataset": {
        "type": "OTQL",
        "query_id": 666 // SELECT {gender @map} FROM UserProfile
    }
    
    // key-value dataset built with an activities analytics query
    "dataset": {
        "type": "activities_analytics",
        "query_json":  { // This query returns the number of active users per channel
            "dimensions": [
                {"name": "channel_id"}
            ],
            "metrics": [
                {
                    "expression": "users"
                }
            ]
        }
    }
    "dataset": {
        "type": "to-list",
        "sources": [
            {
                "type": "OTQL",
                "query_id": "666",
                "series_title": "Female"
            },
            {
                "type": "OTQL",
                "query_id": "777",
                "series_title": "Male"
            }
        ]
    }
    // key-value dataset built with an OTQL query
    "dataset": {
        "type": "OTQL",
        "query_id": 666 // SELECT {cat1 @map{cat2 @map{cat3 @map}}} FROM UserProfile
    }
    
    // key-value dataset built with an activities analytics query
    "dataset": {
        "type": "activities_analytics",
        "query_json":  { // Number of active users per day per channel
            "dimensions": [
                {"name": "date_yyyymmdd"}
                {"name": "channel_id"}
            ],
            "metrics": [
                {
                    "expression": "users"
                }
            ]
        }
    }
    "dataset": {
        "type": "join",
        "sources": [
            {
                "type": "OTQL",
                "query_id": 777, // Select {interests @map} FROM UserPoint WHERE ...
                "series_title": "Group 1" 
            },
            {
                "type": "OTQL",
                "query_id": 666, // Select {interests @map} FROM UserPoint WHERE...
                "series_title": "Group 2"
            }
        ]
    }
    "dataset": {
        "type": "transformation-name",
        "sources": [
            { 
                "type": "transformation-name",
                "sources": [
                    {
                        // OTQL data source
                        "type": "OTQL", 
                        // ID of the OTQL query to call
                        "query_id": Int, 
                        // Optional. Title of the series for tooltips and legends
                        "series_title": String, 
                        // Optional. Datamart on which to run the query.
                        // Defaults to current datamart
                        "datamart_id": Int,
                        // Optional. To adapt the query to the current scope
                        // for example by adding current segment's query
                        // when dashboard is executed on a segment
                        // Defaults to TRUE
                        // COMING SOON
                        "adapt_to_scope": Boolean
                        // Optional. To run the query in a specific precision
                        // To be used when charts take too long to load and 
                        // a lower precision is accepted
                        // Defaults to FULL_PRECISION
                        "precision": "FULL_PRECISION" | "LOWER_PRECISION" | "MEDIUM_PRECISION"
                    }
                ]
            },
            {
                "type": "activities_analytics",
                 // JSON representation of the activities analytics query
                "query_json": Object, 
                // Optional. Title of the series for tooltips and legends
                "series_title": String, 
                // Optional. Datamart on which to run the query.
                // Defaults to current datamart
                "datamart_id": Int,
                // Optional. To adapt the query to the current scope
                // for example by only selecting activities of users 
                // that were in the segment while doing it
                // when dashboard is executed on a segment
                // Defaults to TRUE
                // COMING SOON
                "adapt_to_scope": Boolean
            },
            {
                "type": "collection_volumes",
                 // JSON representation of the activities analytics query
                "query_json": Object, 
                // Optional. Title of the series for tooltips and legends
                "series_title": String 
            },
            {
                "type": "resources_usage",
                 // JSON representation of the activities analytics query
                "query_json": Object, 
                // Optional. Title of the series for tooltips and legends
                "series_title": String 
            },
            {
                "type": "data_ingestion",
                 // JSON representation of the activities analytics query
                "query_json": Object, 
                // Optional. Title of the series for tooltips and legends
                "series_title": String 
            },
            {
                "type": "data_file",
                // URI of the JSON data file containing data
                // Format "mics://data_file/tenants/1426/dashboard-1.json"
                "uri": String,
                // Path of the property in the JSON that should be used as dataset
                // This allows you to have multiple datasets in the same JSON file
                // Should use the JSONPath syntax. See https://jsonpath.com/
                // For example, "$[0].components[1].component.data"
                "JSON_path": String,
                // Optional. Title of the series for tooltips and legends
                "series_title": String
          }
        ]
    }
    "dataset": {
        "type": "join",
        "sources": [
            {
                "type": "OTQL",
                "query_id": 777, // Select {interests @map} FROM UserPoint WHERE ...
                "series_title": "Segment" 
            },
            {
                "type": "OTQL",
                "query_id": 666, // Select {interests @map} FROM UserPoint WHERE...
                "series_title": "Datamart",
                "adapt_to_scope": false
            }
        ]
    }

    Single number datasets

    Key / value datasets

    Key / value / buckets datasets

    Key / values datasets

    Dataset JSON declaration

    • To learn about OTQL queries, go to OTQL queries.

    • To learn about activities analytics queries, go to Activities analytics queries.

    • To learn about collection volumes queries, go to .

    • For a list of available transformations, see .

    series_title property

    datamart_id property

    adapt_to_scope property

    If the dashboard is meant to be displayed on segments, only build OTQL queries FROM UserPoint and activities analytics queries unless you want to retrieve data for the whole datamart.

    If the dashboard is meant to be displayed on builders, only build OTQL queries FROM UserPoint unless you want to retrieve data for the whole datamart.

    Collection volumes
    Resources usage
    Events ingestion monitoring
    OTQL
    activities analytics
    Metric
    OTQL bucket directives
    activities analytics dimensions
    Bars
    Pie
    Radar
    multi-level bucket directives
    activities analytics queries with multiple dimensions
    Bars
    Pie
    Bars
    Radar

    Queries

    • queries with dimensions

    • queries with dimensions

    .

    There are two predefined user events that should be tracked during the exposition of a user to an Ad :

    Event name
    Tracking method
    Description

    $ad_view

    Pixel

    The 'view/impression' of the Display Ad to the User

    $ad_click

    Use the following URL in your tracking pixel to send an $ad_view event to the platform.

    Field
    Type
    Description

    $ev

    String

    The event name. $ad_view for Display Ad impression tracking

    $dat_token

    String

    Use the following click-tracking URL to send an $ad_click event to the platform.

    Field
    Type
    Description

    $ev

    String

    The event name. $ad_click for Display Ad click tracking

    $dat_token

    String

    You can use the following macros as a minimum configuration for tracking on DV 360 (ex-Doubleclick Bid Manager):

    You can use the following macros as a minimum configuration for tracking on Campaign Manager 360 (ex-Doubleclick Campaign Manager):

    You can use the following macros as a minimum configuration for tracking on Ad Manager:

    You can use the following macros as a minimum configuration for tracking on Xandr:

    You can use the following macros as a minimum configuration for tracking on The Trade Desk:

    You can track additional properties by using custom properties such as:

    Basic video ad tracking can be achieved by integrating the display ad pixel (with $ad_view events) and the click-tracking URL (with $ad_click events) into your video ad format.

    For more advanced capabilities, a specific integration can be setup based on the visit pixel (with custom completion events) and an Activity Analyzer. Please advise with your Account Representatives during the design phase.

    The following is true for all types of pixel-based tracking (events, ads, email, conversions, ...) which use the events.mediarithmics.com/v1/touches/pixel API endpoint

    You can pass one or more user identifiers when using the $uids field.

    Field
    Type
    Description

    $tpe

    Constant String

    AC

    $ctok

    String

    Field
    Type
    Description

    $tpe

    Constant String

    EM

    $eh

    String

    Field
    Type
    Description

    $tpe

    Constant String

    AG

    $agid

    String

    https://events.mediarithmics.com/v1/touches/pixel? \
    	$ev=$ad_view& \
    	$dat_token=<DATAMART_TOKEN>&
    	$catn=<CAMPAIGN_TECHNICAL_NAME>&
    	$scatn=<AD_GROUP_TECHNICAL_NAME>&
    	$crtn=<CREATIVE_TECHNICAL_NAME>&
    	$cb=<CACHEBUSTER>&
    	gdpr=<GDPR>&
    	gdpr_consent=<GDPR_CONSENT_184>
    	... any custom property
    https://events.mediarithmics.com/v1/touches/click?
    	$ev=$ad_click&
    	$dat_token=<DATAMART_TOKEN>&
    	$catn=<CAMPAIGN_TECHNICAL_NAME>&
    	$scatn=<AD_GROUP_TECHNICAL_NAME>&
    	$crtn=<CREATIVE_TECHNICAL_NAME>&
    	$cb=<CACHEBUSTER>&
    	$redirect=<CLICK_URL>&
    	gdpr=<GDPR>&
    	gdpr_consent=<GDPR_CONSENT_184>
    	... any custom property
    https://events.mediarithmics.com/v1/touches/pixel?
    	$ev=$ad_view&
    	$dat_token=<DATAMART_TOKEN>&
    	$catn=${CAMPAIGN_ID}&
    	$scatn=${INSERTION_ORDER_ID}&
    	$crtn=${CREATIVE_ID}&
    	gdpr=${GDPR}&
    	gdpr_consent=${GDPR_CONSENT_184}&
    	$cb=${CACHEBUSTER}
    https://events.mediarithmics.com/v1/touches/click?
    	$ev=$ad_click&
    	$dat_token=<DATAMART_TOKEN>&
    	$catn=${CAMPAIGN_ID}&
    	$scatn=${INSERTION_ORDER_ID}&
    	$crtn=${CREATIVE_ID}&
    	gdpr=${GDPR}&
    	gdpr_consent=${GDPR_CONSENT_184}&
    	$cb=${CACHEBUSTER}&
    	$redirect=${CLICK_URL_ENC}
    https://events.mediarithmics.com/v1/touches/pixel?
    	$ev=$ad_view&
    	$dat_token=<DATAMART_TOKEN>&
    	$catn=%ebuy!&
    	$scatn=%eaid!&
    	$crtn=%ecid!&
    	gdpr=${GDPR}&
    	gdpr_consent=${GDPR_CONSENT_184}&
    	$cb=%n
    https://events.mediarithmics.com/v1/touches/click?
    	$ev=$ad_click&
    	$dat_token=<DATAMART_TOKEN>&
    	$catn=%ebuy!&
    	$scatn=%eaid!&
    	$crtn=%ecid!&
    	gdpr=${GDPR}&
    	gdpr_consent=${GDPR_CONSENT_184}&
    	$cb=%n&
    	$redirect=<CLICK_URL>
    https://events.mediarithmics.com/v1/touches/pixel?
    	$ev=$ad_view&
    	$dat_token=<DATAMART_TOKEN>&
    	$catn=%ebuy!&
    	$scatn=%eaid!&
    	$crtn=%ecid!&
    	gdpr=${GDPR}&
    	gdpr_consent=${GDPR_CONSENT_184}&
    	$cb=%%CACHEBUSTER%%
    https://events.mediarithmics.com/v1/touches/click?
    	$ev=$ad_click&
    	$dat_token=<DATAMART_TOKEN>&
    	$catn=%ebuy!&
    	$scatn=%eaid!&
    	$crtn=%ecid!&
    	gdpr=${GDPR}&
    	gdpr_consent=${GDPR_CONSENT_184}&
    	$cb=%%CACHEBUSTER%%&
    	$redirect=<CLICK_URL>
    https://events.mediarithmics.com/v1/touches/pixel?
    	$ev=$ad_view&
    	$dat_token=<DATAMART_TOKEN>&
    	$catn=${CP_CODE}&
    	$scatn=${CPG_CODE}&
    	$crtn=${CREATIVE_CODE}&
    	gdpr=${GDPR}&
    	gdpr_consent=${GDPR_CONSENT_184}&
    	$cb=${CACHEBUSTER}
    https://events.mediarithmics.com/v1/touches/click?
    	$ev=$ad_click&
    	$dat_token=<DATAMART_TOKEN>&
      	$catn=${CP_CODE}&
    	$scatn=${CPG_CODE}&
    	$crtn=${CREATIVE_CODE}&
    	$cb=${CACHEBUSTER}&
    	gdpr=${GDPR}&
    	gdpr_consent=${GDPR_CONSENT_184}&
    	$redirect=${CLICK_URL_ENC}
    https://events.mediarithmics.com/v1/touches/pixel?
    	$ev=$ad_view&
    	$dat_token=<DATAMART_TOKEN>&
    	$catn=%%TTD_CAMPAIGNID%%&
    	$scatn=%%TTD_ADGROUPID%%&
    	$crtn=%%TTD_CREATIVEID%%&
    	$cb=%%TTD_CACHEBUSTER%%&
    	gdpr=${GDPR}&
    	gdpr_consent=${GDPR_CONSENT_184}
    https://events.mediarithmics.com/v1/touches/click?
    	$ev=$ad_click&
    	$dat_token=<DATAMART_TOKEN>&
      	$catn=%%TTD_CAMPAIGNID%%&
    	$scatn=%%TTD_ADGROUPID%%&
    	$crtn=%%TTD_CREATIVEID%%&
    	$cb=%%TTD_CACHEBUSTER%%&
    	gdpr=${GDPR}&
    	gdpr_consent=${GDPR_CONSENT_184}&
    	$redirect=%%TTD_CLK_ESC%%
    ...
    domain=%%TTD_SITE%%&
    device=%%TTD_DEVICETYPE%%&
    ...
    https://events.mediarithmics.com/v1/touches/pixel? \
    	$ev=$ad_view& \
    	$dat_token=<DATAMART_TOKEN>&
    	$catn=<CAMPAIGN_TECHNICAL_NAME>&
    	$scatn=<AD_GROUP_TECHNICAL_NAME>&
    	$crtn=<CREATIVE_TECHNICAL_NAME>&
    	gdpr=<GDPR>&
    	gdpr_consent=<GDPR_CONSENT>&
    	$cb=<CACHEBUSTER>&
    	$uids=jso-[{"$tpe":"AG","$agid":"vec:1234"}]&
    	... any custom property

    You should consider using this feature to get ad view and ad click directly within your datamart when using DSPs .

    Activities tracked through this method will be of DISPLAY_AD $type and NO_SESSION $session_status. See for more information.

    Associated user events

    Display Ad Pixel

    Please note that before declaring a custom property, we recommend that you inform our PS team so that it can be indexed to your data schema (and therefore used for segmentation and/or dataviz), see our .

    Ad Click tracking URL

    If you want to integrate with an external DSP / Ad Server such as Google Ad Manager or App Nexus, you can use the ids of the creative ad groups and campaign from your external DSP as technical names. See the integrations below for examples.

    Campaign tracking on Google

    Display Video 360

    More info on DV360 macros available here:

    Campaign Manager 360 integration

    More info on Google Campaign Manager 360 macros can be found here:

    And for TCF integration:

    Ad Manager integration

    More info on Google Ad Manager macros can be found here:

    Campaign tracking on Xandr

    More info on Xandr supported macros can be found here:

    Campaign tracking on The Trade Desk

    More info on The Trade Desk supported macros can be found here (a The Trade Desk account is requiered to access this page):

    Please note that before declaring a custom property, we recommend that you inform our PS team so that it can be indexed to your data schema (and therefore used for segmentation and/or dataviz), see our .

    Video Ad Tracking

    Passing user identifiers in pixel-based tracking

    jso- prefix means that the rest of the string will be interpreted as a json object.

    Don't forget to correctly encode the URL

    User Account

    User Email

    User Agent

    Use the registry token, not the id, when formatting the user agent id.

    Eg: dev:<registry_token>:<value>

    Important properties

    $transaction_confirmed

    Home dashboards (E-Commerce Engagement)

    Segment dashboards (E-Commerce Engagement)

    Funnel Analytics

    $items : list of products in the transaction

    $items.$qty : for the conversion amounts

    $items.$price: for the conversion amounts

    $items.$id : for the product IDs in funnel analytics

    $items.$brand: for the brand filter in funnel analytics

    $item_view

    Funnel Analytics

    $items : contains only one product

    $items.$price: for the conversion amounts

    $items.$id : for the product IDs in funnel analytics

    $items.$brand: for the brand filter in funnel analytics

    $items.$category1, $items.$category2

    $basket_view

    Funnel Analytics

    $items : list of products in the basket

    $items.$qty : for the conversion amounts

    $items.$price: for the conversion amounts

    $items.$id : for the product IDs in funnel analytics

    $items.$brand: for the brand filter in funnel analytics

    Activities analytics data is kept 4 month in order to optimize performances.

    While it is better to use predefined events when possible, it isn't always the best solution for you. To keep having analytics correctly stored, you can transform your custom events to predefined ones.

    An event transformation is linked to a datamart. Here is a sample transformation:

    Property

    Type

    Description

    datamart_id

    Integer

    The ID of the datamart where the transformation is applied

    channel_id

    Event transformations use property mappings to choose which property in your custom event becomes which property in the predefined event.

    Here is a sample property mapping to start with for $transaction_confirmed events.

    GET https://api.mediarithmics.com/v1/datamarts/:datamartId/analytics_event_transformation

    Name
    Type
    Description

    datamartId

    integer

    The datamart ID

    {
        "status": "ok",
        "data": [
            {
              "datamart_id": ":datamartId",
              "channel_id": "8888",
              "source_event_name": "order",
              "target_event_name": "$transaction_confirmed",
              "mapping_id": xxx
            },
            {
                ...
            }
        ]
    }

    POST https://api.mediarithmics.com/v1/datamarts/:datamartId/analytics_event_transformation

    Name
    Type
    Description

    datamartId

    integer

    The datamart ID

    Name
    Type
    Description

    Body

    string

    The event transformation object

    PUT https://api.mediarithmics.com/v1/datamarts/:datamartId/analytics_event_transformation/:transformationId

    Name
    Type
    Description

    transformationId

    integer

    The transformation ID

    datamartId

    integer

    The datamart ID

    Name
    Type
    Description

    Body

    string

    The event transformation object

    DELETE https://api.mediarithmics.com/v1/datamarts/:datamartId/analytics_event_transformation/:transformationId

    Name
    Type
    Description

    transformationId

    integer

    The transformation ID

    datamartId

    integer

    The datamart ID

    GET https://api.mediarithmics.com/v1/datamarts/:datamartId/analytics_mapping

    Name
    Type
    Description

    datamartId

    integer

    The datamart ID

    POST https://api.mediarithmics.com/v1/datamarts/:datamartId/analytics_mapping

    Name
    Type
    Description

    datamartId

    integer

    The datamart ID

    Name
    Type
    Description

    Body

    object

    The property mapping object

    {
      "status": "ok",
      "data": {
          id: 17,
          created_by: <>
          ...
      }
    }

    DELETE https://api.mediarithmics.com/v1/datamarts/:datamartId/analytics_mapping/:mappingId

    Name
    Type
    Description

    mappingId

    integer

    The mapping ID

    datamartId

    integer

    The datamart ID

    {
        "status": "ok"
    }
    {
        "status": "error",
        "error": "Deleting a property mapping used in a transformation is forbidden",
        "error_code": "BAD_REQUEST_DATA",
        "error_id": "9460be23-0f80-4acb-9a33-dd8a1c5d08a9"
    }
    {
        "$ts": 3489009384393,
        "$event_name": "$transaction_confirmed", // Conversion detected
        "$properties": {
            "$items": [
                {
                     "$id": "product_ID", // Used to filter in funnel analytics
                     "$qty": 20, // Used for conversion amounts
                     "$price": 102.8, // Used or conversion amounts
                     "$brand": "Apple" // Used to filter in funnel analytics
                     "$category1": "Category 1", // Used to filter in funnel analytics
                     "$category2": "Category 2", // Used to filter in funnel analytics
                     "$category3": "Category 3", // Used to filter in funnel analytics
                     "$category4": "Category 4" // Used to filter in funnel analytics
                 },
                 {
                     "$id": "product_ID2",
                     "$qty": 12,
                     "$price": 3.4,
                     "$brand": "Microsoft"
                 }
            ],
            "$currency": "EUR"
        }
    }

    Event name

    For that purpose, it is important that you use predefined event names and properties when possible. Custom events won't be taken into account when calculating metrics. For example, don't create order events when tracking an e-commerce site, but the predefined $transaction_confirmed event. $transaction_confirmed events are used when calculating conversions and amounts but not order events.

    user activities

    Usage

    {
        "id": 15, // Read only
        "datamart_id": "3333", // Read only
        "created_ts": <>, // Read only
        "created_by": <>, // Read only
        "last_modified_by": <>, // Read only
        "last_modified_ts": <>, // Read only
    
        "channel_id": "8888",
        "source_event_name": "order",
        "target_event_name": "$transaction_confirmed",
        "mapping_id": 15
    }
    // Comments are here to help you understand, 
    // remove them before uploading mappings as they are not accepted in JSON
    {
      "id": 17, // Read only
      "created_by": <>, // Read only
      "created_ts": <>, // Read only
      "mapping": {
        "values": [
          {
              // Maps $properties.order.order_products[] to $items[]
               "target_attribute_name": "$items",
               "source_attribute_path": {
                   "attribute_name": "$properties",
                   "sub_path": {
                       "attribute_name": "order",
                       "sub_path": {
                            "attribute_name": "order_products"
                       }
                   }
               },
               // Alternative : mapping directly $properties if there are no multiple
               // elements in the event. It will be treated as an array of only one item
               "target_attribute_name": "$items",
               "source_attribute_path": {
                    "attribute_name": "$properties"
               },
               
               // Maps $properties.order.order_products.xxx to $items.xxx
               // You can't use other target attributes than the ones 
               // in this example.
               // But they are not all mandatory : a non used target 
               // attribute will use the default value
               "children": [
                   // $properties.order.order_products.product.id
                   // becomes $items.$id
                   // to be used by analytics database
                   {
                       "target_attribute_name": "$id",
                       "source_attribute_path": {
                         "attribute_name": "product",
                         "sub_path": {
                            "attribute_name": "id"
                         }
                       }
                   },
                   // $properties.order.order_products.qty
                   // becomes $items.$qty
                   // to be used by analytics database
                   {
                       "target_attribute_name": "$qty",
                       "source_attribute_path": {
                         "attribute_name": "qty"
                       }
                   },
                   {
                       "target_attribute_name": "$price",
                       "source_attribute_path": {
                         "attribute_name": "price"
                       }
                   },
                   {
                       "target_attribute_name": "$ean",
                       "source_attribute_path": {
                         "attribute_name": "ean",
                       }
                   },
                   {
                       "target_attribute_name": "$brand",
                       "source_attribute_path": {
                         "attribute_name": "brand",
                       }
                   },
                   {
                       "target_attribute_name": "$category1",
                       "source_attribute_path": {
                         "attribute_name": "cat1"
                       }
                   },
                   {
                       // In this example $category2 will be 
                       // event.$event_name instead of 
                       // $properties.order.order_products[].$event_name
                       // thanks to absolute_path
                       "target_attribute_name": "$category2",
                       "source_attribute_path": {
                         "absolute_path": true,
                         "attribute_name": "$event_name",
                       }
                   },
                   {
                       "target_attribute_name": "$category3",
                       "source_attribute_path": {
                         "attribute_name": "cat3"
                       }
                   },
                    {
                       "target_attribute_name": "$category4",
                       "source_attribute_path": {
                         "attribute_name": "cat4"
                       }
                   }
               ]
           }
        ]
      }
    }

    Activities analytics data retention

    Transforming important events into your custom events

    Only events coming into the datamart after an event transformation has been defined will be transformed.

    Those transformations don't transform user activities and events anywhere else. You should use to transform them everywhere.

    Event transformations

    Property mappings

    Map events JSON as it is stored in the database and visible in user's timelines (post ).

    Get existing transformations

    Path Parameters

    Create an event transformation

    Path Parameters

    Request Body

    Update an event transformation

    Path Parameters

    Request Body

    Remove an event transformation

    Path Parameters

    Get property mappings

    Path Parameters

    Create property mappings

    Path Parameters

    Request Body

    Delete property mappings

    Path Parameters

    USAGE
      $ mics-cli schema:fetch DATAMARTID [SCHEMAID]
    
    ARGUMENTS
      DATAMARTID  the ID of the datamart
      SCHEMAID    [default: LIVE] the ID of the schema, or LIVE to get the live schema
    
    OPTIONS
      --stdout  output the content of the file instead of saving it in a file

    datamartId

    integer

    The ID of the datamart

    {
        "status": "ok",
        "data": [
            {
                "id": "1266",
                "datamart_id": "1509",
                "status": "ARCHIVED",
                "creation_date": 1602860201358,
                "last_modification_date": 1602860221562,
                "publication_date": 1602860275189,
                "suspension_date": 1602860362588
            },
            {
                "id": "1281",
                "datamart_id": "1509",
                "status": "LIVE",
                "creation_date": 1603198414771,
                "last_modification_date": 1603198415117,
                "publication_date": 1603198415733,
                "suspension_date": null
            },
            {
                "id": "1385",
                "datamart_id": "1509",
                "status": "DRAFT",
                "creation_date": 1609888013947,
                "last_modification_date": 1610443926552,
                "publication_date": null,
                "suspension_date": null
            }
        ],
        "count": 3,
        "total": 3,
        "first_result": 0,
        "max_result": 2147483647,
        "max_results": 2147483647
    }

    datamartId

    integer

    The ID of the datamart

    schemaId

    integer

    The ID of the schema

    {
        "status": "ok",
        "data": {
            "id": "1266",
            "datamart_id": "1509",
            "status": "ARCHIVED",
            "creation_date": 1602860201358,
            "last_modification_date": 1602860221562,
            "publication_date": 1602860275189,
            "suspension_date": 1602860362588
        }
    }

    datamartId

    string

    The ID of the datamart

    schemaId

    integer

    The ID of the schema

    ##
    
    
    type UserPoint  @TreeIndexRoot(index:"USER_INDEX") {
       events:[ActivityEvent!]!
       creation_ts:Timestamp! @TreeIndex(index:"USER_INDEX")
       id:ID!
    }
    
    ##
    
    
    type ActivityEvent  {
       referrer:String @TreeIndex(index:"USER_INDEX") @Property(path:"$properties.$referrer")
       url:String @TreeIndex(index:"USER_INDEX") @Property(path:"$properties.$url")
       date:Date! @TreeIndex(index:"USER_INDEX") @Function(params:["ts"], name:"ISODate")
       nature:String @Property(path:"$event_name") @TreeIndex(index:"USER_INDEX")
       ts:Timestamp!
       id:ID!
    }
    
    

    schemaId

    integer

    The ID of the schema to clone. Usually the current LIVE version.

    datamartId

    integer

    The ID of the datamart

    {
        "status": "ok",
        "data": {
            "id": "1395",
            "datamart_id": "1509",
            "status": "DRAFT",
            "creation_date": 1610449867207,
            "last_modification_date": 1610449867207,
            "publication_date": null,
            "suspension_date": null
        }
    }
    {
        "status": "error",
        "error": "Impossible to create a new schema, there is already one draft schema",
        "error_code": "CONSTRAINT_VIOLATION_EXCEPTION",
        "error_id": "690596a9-b0e0-43b3-88e8-b90d08b98029"
    }

    datamartId

    integer

    The ID of the datamart

    {
        "status": "ok",
        "data": {
            "id": "1395",
            "datamart_id": "1509",
            "status": "DRAFT",
            "creation_date": 1610449867207,
            "last_modification_date": 1610449867207,
            "publication_date": null,
            "suspension_date": null
        }
    }
    {
        "status": "error",
        "error": "Impossible to create a new schema, there is already one draft schema",
        "error_code": "CONSTRAINT_VIOLATION_EXCEPTION",
        "error_id": "690596a9-b0e0-43b3-88e8-b90d08b98029"
    }

    datamartId

    integer

    The ID of the datamart

    schemaId

    integer

    The ID of the schema

    body

    string

    Raw schema to upload

    {
        "status": "ok"
    }

    datamartId

    integer

    The ID of the datamart

    schemaId

    integer

    The ID of the schema

    {
        "status": "ok",
        "data": {
            "datamart_id": "1509",
            "schema_id": "1266",
            "tree_index_operations": [
                {
                    "datamart_id": "1509",
                    "index_selection_id": "2121",
                    "index_name": "USER_INDEX",
                    "init_strategy": "FORCE_NO_BUILD",
                    "driver_version_major_number": 1,
                    "driver_version_minor_number": 2,
                    "current_index_id": "574",
                    "current_index_size": "SMALL",
                    "new_index": false,
                    "new_index_size": "SMALL",
                    "init_job": null,
                    "error_code": null,
                    "error_message": null
                }
            ],
            "schema_errors": []
        }
    }
    {
        "status": "error",
        "error": "2 error(s) found when validating schema : Type 'UserPoint' which is root of tree index 'USER_INDEX' requires a scalar field named 'creation_ts' to be annotated with '@TreeIndex(index:\"USER_INDEX\")' and to be typed 'Timestamp!', Type 'UserAccount' which is root of tree index 'USER_INDEX' requires a scalar field named 'compartment_id' to be annotated with '@TreeIndex(index:\"USER_INDEX\")' and to be typed 'String!'",
        "error_code": "BAD_REQUEST_DATA",
        "error_id": "6a52cea9-6de4-40f5-972e-a8480c268d19"
    }

    datamartId

    integer

    The ID of the datamart

    schemaId

    integer

    The ID of the datamart

    {
        "status": "ok",
        "data": {
            "datamart_id": "1509",
            "schema_id": "1395",
            "tree_indices": [
                {
                    "index_name": "USER_INDEX",
                    "new_index": false,
                    "index_id": "574",
                    "index_size": "SMALL",
                    "init_strategy": "FORCE_NO_BUILD",
                    "driver_version_major_number": 1,
                    "driver_version_minor_number": 2,
                    "init_job": null
                }
            ]
        }
    }
    {
        "status": "error",
        "error": "Impossible to publish schema, validate the schema before a new publication",
        "error_code": "BAD_REQUEST_DATA",
        "error_id": "76e70020-02cb-40ec-8109-adf204aa0a7b"
    }

    Schema updates

    You can ask your mediarithmics contact to start a complete reindexing of your datamart if required

    Manage schemas with mics CLI

    Download a schema

    Update a schema

    Get existing schemas

    Path Parameters

    Archived schemas are displayed, meaning you can watch your history

    Get a schema

    Path Parameters

    Get the content of a schema

    Path Parameters

    Create a DRAFT by cloning

    Path Parameters

    This is the preferred method to create a DRAFT schema, as it will keep all settings from the previous version, like cluster versions, and index sizes.

    Create a DRAFT without cloning

    Path Parameters

    For the schema to keep initial settings—for example, elastic search version, and index size—you need to clone the previous LIVE version. Only use this endpoint if you know the required settings and you can set them up before publishing.

    Upload the content

    Path Parameters

    Request Body

    Validate a DRAFT schema

    Path Parameters

    Publish a schema

    Path Parameters

    OTQL queries
    @TreeIndex directive
    MICS CLI
    cloning best practices
    schema's concepts and how they are structured

    Website tracking

    The mediarithmics is used to track the visitor's navigation on a website. It is imported in a JavaScript snippet that needs to be executed on all the pages you wish to track.

    The code of the Visit Tracking snippet is non-blocking—it does not impact on the page rendering time. The snippet can be inserted in the <head> part of the web page.

    You can use the snippet to track in real-time, what your users are doing on your website. If you want to track users from your backend, please consider using our API. If you want to import bulk events or activities, please consider using the feature.

    The mediarithmics tracking snippet is made of two parts:

    Audience features

    Let's take the following query as an example:

    It is technically an OTQL query based on your schema in which you registered parameters. In this case, it represents a business feature that may be used regularly by your users: selecting UserPoint that perform a transaction in a particular date range and for specific products.

    Users will see this selector in the builder instead of an OTQL query.

    This audience feature will automatically be combined with other audience features, which the user can select to create segments.

    Users will have access to the standard segment builder if at least one audience feature is set up. But you need multiple ones to create value for users.

    Click Tracking URL

    The 'click' of the Ad by the User

    The token (not the ID) of the datamart in the mediarithmics platform.

    $catn

    String

    Campaign technical name

    $scatn

    String

    Sub-campaign technical name

    $crtn

    String

    Creative technical name

    $cb

    String

    The cache buster parameter. It should contain a random string. optional

    $cuid

    String

    User account identifier of the user

    $uaid

    String

    Mobile identifier of the user to identify the User agent

    $email_hash

    String

    Email Hash identifier of the user

    $comp_token

    String

    Compartment token (not the ID)

    $uids

    JSON as string (Optional)

    The list of user identifiers of the user.

    gdpr

    Number

    TCF v2.2 parameter to indicate if gdpr applies or not (values: 1 or 0)

    gdpr_consent

    String

    TCF v2.2 parameter containing the encoded consent string

    any custom property name

    Any Type

    Any custom property. optional

    The id of the audience datamart in the mediarithmics platform.

    $redirect

    String

    The redirect url. This string should be URL Encoded. (RFC 3986)

    $catn

    String

    Campaign technical name

    $scatn

    String

    Sub-campaign technical name

    $crtn

    String

    Creative technical name

    $cb

    String

    The cache buster parameter. It should contain a random string. optional

    $cuid

    String

    User account ID identifier of the user

    $email_hash

    String

    Email Hash identifier of the user

    $comp_token

    String

    Compartment token (not the ID)

    $uids

    JSON as string (Optional)

    The list of user identifiers of the user.

    gdpr

    Number

    TCF v2.2 parameter to indicate if gdpr applies or not (values: 1 or 0)

    gdpr_consent

    String

    TCF v2.2 parameter containing the encoded consent string

    any custom property name

    Any Type

    Any custom property. optional

    The token of the compartment

    $acid

    String

    The user account id of the user

    The email hash

    $e

    String (Optional)

    The "raw" email

    The user agent id

    User activity object
    data model documentation
    https://support.google.com/displayvideo/answer/2789508
    https://support.google.com/campaignmanager/table/6096962
    https://support.google.com/campaignmanager/answer/10031693?hl=en
    https://support.google.com/admanager/answer/2376981
    https://learn.microsoft.com/fr-fr/xandr/monetize/supported-creative-macros
    https://desk.thetradedesk.com/knowledge-portal/en/faq-macros.html
    data model documentation
    user_agent_id
    user_agent_id

    Transformations

    to-list to-percentages index

    Transformations

    None

    Collection volumes
    Transformations
    OTQL bucket directives
    Activities analytics
    Collection volumes
    Pie
    Radar
    Bars
    to-percentages
    join
    index
    reduce
    OTQL multi-level bucket directives
    Activities analytics
    Collection volumes
    Pie
    Bars
    to-percentages
    reduce
    join
    Bars
    Radar
    reduce
    $items.$category1, $items.$category2, $items.$category3 and $items.$category4 : for the categorization in funnel analytics
    ,
    $items.$category3
    and
    $items.$category4
    : for the categorization in funnel analytics
    $items.$category1, $items.$category2, $items.$category3 and $items.$category4 : for the categorization in funnel analytics

    Integer

    The ID of the channel where the transformation is applied

    source_event_name

    String

    The name of your custom event you wish to transform into a predefined event

    target_event_name

    String

    The name of the predefined event it is transformed into. Allowed values are :

    • $transaction_confirmed

    • $item_view

    • $basket_view

    • $list_item_view

    To learn about predefined events, see

    mapping_id

    Integer

    The ID of the Property mapping to apply when transforming the event

    activity analyzers
    activity analyzers
    A technical tag which contains JavaScript code to asynchronously load the TAG in the page. This part should not be edited, except when customizing the TAG name (see below).
  • The configuration that you should fill according to your context (site token / event name / event properties / etc.)

  • Here is an example of the tracking snippet you should implement on every page.

    To implement multiple tags or customize the tag for your own needs, you can do the following. Here is an example of a tag called umbrella_corp.

    If you want to get your own domain name, to fully remove mediarithmics from your website, contact your technical support to get your own domain name.

    Here is a an example of the full transparent snippet implementation.

    You don't have to push data on page load. You can, for example, bind an event to a button-click.

    If you want to pass one or multiple identifiers for your user, you can leverage the addIdentifier(type: string, identifier: object) method for each identifier you want to pass

    Hereafter are the formats:

    • If type == "USER_ACCOUNT" then identifier object must have the following structure {$user_account_id: string}or {$user_account_id: string, $compartment_token: string}

    • If type == "USER_EMAIL" then identifier object must have the following structure {$email_hash: string}or {$email_hash: string, $email: string}

    • If type == "USER_AGENT" then identifier object must have the following structure {$user_agent_id: string}

    The main purpose of the job is to send the right events with the right properties. This ensures good usability of the data for the users.

    We provide out-of-the-box tracking that will generate a $page_view event. This is the behavior if you are using our snippet as is.

    If you need to trigger a custom event on a particular page, you can use the mics.push function to specify an event name and an object containing the event properties.

    In this example, we send the event named view my form with the property form subject set to auto trial :

    It is recommended to implement the mediarithmics snippet at several key places, with specific event names:

    • Home page $home_view

    • Category or search results page $item_list_view

    • Product page $item_view

    • Basket page $basket_view

    • Transaction confirmation page $transaction_confirmed

    A list of products should be associated with any event with the reserved property $items.

    When the user views a list of products in a category page or in a search results page. Only the first 3 items in the list should be declared.

    • The $id field corresponds to the product id.

    • The $id field corresponds to the product id.

    • The $id field corresponds to the product id.

    • The $price field should contain the product price without the currency

    • The $qty field should contain the quantity of this product in the basket

    • The $currency field is optional. If there is only one catalog, the catalog currency is used by default

    • The $id field corresponds to the product id. It should be the same id as the one used in the product feed

    • The $price field should contain the product price without the currency

    • The $qty field should contain the quantity of this product in the basket

    • The $transaction_id field should contain the ID of the transaction

    • The $currency field is optional. If there is only one catalog, the catalog currency is used by default

    If the user is identified, you can register updates to its profile from the JS Snippet. It is generally used in user profile pages of your site.

    Use a special event called $set_user_profile_properties . The properties and values associated with the event will be written as key-value pairs on the UserProfile . By default, the anonymous UserProfile associated with the default compartment of the datamart will be updated. By default, the property force_replace is set to false when sending an event $set_user_profile_properties .

    The following special properties are available to specify which UserProfile should be updated:

    Property
    Description

    $set_user_profile_comp_token

    (Optional) The compartment token representing the compartment in which the profile should be written. If not provided, this will be the default compartment.

    $set_user_profile_user_account_id

    (Optional) The user account id under which the profile should be written. If not provided, it is the anonymous profile.

    Example 1: Write the gender to the anonymous UserProfile of the default compartment.

    Example 2: Write the gender to the anonymous UserProfile of a given compartment.

    Example 3: Write the gender to the UserProfile identified by a User Account Id of a given compartment.

    Some behaviors for the JavaScript can be set server-side, in the same way as tag managers. These configurations can be found on the related channel in Navigator settings.

    Select the identifiers that will automatically be used by the JavaScript tag to identify devices. The possible options include:

    • mediarithmics first-party cookie

    • mediarithmics third-party cookie (vector ID)

    In addition, mediarithmics tag can automatically retrieve a user or device identifier from the following partners if you have previously integrated with them:

    • ID5

    • First ID

    • Utiq martechpass (mobile)

    This device identification method, also referred to as INSTALLATION_ID, can only be used for tracking on the specific website where it is dropped , and to a limited extent for first-party activation (acting as a PPID). As a result, it does not enable cross-site reconciliation or cross-site targeting.

    When you activate mediarithmics first-party cookie, a first-party cookie named mics_<custom_cookie_name> OR mics_<site_token> will be dropped in the user’s browser. Refer to Installation ID - First-party cookie generated by mediarithmics to learn more about the cookie value format.

    Enable this setting if you want the javascript tag to automatically consider any TCF-compliant CMP on the website before third-party cookie creation and cookie matchings.

    Select if you want the javascript tag to trigger cookie matchings with Google and Xandr. For other partners, please check with your support.

    By default, mediarithmics third-party cookie (vector ID) is not generated if the browser does not support matchings with Google and Xandr. Use this setting to force its generation even if these matchigns do not succeed.

    A One Tag approach in web tracking refers to a method of tracking website visitors and their behavior on a website using a single tracking code. The advantage of a one tag approach is that it is relatively simple to implement and maintain, as it only requires the use of a single tracking code on the website.

    The mediarithmics javascript tag can easily be used in a "one tag" approach by referencing the relevant variables in the browser Document Object Model.

    Here are several examples of a One Tag implementation with different tag management services.

    • By default, the mediarithmics tag already collects the url, the referrer, the user agent and the time. It is not necessary to provide these properties:

    • For Google Tag Manager, it is possible to collect all the relevant properties in the data layer:

    • For Commanders Act, all the properties are stored in the tc_vars variable:

    The two common ways to integrate the tag are:

    • Through a universal tag container like Google Tag Manager or another similar solution. The code snippet must be copied once in a new tag and the tag container service automatically inserts the code wherever it is needed.

    • By inserting the code snippet in a general purpose template (ex: header template for an e-shop) which is used in all the web site pages.

    Cookies used by the tag are considered as advertising cookies. You must obtain user consent before using it.

    Implementing the snippet

    JS tag
    Bulk Import
    <script type="text/javascript">
        /* YOU SHOULD NOT EDIT THIS PART */
        !function(t,e,a){"use strict";var i=t.scimhtiraidem||{};function s(t){var e=i[a]||{};i[a]=e,e[t]||(e[t]=function(){i._queue[a].push({method:t,args:Array.prototype.slice.apply(arguments)})})}t.googletag=t.googletag||{},t.googletag.cmd=t.googletag.cmd||[],t.googletag.cmd.push(function(){var e=t.localStorage.getItem("mics_sgmts"),a=JSON.parse(e),i=a||{};Object.keys(i).forEach(function(e){t.googletag.pubads().setTargeting("mics_"+e,i[e].map(String))})});var r="init call config push pushDefault addIdentifier addProperties addProperty onFinish onStart _reset".split(" ");i._queue=i._queue||{},i._names=i._names||[],i._names.push(a),i._queue[a]=i._queue[a]||[],i._startTime=(new Date).getTime(),i._snippetVersion="2.0";for(var o=0;o<r.length;o++)s(r[o]);t.scimhtiraidem=i,t[a]=i[a];var n=e.createElement("script");n.setAttribute("type","text/javascript"),n.setAttribute("src","https://static.mediarithmics.com/tag/2/tag.min.js"),n.setAttribute("async","true"),e.getElementsByTagName("script")[0].parentNode.appendChild(n)}(window,document,"mics");
        
        mics.init("<SITE_TOKEN>");
    
        // Enables client-side feeds
        mics.call("syncFeeds");
        
        /* CUSTOMIZE THE TAG CALL BELOW */
        // remove next line to customize what you track
        mics.pushDefault();
    </script>
    <script type="text/javascript">
        /* YOU SHOULD NOT EDIT THIS PART */
        !function(t,e,a){"use strict";var i=t.scimhtiraidem||{};function s(t){var e=i[a]||{};i[a]=e,e[t]||(e[t]=function(){i._queue[a].push({method:t,args:Array.prototype.slice.apply(arguments)})})}t.googletag=t.googletag||{},t.googletag.cmd=t.googletag.cmd||[],t.googletag.cmd.push(function(){var e=t.localStorage.getItem("mics_sgmts"),a=JSON.parse(e),i=a||{};Object.keys(i).forEach(function(e){t.googletag.pubads().setTargeting("mics_"+e,i[e].map(String))})});var r="init call config push pushDefault addIdentifier addProperties addProperty onFinish onStart _reset".split(" ");i._queue=i._queue||{},i._names=i._names||[],i._names.push(a),i._queue[a]=i._queue[a]||[],i._startTime=(new Date).getTime(),i._snippetVersion="2.0";for(var o=0;o<r.length;o++)s(r[o]);t.scimhtiraidem=i,t[a]=i[a];var n=e.createElement("script");n.setAttribute("type","text/javascript"),n.setAttribute("src","https://static.mediarithmics.com/tag/2/tag.min.js"),n.setAttribute("async","true"),e.getElementsByTagName("script")[0].parentNode.appendChild(n)}(window,document,"umbrella_corp");
        
        umbrella_corp.init("<SITE_TOKEN>");
        
        // Enables client-side feeds
        umbrella_corp.call("syncFeeds");
        
        /* CUSTOMIZE THE TAG CALL BELOW */
        // remove next line to customize what you track
        umbrella_corp.pushDefault();
    </script>
    <script type="text/javascript">
        /* YOU SHOULD NOT EDIT THIS PART */
        !function(t,e,a){"use strict";var i=t.scimhtiraidem||{};function s(t){var e=i[a]||{};i[a]=e,e[t]||(e[t]=function(){i._queue[a].push({method:t,args:Array.prototype.slice.apply(arguments)})})}t.googletag=t.googletag||{},t.googletag.cmd=t.googletag.cmd||[],t.googletag.cmd.push(function(){var e=t.localStorage.getItem("mics_sgmts"),a=JSON.parse(e),i=a||{};Object.keys(i).forEach(function(e){t.googletag.pubads().setTargeting("mics_"+e,i[e].map(String))})});var r="init call config push pushDefault addIdentifier addProperties addProperty onFinish onStart _reset".split(" ");i._queue=i._queue||{},i._names=i._names||[],i._names.push(a),i._queue[a]=i._queue[a]||[],i._startTime=(new Date).getTime(),i._snippetVersion="2.0";for(var o=0;o<r.length;o++)s(r[o]);t.scimhtiraidem=i,t[a]=i[a];var n=e.createElement("script");n.setAttribute("type","text/javascript"),n.setAttribute("src","https://static.mediarithmics.com/tag/2/tag.min.js"),n.setAttribute("async","true"),e.getElementsByTagName("script")[0].parentNode.appendChild(n)}(window,document,"umbrella_corp");
        
        umbrella_corp.init({ mode: "VISIT", site_token: "<SITE_TOKEN>", domain_name: "<YOUR_DOMAIN_NAME>" });
        
        // Enables client-side feeds
        umbrella_corp.call("syncFeeds");
        
        /* CUSTOMIZE THE TAG CALL BELOW */
        // remove next line to customize what you track
        umbrella_corp.pushDefault();
    </script>
    <script type="text/javascript">
      /* YOU SHOULD NOT EDIT THIS PART */
      !function(t,e,a){"use strict";var i=t.scimhtiraidem||{};function s(t){var e=i[a]||{};i[a]=e,e[t]||(e[t]=function(){i._queue[a].push({method:t,args:Array.prototype.slice.apply(arguments)})})}t.googletag=t.googletag||{},t.googletag.cmd=t.googletag.cmd||[],t.googletag.cmd.push(function(){var e=t.localStorage.getItem("mics_sgmts"),a=JSON.parse(e),i=a||{};Object.keys(i).forEach(function(e){t.googletag.pubads().setTargeting("mics_"+e,i[e].map(String))})});var r="init call config push pushDefault addIdentifier addProperties addProperty onFinish onStart _reset".split(" ");i._queue=i._queue||{},i._names=i._names||[],i._names.push(a),i._queue[a]=i._queue[a]||[],i._startTime=(new Date).getTime(),i._snippetVersion="2.0";for(var o=0;o<r.length;o++)s(r[o]);t.scimhtiraidem=i,t[a]=i[a];var n=e.createElement("script");n.setAttribute("type","text/javascript"),n.setAttribute("src","https://static.mediarithmics.com/tag/2/tag.min.js"),n.setAttribute("async","true"),e.getElementsByTagName("script")[0].parentNode.appendChild(n)}(window,document,"mics");
      
      mics.init({mode: "VISIT", site_token: "<SITE_TOKEN>"});
      mics.call("syncFeeds");
      
      $(".your_button").on("click", function () {
        mics.push("click button", {
          button_type: "button1"
          // ...
        });
      });
    </script>
    mics.addIdentifier(
        "USER_ACCOUNT",
        {
            $user_account_id:"account 1",
            $compartment_token:"token1"
        }
    );
    mics.addIdentifier(
        "USER_ACCOUNT",
        {
            $user_account_id:"account 2",
            $compartment_token:"token2"
        });
    );
    mics.addIdentifier(
        "USER_EMAIL",
        {
            $email_hash:"email hash",
            $email:"email address"
        }
    );
    mics.addIdentifier(
        "USER_AGENT",
        {
            $user_agent_id:"user agent id"
        }
    );
    mics.pushDefault();
    mics.push("view my form", {
      "form subject": "auto trial"
    });
    // Add the user account id if available
    mics.addIdentifier(
        "USER_ACCOUNT",
        {
            $user_account_id:"<USER_ACCOUNT_ID>",
            $compartment_token:"<COMPARTMENT_TOKEN>"
        }
    );
    
    // Push the event
    mics.push("$home_view");
    // Add the user account id if available
    mics.addIdentifier(
        "USER_ACCOUNT",
        {
            $user_account_id:"<USER_ACCOUNT_ID>",
            $compartment_token:"<COMPARTMENT_TOKEN>"
        }
    );
    
    // Push the event
    mics.push("$item_list_view", {
      "$items": [
        {"$id": "78798978"},
        {"$id": "444444"},
        {"$id": "78808900"}
      ]
    });
    // Add the user account id if available
    mics.addIdentifier(
        "USER_ACCOUNT",
        {
            $user_account_id:"<USER_ACCOUNT_ID>",
            $compartment_token:"<COMPARTMENT_TOKEN>"
        }
    );
    
    // Push the event
    mics.push("$item_view", {
      "$items": [
        { "$id": "89999999" }
      ]
    });
    // Add the user account id if available
    mics.addIdentifier(
        "USER_ACCOUNT",
        {
            $user_account_id:"<USER_ACCOUNT_ID>",
            $compartment_token:"<COMPARTMENT_TOKEN>"
        }
    );
    
    // Push the event
    mics.push("$basket_view", {
      "$items" : [
        {"$id" : "78794", "$price" : 10.8,  "$qty" : 1 },
        {"$id" : "78677", "$price" : 56.99, "$qty" : 1 }
      ],
      "$currency" : "EUR"
    });
    // Add the user account id if available
    mics.addIdentifier(
        "USER_ACCOUNT",
        {
            $user_account_id:"<USER_ACCOUNT_ID>",
            $compartment_token:"<COMPARTMENT_TOKEN>"
        }
    );
    
    // Push the event
    mics.push("$transaction_confirmed", {
      "$items" : [
        {"$id" : "78794", "$price" : 10.8,  "$qty" : 1 },
        {"$id" : "78677", "$price" : 56.99, "$qty" : 1 }
      ],
      "$transaction_id" : "transact-XYZ",
      "$currency" : "EUR"
    });
    // Add the user account id if available
    mics.addIdentifier(
        "USER_ACCOUNT",
        {
            $user_account_id:"<USER_ACCOUNT_ID>",
            $compartment_token:"<COMPARTMENT_TOKEN>"
        }
    );
    
    // Push the profile
    mics.push("$set_user_profile_properties", {
      gender: "male",
      // add any other properties you whish
    });
    umbrella_corp.push(
        '$set_user_profile_properties',
        {
            'gender': 'female'
        }
    );
    umbrella_corp.push(
        '$set_user_profile_properties',
        {
            '$set_user_profile_comp_token': 'my_compartment_token',
            'gender': 'female'
        }
    );
    umbrella_corp.push(
        '$set_user_profile_properties',
        {
            '$set_user_profile_comp_token': 'my_compartment_token',
            '$set_user_profile_user_account_id': '456',
            'gender': 'female'
        }
    );
    <script type="text/javascript">
        /* YOU SHOULD NOT EDIT THIS PART */
        !function(t,e,a){"use strict";var i=t.scimhtiraidem||{};function s(t){var e=i[a]||{};i[a]=e,e[t]||(e[t]=function(){i._queue[a].push({method:t,args:Array.prototype.slice.apply(arguments)})})}t.googletag=t.googletag||{},t.googletag.cmd=t.googletag.cmd||[],t.googletag.cmd.push(function(){var e=t.localStorage.getItem("mics_sgmts"),a=JSON.parse(e),i=a||{};Object.keys(i).forEach(function(e){t.googletag.pubads().setTargeting("mics_"+e,i[e].map(String))})});var r="init call config push pushDefault addIdentifier addProperties addProperty onFinish onStart _reset".split(" ");i._queue=i._queue||{},i._names=i._names||[],i._names.push(a),i._queue[a]=i._queue[a]||[],i._startTime=(new Date).getTime(),i._snippetVersion="2.0";for(var o=0;o<r.length;o++)s(r[o]);t.scimhtiraidem=i,t[a]=i[a];var n=e.createElement("script");n.setAttribute("type","text/javascript"),n.setAttribute("src","https://static.mediarithmics.com/tag/2/tag.min.js"),n.setAttribute("async","true"),e.getElementsByTagName("script")[0].parentNode.appendChild(n)}(window,document,"mics");
        
    mics.init("<SITE_TOKEN>")
    mics.push("hit", {})
    
    </script>
    <script type="text/javascript">
        /* YOU SHOULD NOT EDIT THIS PART */
        !function(t,e,a){"use strict";var i=t.scimhtiraidem||{};function s(t){var e=i[a]||{};i[a]=e,e[t]||(e[t]=function(){i._queue[a].push({method:t,args:Array.prototype.slice.apply(arguments)})})}t.googletag=t.googletag||{},t.googletag.cmd=t.googletag.cmd||[],t.googletag.cmd.push(function(){var e=t.localStorage.getItem("mics_sgmts"),a=JSON.parse(e),i=a||{};Object.keys(i).forEach(function(e){t.googletag.pubads().setTargeting("mics_"+e,i[e].map(String))})});var r="init call config push pushDefault addIdentifier addProperties addProperty onFinish onStart _reset".split(" ");i._queue=i._queue||{},i._names=i._names||[],i._names.push(a),i._queue[a]=i._queue[a]||[],i._startTime=(new Date).getTime(),i._snippetVersion="2.0";for(var o=0;o<r.length;o++)s(r[o]);t.scimhtiraidem=i,t[a]=i[a];var n=e.createElement("script");n.setAttribute("type","text/javascript"),n.setAttribute("src","https://static.mediarithmics.com/tag/2/tag.min.js"),n.setAttribute("async","true"),e.getElementsByTagName("script")[0].parentNode.appendChild(n)}(window,document,"mics");
        
        function micsGetAllProperties() {
            var data={};
            if (Object.keys(dataLayer).length > 0) {
                dataLayer.forEach((item, index) => {
                    Object.keys(item).forEach( key => {
                        if (isNaN(key) && key!="event" && !key.startsWith("gtm")) {
                            data[key] = item[key];
                        }
                    })
                }) 
            }
            return data;
        };
    
    mics.init("<SITE_TOKEN>")
    mics.push("hit", { "data": micsGetAllProperties()})
    
    </script>
    <script type="text/javascript">
        /* YOU SHOULD NOT EDIT THIS PART */
        !function(t,e,a){"use strict";var i=t.scimhtiraidem||{};function s(t){var e=i[a]||{};i[a]=e,e[t]||(e[t]=function(){i._queue[a].push({method:t,args:Array.prototype.slice.apply(arguments)})})}t.googletag=t.googletag||{},t.googletag.cmd=t.googletag.cmd||[],t.googletag.cmd.push(function(){var e=t.localStorage.getItem("mics_sgmts"),a=JSON.parse(e),i=a||{};Object.keys(i).forEach(function(e){t.googletag.pubads().setTargeting("mics_"+e,i[e].map(String))})});var r="init call config push pushDefault addIdentifier addProperties addProperty onFinish onStart _reset".split(" ");i._queue=i._queue||{},i._names=i._names||[],i._names.push(a),i._queue[a]=i._queue[a]||[],i._startTime=(new Date).getTime(),i._snippetVersion="2.0";for(var o=0;o<r.length;o++)s(r[o]);t.scimhtiraidem=i,t[a]=i[a];var n=e.createElement("script");n.setAttribute("type","text/javascript"),n.setAttribute("src","https://static.mediarithmics.com/tag/2/tag.min.js"),n.setAttribute("async","true"),e.getElementsByTagName("script")[0].parentNode.appendChild(n)}(window,document,"mics");
        
    mics.init("<SITE_TOKEN>")
    mics.push("hit", { "data": tc_vars})
    
    </script>

    Changing the name

    Changing the domain name

    Pushing on events

    Passing one or multiple user identifiers

    • $email is optional

    • $compartment_token is optional, if omitted, the datamart default compartment will be used

    If invalid arguments are passed to addIdentifier, no error is thrown in the browser console

    The legacy method will soon be removed :

    We advise to use the new one as soon as possible

    Sending the right events and properties

    NOTE: Sending too many properties creates confusion when the users need to decide which properties to query. Only send what you know is required.

    Default tracking

    $page_view events will be dropped when the session closes (and disappear from the monitoring timeline), so it will only be useful to test that events are correctly sent to mediarithmics.

    Custom events

    Refer to the list of base event names and prefer using them to custom event names, as the platform will handle some automatic processing for them.

    E-commerce and products events

    If you have a unique identifier for the user, don't forget to add the $user_account_id property as described in this article for an optimal tracking.

    Home page

    Category or search results page

    Product page

    Basket page

    Transaction confirmation page

    You can add any custom properties available for each product in your page JavaScript. You can also use Activity Analyzers to enrich your data later using the product IDs.

    UserProfile updates

    Server-side configuration of the JavaScript tag

    Device Identification

    mediarithmics first-party cookies

    Note that:

    • This device identification method is only available on the SITE channel type.

    • It does not provide full browser coverage, as some browsers (such as Safari) enforce restrictions on first-party cookies set via JavaScript originating from third-party sources (such as our JS tag).

    IAB Transparency and Consent Framework

    Cookie matching with Google and Xandr

    Support of mediarithmics third-party cookie (vector ID)

    JavaScript Tag API Reference

    You can check the complete reference of the JS Tag tool .

    One Tag approach

    It usually implies to use an activity analyzer to process the collected data on the server side.

    Examples:

    Good knowledge of the schema and the queries that are usually created in your datamart is important for the success of this feature.

    Here is a sample process to follow to enable audience features and create value for your users:

    1. Know your schema. What is it optimized for? Which queries are regularly created? What are your actual segments and what are their queries? You should be able to create a list of useful audience features with these pieces of information.

    2. Set up audience features, in the UI and/or by script.

    3. Monitor usage and update audience features regularly!

    You can store audience features in folders. Any audience feature without a folder will be assigned to the root folder. Here are some examples.

    GET https://api.mediarithmics.com/v1/datamarts/{datamart_id}/audience_feature_folders

    Name
    Type
    Description

    datamart_id

    integer

    The ID of the datamart

    {
      "first_result": 0,
      "count": 0,
      "max_results": 0,
      "status": "ok",
      "data": [
        {
          "id": "string",
          "children_ids": [
            "string"
          ],
          "audience_features_ids": [
            "string"
          ],
          "parent_id": "string",
          "datamart_id": "string",
          "name": "string"
        }
      ],
      "total": 0
    }

    GET https://api.mediarithmics.com/v1/datamarts/{datamart_id}/audience_feature_folders/{audience_feature_folders_id}

    Name
    Type
    Description

    audience_feature_folders_id

    integer

    The ID of the folder

    datamart_id

    integer

    The ID of the datamart

    {
      "status": "ok",
      "data": {
        "id": "string",
        "children_ids": [
          "string"
        ],
        "audience_features_ids": [
          "string"
        ],
        "parent_id": "string",
        "datamart_id": "string",
        "name": "string"
      }
    }

    POST https://api.mediarithmics.com/v1/datamarts/{datamart_id}/audience_feature_folders

    Name
    Type
    Description

    datamart_id*

    integer

    The ID of the datamart

    Name
    Type
    Description

    children_ids

    array

    IDs of folder's children

    audience_features_ids

    array

    IDs of audience features attached to the folder

    PUT https://api.mediarithmics.com/v1/datamarts/{datamart_id}/audience_feature_folders/{audience_feature_folders}

    Name
    Type
    Description

    datamart_id*

    integer

    The ID of the datamart

    audience_feature_folders_id*

    integer

    The ID of the audience feature folder

    Name
    Type
    Description

    children_ids

    array

    IDs of folders's children

    audience_features_ids

    array

    IDs of audience features attached to the folder

    {
      "status": "ok",
      "data": {
        "id": "string",
        "children_ids": [
          "string"
        ],
        "audience_features_ids": [
          "string"
        ],
        "parent_id": "string",
        "datamart_id": "string",
        "name": "string"
      }
    }

    GET https://api.mediarithmics.com/v1/datamarts/{datamart_id}/audience_features

    Name
    Type
    Description

    datamart_id

    integer

    The ID of the datamart

    {
      "first_result": 0,
      "total": 0,
      "count": 0,
      "data": [
        {
          "object_tree_expression": "string",
          "description": "string",
          "id": "string",
          "variables": [
            {
              "field_name": "string",
              "data_type": "string",
              "reference_model_type": "string",
              "type": "string",
              "parameter_name": "string",
              "path": [
                "string"
              ],
              "reference_type": "string",
              "directive": "string",
              "container_type": "string"
            }
          ],
          "token": "string",
          "datamart_id": "string",
          "addressable_object": "string",
          "name": "string",
          "folder_id": "string",
          "creation_date": 0
        }
      ],
      "max_results": 0,
      "status": "ok"
    }

    GET https://api.mediarithmics.com/v1/datamarts/{datamart_id}/audience_features/{audience_feature_id}

    Name
    Type
    Description

    audience_feature_id

    integer

    The ID of the audience feature

    datamart_id

    integer

    The ID of the datamart

    {
      "status": "ok",
      "data": {
        "object_tree_expression": "string",
        "description": "string",
        "id": "string",
        "variables": [
          {
            "field_name": "string",
            "data_type": "string",
            "reference_model_type": "string",
            "type": "string",
            "parameter_name": "string",
            "path": [
              "string"
            ],
            "reference_type": "string",
            "directive": "string",
            "container_type": "string"
          }
        ],
        "token": "string",
        "datamart_id": "string",
        "addressable_object": "string",
        "name": "string",
        "folder_id": "string",
        "creation_date": 0
      }
    }

    POST https://api.mediarithmics.com/v1/datamarts/{datamart_id}/audience_features

    Name
    Type
    Description

    datamart_id

    integer

    The ID of the datamart

    Name
    Type
    Description

    object_tree_expression

    string

    The WHERE statement of the query associated to the audience feature

    description

    string

    The description of your audience feature

    {
      "status": "ok",
      "data": {
        "object_tree_expression": "string",
        "description": "string",
        "id": "string",
        "variables": [
          {
            "field_name": "string",
            "data_type": "string",
            "reference_model_type": "string",
            "type": "string",
            "parameter_name": "string",
            "path": [
              "string"
            ],
            "reference_type": "string",
            "directive": "string",
            "container_type": "string"
          }
        ],
        "token": "string",
        "datamart_id": "string",
        "addressable_object": "string",
        "name": "string",
        "folder_id": "string",
        "creation_date": 0
      }
    }

    PUT https://api.mediarithmics.com/v1/datamarts/{datamart_id}/audience_features/{audience_feature_id}

    Name
    Type
    Description

    audience_feature_id

    integer

    The ID of the audience feature to edit

    datamart_id

    integer

    The ID of the datamart

    Name
    Type
    Description

    object_tree_expression

    string

    The WHERE statement of the query associated to the audience feature

    description

    string

    The description of your audience feature

    {
      "status": "ok",
      "data": {
        "object_tree_expression": "string",
        "description": "string",
        "id": "string",
        "variables": [
          {
            "field_name": "string",
            "data_type": "string",
            "reference_model_type": "string",
            "type": "string",
            "parameter_name": "string",
            "path": [
              "string"
            ],
            "reference_type": "string",
            "directive": "string",
            "container_type": "string"
          }
        ],
        "token": "string",
        "datamart_id": "string",
        "addressable_object": "string",
        "name": "string",
        "folder_id": "string",
        "creation_date": 0
      }
    }

    Create query parameters using the $parameter_namesyntax. Example:

    The field in the audience feature will have the name you enter after the $ . Spaces in field name are not authorized. The type of selector in the audience feature is automatically chosen based on the field type

    If you want to be able to select several values in a field, use keyword in instead of the classic ==.

    You can create parameters for frequency requests with the @ScoreSum directive:

    SELECT @count{} FROM UserPoint WHERE
    events { 
        nature = "$transaction_confirmed" and 
        date >= $date 
        and products {brand in $brand and name in $name}
        }

    Audience features you create are available in the navigator, in Audience > Builders > Standard.

    The process

    // Create a folder payload
    {
      "children_ids": [
        "string"
      ],
      "audience_features_ids": [
        "string"
      ],
      "parent_id": "string",
      "datamart_id": "string",
      "name": "string"
    }
    // Editing a folder payload
    {
      "children_ids": [
        "string"
      ],
      "audience_features_ids": [
        "string"
      ],
      "parent_id": "string",
      "datamart_id": "string",
      "name": "string"
    }
    // Creating an audience feature payload
    {
        "object_tree_expression": "string",
        "description": "string",
        "datamart_id": "string",
        "addressable_object": "string",
        "name": "string",
        "folder_id": "string"
    }
    // Editing an audience feature payload
    {
        "object_tree_expression": "string",
        "description": "string",
        "datamart_id": "string",
        "addressable_object": "string",
        "name": "string",
        "folder_id": "string"
    }
    // The gender will be selectable by the user
    SELECT @count{} FROM UserPoint 
    where  profiles {gender in $gender}
    
    // The date will be selectable by the user,
    // but the nature will always be $transaction_confirmed
    SELECT @count{} FROM UserPoint 
    where events { nature = "$transaction_confirmed" and date >= $date }
    
    // User will only be able to select one gender
    SELECT @count{} FROM UserPoint 
    where  profiles {gender == $gender}
    
    // User will be able to select multiple gender values
    SELECT @count{} FROM UserPoint 
    where  profiles {gender in $gender}
    // User will be able to select the minimum number of transactions
    SELECT @count{} FROM UserPoint 
    WHERE events@ScoreSum(min: $frequency) { 
        purchase in $user_purchase 
    }

    Folders

    List folders

    Path Parameters

    List one folder

    Path Parameters

    Create a folder

    Path Parameters

    Request Body

    Edit a folder

    Path Parameters

    Request Body

    Audience features

    List audience features

    Path Parameters

    Get an audience feature

    Path Parameters

    Create an audience feature

    Path Parameters

    Request Body

    Edit an audience feature

    Path Parameters

    Request Body

    OTQL query rules

    Parameters

    UserDeviceTechnicalId

    In each datamart, all device information is stored within a device graph:

    • Devices are represented by UserDevicePoint

    • Device identifiers are represented by UserDeviceTechnicalId

    A UserPoint can have multiple user device points. A user device point can have multiple user device technical identifiers, and one device info.

    UserPoint
    |
    |---------UserDevicePoint--------------------------DeviceInfo: PC - CHROME BROWSER
    |                |---------UserDeviceTechnicalId: 1P cookie
    |                |---------UserDeviceTechnicalId: Network ID
    |                |---------UserDeviceTechnicalId: 3P cookie
    |
    |---------UserDevicePoint--------------------------DeviceInfo: ANDROID TABLET
    |                |---------UserDeviceTechnicalId: Mobile advertising id
    |                |---------UserDeviceTechnicalId: Mobile vendor id

    Organizing device technical identifiers within registries

    Device technical identifiers are related to a registry. There are 6 types of registries:

    Type
    Description

    Registries are related to organisations. You can manage them by going to Navigator > Settings > Organisation > Device registries.

    You can create your own registries under the types MOBILE_VENDOR_ID and CUSTOM_DEVICE_ID, IP_V4_ADDRESS_ID, IP_V6_ADDRESS_ID or subscribe to existing registries under other types. For more information of IP addresses refer to . Once created, you can activate them on the organisation datamarts.

    You can set up a expiration duration for identifiers stored in registries you created manually. This will only apply to identifiers captured after setting up the expiration duration.

    Registries of type INSTALLATION_ID are automatically created and removed by the platform.

    Some device registry identifiers require Channel configuration updates to trigger tracking using them on your websites properly.

    When two device technical ids are associated, the related device points are merged. This can happen:

    • When capturing user activities with multiple identifiers

    • When using the

    Hereafter is the description of the documents and their properties, as they can be fetched on the APIs.

    Property
    Type
    Description
    Property
    Type
    Description
    Property
    Type
    Description

    user_agent_id property allows to use device identifiers in a single property by concatenating several informations such as registry type, registry id and the id value.

    The Installation ID can appear in different formats depending on where it is used:

    Location
    Value format
    Example

    mediarithmics offers to use its third-party cookie, the vector ID. More information can be found on the .

    mediarithmics third-party cookie can be used as a user identifier with two different formats:

    • vec:<value>

    • mum:<value>

    Both formats are equivalent: the first one is the exact format stored in the cookie, the second one is the one stored as a technical identifier in the the datamart.

    Example: vec:89998434 / mum:89998434

    For a given device point, the vector ID can be retrieved:

    • In the technical_identifiers list as a device technical id of type MUM_ID ; in which case the identifier format will be mum:89998434

    • In the mappings list related to the device point

    The formatting of advertising cookie values from Google and Xandr is a bit specific due to the historical activity of mediarithmics as a DSP provider:

    • tech:goo:<value> for Google advertising cookies

    • tech:apx:<value> for Xandr advertising cookies

    For other partners, their third-party cookie value is attached to a web domain that is defined by mediarithmics. The identifier format is as follows:

    • web:<web_domain_id>:<value>

    The web domain designates the partner-domain.com and value the identifier value inside the cookie on partner-domain.com.

    The generic format for mobile advertising ids is:

    • mob:<os>:<encoding>:<value>.

    The os field designates the OS of device: and for Android, ios for iOS.

    The encoding field describes how the value is encoded. Available values are: raw for no encoding, sha1 for SHA1, md5 for MD5.

    The value field contains the mobile advertising id value, encoded according to the previous field. The non-encoded ID should be in lower case for Android and in uppercase for iOS.

    Example:

    The compressed format for mobile vendor ids is:

    • mov:<os>:<registry_id>:<value>

    The os field designates the OS of device: and for Android, ios for iOS.

    The registry_id field designates the registry to which this device id should be linked.

    value refers to the identifier value as generated within the mobile application.

    The generic format for CTV advertising ids is:

    • tv:<registry_id>:<value>

    • ipv4:<registry_id>:<value> for registries of type IPV4_ADDRESS_ID

    • ipv6:<registry_id>:<value> for registries of type IPV6_ADDRESS_ID

    value will contain the raw IP address (no hashing or normalization)

    • net:<registry_id>:<value> for device technical ids of type NETWORK_ID

    • dev:<registry_id>:<value> for type CUSTOM_DEVICE_ID

    User agents are the legacy format to store device identifiers. Several user agents can be attached to a UserPoint, and each user agent has a device info object.

    All user agents are identified by a vector ID.

    User agents have the following properties:

    Property
    Type
    Description

    Two web browsers on the same desktop PC are considered as two distinct agents. For example, your Chrome browser on your Windows laptop is a different device than your Firefox browser on the same laptop. On smartphones, the web browser and the phone itself are considered as two distinct agents.

    Agent-based operations like visiting a website or seeing an ad will generally automatically leverage the user agent to identify the user. You can use an agent to identify a user, usually with a user_agent_id field in the requests.

    The value field contains the string value in lower case, after the optional encoding.

    Segment builders

    You have access to three tools to segment your audience using queries:

    • Leverage to build your queries in the standard segment builder (Audience > Builders > Standard). Once set up, this is the preferred solution for fast queries building and visualising the segment in a dashboard before saving it.

    • Drag and drop fields from your schema into a visual OTQL query builder with the advanced segment builder (Audience > Builders > Advanced

    Predefined event names

    TV_ADVERTISING_ID

    Includes all registries that refer to Smart TVs and TV boxes: AAID on Android TV and Android boxes, IDFA on Apple TV, Amazon Advertising ID on Fire TV, Tizen Advertising ID on Samsung Smart TV etc.

    NETWORK_DEVICE_ID

    For registries designating IDs that are device-related & managed by third parties actors. For instance ID5, First-ID etc. ⚠️Some network identifiers are directly user-related and not device related (such as the ones generated from the email)

    CUSTOM_DEVICE_ID

    If you want to use your own device identifier (for instance: a 1P cookie that you generate), you can create it under this type.

    MUM_ID

    "mediarithmics User Mapping Identifier"

    This type and the single registry it contains are dedicated to hosting mediarithmics 3P cookie (vector_id) and references to partners' 3P cookies, until their deprecation

    IP_V4_ADDRESS_ID

    Registry used to store IPv4 addresses. Can be automatically generated when activating IP addresses auto capture on a channel

    IP_V6_ADDRESS_ID

    Registry used to store IPv6 addresses. Can be automatically generated when activating IP addresses auto capture on a channel

    creation_ts

    Timestamp

    Timestamp at which the device point was created

    last_activity_ts

    Timestamp

    Last time an event was ingested from this device. ⚠️This property is not updated at the moment.

    device

    Object of type DeviceInfo

    Description of the device through a set of normalized properties

    technical_identifiers

    List of objects

    List of available identifiers for the device

    agent_type

    Enum UserAgentType

    Indicates the type of device. Possible values: WEB_BROWSER, MOBILE_APP or CTV_APP

    browser_family

    Enum BrowserFamily

    If the device is a browser.

    Possible values: OTHER, CHROME, IE, FIREFOX, SAFARI, OPERA, STOCK_ANDROID, BOT, EMAIL_CLIENT, MICROSOFT_EDGE.

    browser_version

    String

    The version of the browser.

    form_factor

    Enum FormFactor

    Indicates the format of the device. Possible values: PERSONAL_COMPUTER, SMART_TV, GAME_CONSOLE, SMARTPHONE, TABLET, WEARABLE_COMPUTER, OTHER.

    os_family

    Enum OperatingSystemFamily

    The operating system family of the device. Possible values: WINDOWS, MAC_OS, LINUX, ANDROID, IOS, TIZEN, WEB_OS, ANDROID_TV, GOOGLE_TV, TV_OS, FIRE_TV, ROKU_TV

    os_version

    String

    The version of the operating system (ex.: "macOS 10.15 Catalina")

    carrier

    String

    The service provider that ensures connectivity of the device.

    type

    Enum RegistryType

    The type of the registry to which it is attached.

    See for possible values

    creation_ts

    Timestamp

    Timestamp at which the document was created

    last_activity_ts

    Timestamp

    Last time an event was ingested with this identifier. ⚠️This property is not updated at the moment.

    expiration_ts

    Timestamp

    Timstamp at which this document will expire. ℹ️For the moment, technical ids are stored for a period of 1 year after their creation

    Stored in mediarithmics & used in non authenticated endpoint

    ins:<registry_token>:<version_prefix><base64(value)>

    ins:first:aMGQ0YTU4Y2EtMTRlNS0xMWVlLWJlNTYtMDI0MmFjMTIwMDAy

    udp:<value> if you want to use directly the device point identifier instead of a custom device identifier.

    creation_ts

    Timestamp

    When the user agent was registered on the platform

    mappings

    Array

    Additional identifiers called the device mappings. They are cookie-based identifiers or mobile application identifiers associated with the agent.

    INSTALLATION_ID

    For each site on which the installation ID feature is activated, a registry of type INSTALLATION_ID is created.

    MOBILE_ADVERTISING_ID

    Registries representing mobile advertising ids that can be shared across editors are related to this type. It includes for instance Android Advertising IDs (AAID) and Apple Identifier for Advertisers (IDFA).

    MOBILE_VENDOR_ID

    id

    String

    The document identifier. Formatted as udp:-1234

    type

    Enum UserIdentifierType

    brand

    String

    The brand of the device (ex.: "Apple")

    model

    String

    user_agent_id

    String

    The value of the identifier. See format hereunder

    registry_id

    String

    Cookie stored in the user' browser

    <version_prefix><base64(value)> w

    aMGQ0YTU4Y2EtMTRlNS0xMWVlLWJlNTYtMDI0MmFjMTIwMDAy

    Used in authenticated endpoints

    ins:<registry_id>:<value>

    ins:1001:0d4a58ca-14e5-11ee-be56-0242ac120002

    mob:ios:raw:12345654-ABCD-1234-A1B2-123456789876
    mob:and:raw:12345678-abcd-1234-a1b2-123456789876
    UserPoint
    |
    |---------UserAgent: vec:1111--------------------------DeviceInfo: PC - CHROME BROWSER              
    |
    |---------UserAgent: vec:2222--------------------------DeviceInfo: ANDROID TABLET

    vector_id

    String

    Unique ID generated by mediarithmics and associated with each agent

    device

    Object

    // Browser based agent
    {
        "vector_id": "vec:12345654321",
        "device": {
            "form_factor": "SMARTPHONE",
            "os_family": "IOS",
            "browser_family": "SAFARI",
            "browser_version": null,
            "brand": null,
            "model": null,
            "os_version": null,
            "carrier": null,
            "raw_value": null,
            "agent_type": "WEB_BROWSER"
        },
        "creation_ts": 1591712194234,
        "mappings": [
            {
                "user_agent_id": "tech:goo:Cazrazrkazeeza-azeree9-azezrze",
                "realm_name": "GOOGLE_OPERATOR"
            },
            {
                "user_agent_id": "tech:apx:12345654321654321",
                "realm_name": "APP_NEXUS_OPERATOR"
            }
        ]
    }
    // Mobile application agent
    {
        "vector_id": "vec:12345654321",
        "device": {
            "form_factor": "OTHER",
            "os_family": "OTHER",
            "browser_family": null,
            "browser_version": null,
            "brand": null,
            "model": null,
            "os_version": null,
            "carrier": null,
            "raw_value": null,
            "agent_type": null
        },
        "creation_ts": 1573405364473,
        "mappings": [
            {
    
                // IDFA user agent id with raw encoding: mob:ios:raw:6d92078a-8246-4ba4-ae5b-76104861e7dc
                // IDFA user agent id with SHA1 encoding: mob:ios:sha1:d520a80c026be39edeb9c6e3f37c01f2da5f5e97
                // AAID user agent id with raw encoding: mob:and:raw:97987bca-ae59-4c7d-94ba-ee4f19ab8c21
                // AAID user agent id with MD5 encoding: mob:and:md5:ba06c008973b8a1bff6e087c6149227f
                "user_agent_id": "mob:ios:raw:12345654-8246-1234-ae5b-123456454654",
            }
        ]
    },

    Do not forget to create or subscribe to the required registries before using them to identify user data. If user data is received under unknown registries, identifiers will be removed and data may not be ingested properly.

    Two web browsers on the same desktop PC are considered as two distinct agents. For example, your Chrome browser on your Windows laptop is a different device than your Firefox browser on the same laptop. On smartphones, the web browser and the phone itself are considered as two distinct agents.

    Merge of device points

    If the related device points are linked to different UserPoint, a merge of device points will induce the merge of UserPoint as well.

    For some ids that are considered as probabilistic (e.g. that can create false positive matchings of users), the merge of UserDevicePoint/UserPoint will not be allowed to avoid inconsistencies in your ID graph.

    You contact your Account manager for additional information

    Description of device graph documents

    User device point

    device property of user device point

    User device technical identifier

    The properties available in the documents might differ slightly from the ones of the runtime schema.

    user_agent_id

    user_agent_id formatting - Cookie-based identifiers

    Installation ID - First-party cookie generated by mediarithmics

    Note that version_prefix is currently defined as a.

    Vector ID - mediarithmics third-party cookie

    Partners' third party cookies

    user_agent_id formatting - Mobile application identifiers

    Mobile advertising identifiers

    Mobile vendor identifiers

    user_agent_id formatting - CTV identifiers

    CTV advertising identifiers

    IP addresses captured on CTV channel

    While there is no registry dedicated to store CTV vendor identifiers, you can still use either custom registries or Mobile vendor ones (if you want to store the value of the os in the identifier)

    user_agent_id formatting - Other device identifiers

    User agents (legacy)

    User agent is a legacy format that is being replaced replaced by user device points and user device technical identifiers.

    this page
    identifier association feature
    cookie documentation

    Registries representing mobile ids that can be only be shared among apps of the same developer account are related to this type. This includes for instance Apple Identifier for Vendors (IDFV).

    In the case of device points, this property takes the value "USER_DEVICE_POINT"

    The model of the device (ex.: "Iphone 14")

    The registry to which the technical identifier

    Device pieces of information such as operating system and browser

    $user_agent_id is a UserAgentId. Agent type accepted are mobile advertising id, mobile vendor id, tv advertising id, and custom id.

  • You should not add network device id here as they are managed from the UI. If the desired network device id is not available please contact support.

  • This mechanism is different from the replication of the mediarithmics third-party cookie onto the first-party domain (mics_vid), which occurs systematically for caching purposes (see ).

    mics.addProperty("$user_account_id", "<USER_ACCOUNT_ID>" )
    mics.addProperty("$comp_token", "<COMPARTMENT_TOKEN>" );
    here
    ). It doesn't require any setup but requires knowledge about the schema. May not be the best option for casual users.
  • Build OTQL queries directly in Data Studio > Query tool. This requires a solid knowledge of your schema and OTQL.

  • You enable this feature when you set up at least:

    • One segment builder

    • One audience feature.

    You can set up multiple segment builder to create templates once you identify common segment queries that you often use.

    Each segment builder has a list of default audience features that are automatically used in it.

    You can create and edit segment builders through the UI by going to Settings > Datamart > Your datamart > Segment builders. You can also manage them by API.

    GET https://api.mediarithmics.com/v1/datamarts/{datamart_id}/audience_builders

    Name
    Type
    Description

    datamart_id

    integer

    The ID of the datamart

    {
      "first_result": 0,
      "count": 0,
      "max_results": 0,
      "status": "ok",
      "data": [
        {
          "id": "string",
          "children_ids": [
            "string"
          ],
          "audience_features_ids": [
            "string"
          ],
          "parent_id": "string",
          "datamart_id": "string",
          "name": "string"
        }
      ],
      "total": 0
    }

    GET https://api.mediarithmics.com/v1/datamarts/{datamart_id}/audience_builders/{audience_builders_id}

    Name
    Type
    Description

    datamart_id

    integer

    The ID of the datamart

    audience_builders_id

    integer

    The ID of standard segment builder you want to get

    POST https://api.mediarithmics.com/v1/datamarts/{datamart_id}/audience_builders

    Name
    Type
    Description

    datamart_id

    integer

    The ID of the datamart

    Name
    Type
    Description

    datamart_id

    string

    The ID of the datamart

    demographics_features_ids

    array

    Array of string: the IDs of audience features you want to link to your standard segment builder. These audience features will always be selected in the builder.

    {
      "first_result": 0,
      "count": 0,
      "max_results": 0,
      "status": "ok",
      "data": [
        {
          "id": "string",
          "children_ids": [
            "string"
          ],
          "audience_features_ids": [
            "string"
          ],
          "parent_id": "string",
          "datamart_id": "string",
          "name": "string"
        }
      ],
      "total": 0
    }

    GET https://api.mediarithmics.com/v1/datamarts/{datamart_id}/audience_builders

    Name
    Type
    Description

    datamart_id

    integer

    GLLBBPYmcMbn

    GET https://api.mediarithmics.com/v1/datamarts/{datamart_id}/audience_builders/{audience_builders_id}

    Name
    Type
    Description

    datamart_id

    integer

    EACXzNpxesGA

    audience_builders_id

    integer

    y1iztafbxNOl

    POST https://api.mediarithmics.com/v1/datamarts/{datamart_id}/audience_builders

    Name
    Type
    Description

    datamart_id

    integer

    UpWZubSJk7SC

    Name
    Type
    Description

    datamart_id

    string

    ZdvK39oPj25k

    demographics_features_ids

    array

    Zu89g8D3qu6m

    PUT https://api.mediarithmics.com/v1/datamarts/{datamart_id}/audience_builders/{audience_builders_id}

    Name
    Type
    Description

    audience_builders_id

    integer

    The ID of the standard segment builder to edit

    datamart_id

    integer

    The ID of the datamart

    Name
    Type
    Description

    datamart_id

    string

    The ID of the datamart

    demographics_features_ids

    string

    Array of string: The IDs of audience features you want to link to your standard segment builder. These audience features will always be selected in the builder.

    PUT https://api.mediarithmics.com/v1/datamarts/{datamart_id}/audience_builders/{audience_builders_id}

    Name
    Type
    Description

    audience_builders_id

    integer

    aIhsvJpgK6ny

    datamart_id

    integer

    TTSN6yxr96WI

    Name
    Type
    Description

    datamart_id

    string

    N2N4Y3WHqATi

    demographics_features_ids

    string

    1EsZV25xtbUt

    This API helps you upload dashboards.

    GET https://api.mediarithmics.com/v1/data_file/data?uri=mics://data_file/tenants/{organisation_id}/dashboards/{datamart_id}/AUDIENCE_BUILDER-{audience_builder_id}.json

    Name
    Type
    Description

    organisation_id

    integer

    The ID of the organisation

    datamart_id

    integer

    The ID of the datamart

    PUT https://api.mediarithmics.com/v1/data_file/data?uri=mics://data_file/tenants/{organisation_id}/dashboards/{datamart_id}/AUDIENCE_BUILDER-{audience_builder_id}.json

    Name
    Type
    Description

    organisation_id

    integer

    The ID of the organization

    datamart_id

    integer

    The ID of the datamart

    GET https://api.mediarithmics.com/v1/data_file/data?uri=mics://data_file/tenants/{organisation_id}/dashboards/{datamart_id}/AUDIENCE_BUILDER-{audience_builder_id}.json

    Name
    Type
    Description

    organisation_id

    integer

    xpvJF5g4SpwP

    datamart_id

    integer

    uqK1nIMmTAn6

    PUT https://api.mediarithmics.com/v1/data_file/data?uri=mics://data_file/tenants/{organisation_id}/dashboards/{datamart_id}/AUDIENCE_BUILDER-{audience_builder_id}.json

    Name
    Type
    Description

    organisation_id

    integer

    UFX1xf9M0BWy

    datamart_id

    integer

    uhpUbCPUJ0Gm

    In ordre to be able to select audience features thanks to final values, you should first import your final values thanks to a csv file. For more information about the search by final feature, please read the search by final value feature guider.

    Your csv file should have:

    • The following format: 1 level min and 8 levels max, final_value,

    Example

    • A maximum of 100 000 lines, each line should match your schema,

    • Final values' field of type String or [String].

    POST https://api.mediarithmics.com/v1/datamarts/{datamart_id}/reference_table_job_executions

    Name
    Type
    Description

    datamart_id

    integer

    The ID of the datamart

    Name
    Type
    Description

    file

    string

    The name of the file you want to import. Ex: "@final_value_file.csv"

    {
      "status": "ok",
      "data": {
        "parameters": null,
        "result": null,
        "error": null,
        "id": "xxxxxx",
        "status": "PENDING",
        "creation_date": 1634134417792,
        "start_date": null,
        "duration": null,
        "organisation_id": "xxxx",
        "user_id": "xxxx",
        "cancel_status": null,
        "debug": null,
        "is_retryable": false,
        "num_tasks": null,
        "completed_tasks": null,
        "erroneous_tasks": null,
        "retry_count": 0,
        "permalink_uri": null,
        "job_type": "REFERENCE_TABLE",
        "import_mode": "MANUAL_FILE",
        "import_type": null
      }
    }

    POST https://api.mediarithmics.com/v1/datamarts/{datamart_id}/reference_table_job_executions

    Name
    Type
    Description

    datamart_id

    integer

    Od2HfDMVLPel

    Name
    Type
    Description

    file

    string

    kUYOfU4QZxF3

    Example

    audience features
    // Create a standard segment builder payload
    {
      "datamart_id": "string",
      "demographics_features_ids": [
        "string"
      ],
      "name": "string"
    }
    // Edit a standard segment builder payload
    {
      "datamart_id": "string",
      "demographics_features_ids": [
        "string"
      ],
      "name": "string"
    }
    // Create a dashboard payload example
    [
      {
          "id": "1",
          "name": "Standard segment builder",
          "type": "AUDIENCE_BUILDER",
          "datamart_id": "xxxx",
          "components": [
            {
              "layout": {
                "h": 1,
                "static": false,
                "w": 6,
                "x": 0,
                "y": 0
              },
              "component": {
                "id": 2,
                "component_type": "COUNT",
                "title": "User Profiles",
                "query_id": "22252"
              }
            },
            {
              "layout": {
                "h": 1,
                "static": false,
                "w": 6,
                "x": 6,
                "y": 0
              },
              "component": {
                "id": 2,
                "component_type": "COUNT",
                "title": "User Cookies",
                "query_id": "22264"
              }
            },
            {
              "layout": {
                "h": 3,
                "static": false,
                "w": 12,
                "x": 0,
                "y": 1
              },
              "component": {
                "id": 5,
                "component_type": "MAP_BAR_CHART",
                "title": "Genre",
                "show_legend": true,
                "query_id": "47031",
                "sortKey": "A-Z",
                "percentage": true,
                "labels": {
                  "enable": true,
                  "filterValue": "",
                  "format": "{point.y}%"
                },
                "tooltip": {
                  "formatter": "{point.y}% ({point.count})"
                }
              }
            },
            {
              "layout": {
                "h": 3,
                "static": false,
                "w": 12,
                "x": 0,
                "y": 4
              },
              "component": {
                "id": 5,
                "component_type": "COUNT_BAR_CHART",
                "labels_enabled": true,
                "plot_labels": [
                  "Email",
                  "Print",
                  "Sms",
                  "Tel",
                  "Web",
                  "App"
                ],
                "title": "Contactabilité",
                "show_legend": false,
                "query_ids": [
                  "47033",
                  "47034",
                  "47035",
                  "47036",
                  "47037",
                  "47038"
                ]
              }
            }
          ]
        }
    ]
    level1,level2, ... ,final_value
    level1,level2,level3,level4,final_value
    activities,channel_id,,,my channel id1
    segments,creation_ts,,,123
    ...
    curl -k --location --request POST 'https://api.mediarithmics.com/v1/datamarts/{datamart_id}/reference_table_job_executions' \
    -H 'Content-Type: text/csv' \
    -H 'Authorization: TOKEN' \
    --data-binary '@./final_value_file.csv'

    Standard segment builder set up

    List standard segment builders

    Path Parameters

    Get a standard segment builder

    Path Parameters

    Create a standard segment builder

    Path Parameters

    Request Body

    List standard segment builders

    Path Parameters

    Get a standard segment builder

    Path Parameters

    Create a standard segment builder

    Path Parameters

    Request Body

    You cannot create more than 20 standard segment builder instances per datamart.

    Edit a standard segment builder

    Path Parameters

    Request Body

    Edit a standard segment builder

    Path Parameters

    Request Body

    Dashboards API

    List dashboards for standard segment builder

    Path Parameters

    Create & edit dashboards for standard segment builder

    Path Parameters

    List dashboards for standard segment builder

    Path Parameters

    Create & edit dashboards for standard segment builder

    Path Parameters

    Final values import

    Requirements

    Don't need to specify UserPoint for the level1, it's implicit.

    API

    Upload final values csv file

    Path Parameters

    Request Body

    Upload final values csv file

    Path Parameters

    Request Body

    parent_id

    string

    The ID of the folder's parent

    datamart_id

    string

    The ID of the datamart

    name*

    string

    The name of the folder

    parent_id

    string

    The ID of the folder's parent

    datamart_id

    string

    The ID of the datamart

    name*

    string

    The name of the folder

    datamart_id

    string

    The ID of the datamart

    addressable_object

    string

    The SELECT statement of the query associated to the audience feature. It must always set at UserPoint.

    name

    string

    The name of the audience feature

    folder_id

    string

    The ID of folder where the audience feature is stored

    datamart_id

    string

    The ID of the datamart

    addressable_object

    string

    The SELECT statement of the query associated to the audience feature. It must always set at UserPoint.

    name

    string

    The name of the audience feature

    folder_id

    string

    The ID of folder where the audience feature is stored

    name

    string

    Name of the standard segment builder

    name

    string

    bpFIx0HWRbci

    name

    string

    The name of the standard segment builder

    name

    string

    xsAiWSvKY437

    audience_builder_id

    integer

    The ID of the standard segment builder on which you want to upload dashboards

    audience_builder_id

    integer

    The ID of the standard segment builder on which you want to upload dashboards

    audience_builder_id

    integer

    cZe7evLowSbp

    audience_builder_id

    integer

    5Rm1gDwXgxFe

    ,
    TITAN_OS
    ,
    OTHER
    .
    section above
    Cookies installed on the first-party domain

    Data model

    A schema is applied to a datamart and defines what mediarithmics should index and make available through queries.

    ‌Each schema is a Graph Query Language schema defining an object tree index that will allow you to run fast Object Tree Query Language queries to search users.

    Sample Schema

    This schema defines all available mediarithmics objects with the standard properties. When defining your schema, you can start from this schema and add/remove properties based on your needs and the data you ingest into the platform.

    The number of referenced properties has an impact on query performance. It would be best only to have the properties you need to use when . Don't just copy the default ones.

    UserPoint is the root element of any mediarithmics schema, and only one index can be created. This may change in future releases to allow you to build different indexes.

    type UserPoint @TreeIndexRoot(index:"USER_INDEX"){
      id: ID!
      creation_ts: Timestamp! @TreeIndex(index:"USER_INDEX")
      creation_date:Date! @Function(name:"ISODate", params:["creation_ts"])
      
      # User identifiers
      accounts: [UserAccount!]!
      emails: [UserEmail!]!
      devices: [UserDevicePoint!]!
    
      # User content
      activities: [UserActivity!]!
      events: [UserEvent!]!
      profiles: [UserProfile!]!
      choices: [UserChoice!]!
      
      # Technical objects
      scenarios: [UserScenario!]!
      segments: [UserSegment!]!
      
      # Deprecated identifiers
      # agents: [UserAgent!]!
    }
    
    
    ### User identifiers
    
    type UserAccount {
      id:ID! @TreeIndex(index:"USER_INDEX")
      creation_ts: Timestamp! @TreeIndex(index:"USER_INDEX")
      creation_date:Date! @TreeIndex(index:"USER_INDEX") @Function(params:["creation_ts"], name:"ISODate")
      
      compartment_id: String! @TreeIndex(index:"USER_INDEX") @ReferenceTable(model_type:"COMPARTMENTS", type:"CORE_OBJECT")
      user_account_id: String! @TreeIndex(index:"USER_INDEX")
    }
    
    type UserEmail {
      id:ID! @TreeIndex(index:"USER_INDEX")
      creation_ts: Timestamp! @TreeIndex(index:"USER_INDEX")
      last_activity_ts: Timestamp @TreeIndex(index:"USER_INDEX")
      
      email: String @TreeIndex(index:"USER_INDEX")
    }
    
    type UserDevicePoint  {
      id:ID! @TreeIndex(index:"USER_INDEX")
      creation_ts:Timestamp! @TreeIndex(index:"USER_INDEX")
      creation_date:Date! @Function(name:"ISODate", params:["creation_ts"])
    
      device_info:DeviceInfo
      technical_identifiers:[UserDeviceTechnicalId!]!
      mappings:[UserAgentMapping!]! @Function(name:"ThirdPartyCookieMappings", params:["id"])
    }
    
    type DeviceInfo  {
      brand:String @TreeIndex(index:"USER_INDEX")
      browser_version:String @TreeIndex(index:"USER_INDEX")
      carrier:String @TreeIndex(index:"USER_INDEX")
      model:String @TreeIndex(index:"USER_INDEX")
      os_version:String @TreeIndex(index:"USER_INDEX")
    
      agent_type:UserAgentType @TreeIndex(index:"USER_INDEX")
      browser_family:BrowserFamily @TreeIndex(index:"USER_INDEX")
      form_factor:FormFactor @TreeIndex(index:"USER_INDEX")
      os_family:OperatingSystemFamily @TreeIndex(index:"USER_INDEX")
    }
    
    type UserDeviceTechnicalId  {
       id:ID! @TreeIndex(index:"USER_INDEX")
       creation_ts:Timestamp! @TreeIndex(index:"USER_INDEX")
       expiration_ts:Timestamp! @TreeIndex(index:"USER_INDEX")
       last_seen_ts:Timestamp! @TreeIndex(index:"USER_INDEX")
    
       registry_id:String! @TreeIndex(index:"USER_INDEX")
       type:String! @TreeIndex(index:"USER_INDEX")
    }
    
    type UserAgentMapping  {
       last_seen:Timestamp
       user_agent_id:String @TreeIndex(index:"USER_INDEX")
       vector_id:String
    }
    
    
    ### User content
    
    type UserActivity {
      id: ID!
      type: UserActivityType!
      channel_id:String @TreeIndex(index:"USER_INDEX") @ReferenceTable(type:"CORE_OBJECT", model_type:"CHANNELS") @Property(paths:["$site_id", "$app_id"])
      source: UserActivitySource!
      ts: Timestamp! @TreeIndex(index:"USER_INDEX")
      duration: Int @TreeIndex(index:"USER_INDEX")
      
      events: [UserEvent!]!
    }
    
    type UserEvent  @Mirror(object_type:"UserEvent") {
      id: ID!
      ts: Timestamp! @TreeIndex(index:"USER_INDEX")
      date:Date! @Function(params:["ts"], name:"ISODate")
    
      name:String! @TreeIndex(index:"USER_INDEX")
      channel_id:String @TreeIndex(index:"USER_INDEX") @ReferenceTable(model_type:"CHANNELS", type:"CORE_OBJECT") @Property(paths:["[parent].$site_id", "[parent].$app_id"])
      url: String @TreeIndex(index:"USER_INDEX")
      referrer:String @TreeIndex(index:"USER_INDEX")
    }
    
    type UserProfile {
      id: ID! 
      creation_ts: Timestamp! @TreeIndex(index:"USER_INDEX")
      last_modified_ts: Timestamp! @TreeIndex(index:"USER_INDEX")
      
      compartment_id: String! @TreeIndex(index:"USER_INDEX") @ReferenceTable(model_type:"COMPARTMENTS", type:"CORE_OBJECT")
      user_account_id: String @TreeIndex(index:"USER_INDEX")
    }
    
    type UserChoice {
      id: ID! 
      creation_ts: Timestamp! @TreeIndex(index:"USER_INDEX")
      choice_ts: Timestamp! @TreeIndex(index:"USER_INDEX")
      processing_id: String! @TreeIndex(index:"USER_INDEX")
      choice_acceptance_value: Boolean! @TreeIndex(index:"USER_INDEX")
    
      user_account_id: String
      compartment_id: String
      email_hash: String
      user_agent_id: String
      channel_id: String
    }
    
    
      ### Technical objects
      
    type UserSegment {
      id: ID! @TreeIndex(index:"USER_INDEX") @ReferenceTable(model_type:"SEGMENTS", type:"CORE_OBJECT")
      creation_ts: Timestamp! @TreeIndex(index:"USER_INDEX")
      last_modified_ts: Timestamp! @TreeIndex(index:"USER_INDEX")
      expiration_ts: Timestamp @TreeIndex(index:"USER_INDEX")
    }
    
    type UserScenario {
      id: ID! @TreeIndex(index:"USER_INDEX")
      scenario_id: String! @TreeIndex(index:"USER_INDEX")
      execution_id: String! @TreeIndex(index:"USER_INDEX")
      node_id: String! @TreeIndex(index:"USER_INDEX")
      callback_ts: Timestamp @TreeIndex(index:"USER_INDEX")
      start_ts: Timestamp! @TreeIndex(index:"USER_INDEX")
      node_start_ts: Timestamp! @TreeIndex(index:"USER_INDEX")
      active: Boolean @TreeIndex(index:"USER_INDEX")
    }
    
    
    ### Deprecated identifiers
    
    # type UserAgent {
    #  id:ID!
    #  creation_ts: Timestamp! 
    #  last_activity_ts: Timestamp
    #  user_agent_info:UserAgentInfo @Function(name:"DeviceInfo", params:["id"])
    # }
    
    # type UserAgentInfo  {
    #   form_factor:FormFactor
    #   brand:String
    #   browser_family:BrowserFamily
    #   browser_version:String
    #   carrier:String
    #   model:String
    #   os_family:OperatingSystemFamily
    #   os_version:String
    #   agent_type:UserAgentType
    # }

    Syntax highlights

    The ! operator

    The ! operator marks elements as mandatory. That means the element is expected not to be null.

    type MyType {
        user_account_id: String # doesn't necessarily have a user account
        user_account_id: String! # has a user account
        events: [UserEvent!]! # has a list of events, in which each event can't be null
        events: [UserEvent!] # doesn't necessarily have a list of events, but lists can't have null elements
    }

    If you add the ! operator to a field that happens to have null values, the entire object won't be indexed.

    It is hard to ensure a field will always have a value in all the data you'll put into the platform, whatever the ingestion method. Therefore, we recommend not using this operator in your schema for fields other than the predefined ones.

    The ID type

    This type is treated as a keyword string, but marks data that is not understandable for a user, as it is an identifier.

    type UserChoice {
      id: ID! 
    }

    Basic types

    There is existing multiple native type you can use in your schema.

    A best practice is to import objects with dates as Timestamp

    To display the value as date and time when running queries or in exports, you can use the Date type.

    You usually get data as Timestamp and generate the Date type from the Timestamp with the function. If not, then ensure you get data in the correct format. There is no implicit conversion between timestamps and dates.

    This directive marks the root element of an Object Tree Index. The index property marks the name of the Object Tree Index

    It should always be USER_INDEX as multiple indexes are not currently supported.

    This directive makes a field available in the WHERE clause and in of your . Fields that don't have this directive can't be used in the WHERE clause but can still be retrieved in the SELECT clause.

    Don't mark every field with this directive. Some fields, like first name, last name ... will never be used in WHERE clauses and would only make your index larger.

    When registering a String in a Tree Index with the directive @TreeIndex, you can specify how the field should be indexed, depending on how you want to use it later.

    Two modes are available, text and keyword.

    This mode is considering your value as a set of words (e.g. a text). For example, the value 'The QUICK brown fox JuMpS, over the Lazy doG.' will be considered as the list of:

    • the

    • quick

    • brown

    As you can see, some transformations were done before storing the data:

    • all the words were put in lowercase -> all string operators will be case insensitive on a field indexed with data_type: text

    • the original string was split, and the splitting characters were removed (here, it was , . and ,)

    The method used to split the words together is described The most common characters that trigger a split are (non-exhaustive list):

    • (space)

    • -

    • "

    Note that the following characters do not trigger a split (non-exhaustive list):

    • .

    • _

    • '

    • ’

    The data_type: "text" mode should be used when you're working with:

    • Full sentences (ex. a Page Title)

    • URLs

    • List of keywords (separated by a splitting character as listed above)

    Generally, this mode is used when you don't have great control over the value being collected in this field, and you want to do "broad" queries based on it.

    This mode is used to consider your value as a single word. No transformation is done with the provided value. The data_type: "keyword" mode should be used when you're working with:

    • Single values

    • Ids passed as text (ex: UUIDs, productId, categoryId, etc.)

    • Every time that you already know the values that are passed in the field (e.g. when the field data is linked to a taxonomy)

    Generally, this mode is used when you have great control over the value being collected in this field, and you want to do exact queries on it later by doing exact equality in queries.

    By default, the path associated with each of your properties is the name of these properties. You can change this behavior with the @Property directive.

    All the properties in the default schema already redefine their path. For example, the creation_ts property in the UserPoint object points to the $creation_ts property in the stored data. The declaration should theoretically have used the @Property directive, but it is unnecessary to do the work for you.

    You can define multiple paths to get the data from. If the first path is empty, the second one will be used and so one.

    In this example, user activities channel ID is either the site ID or the app ID depending on the user activity's context.

    You can use the [parent] token to go up in the object tree when defining a path

    This directive allows you to create custom types based on predefined types.

    The @Function directive is used to declare a calculated field with a set of predefined functions.

    This function creates a date from a timestamp.

    In order to retrieve third party cookie mappings for a given device point, the ThirdPartyCookieMapping function can be used:

    The function works on device points that have a device technical id of type MUM_ID attached to them. It translates the MUM_ID into a vector_id (mum:-1234 -> vec:1234) and retrieves attached partners' 3P cookies.

    This function extracts device information for an agent identifier.

    The UserAgentInfo class has the following properties:

    When users create their queries using your schema, they usually remember some elements they search for but don't know their identifiers.

    You can add the @ReferenceTable directive to fields storing channels, compartments and segment identifiers. That way, the user will have an autocomplete with the element's name instead of their identifier when creating his queries.

    This directive marks properties as usable in queries when creating .

    This directive marks properties as calculated from a .

    This directive is used in order to make

    This directive is used in order to make

    Do not index the output of the ISODate Function. You should index the timestamp value only.

    In some scenarios, you could have events directly in the UserPoint and in user activities. For example, to use frequency OTQL directives on UserEvents and build queries on several events that occurred on a single activity.

    In any other case, do not duplicate the UserEvent. Either use it in the UserPoint or the user activity.

    Bulk processing

    Bulk import aims at giving you the ability to bulk-import data into the mediarithmics platform.

    You can import:

    • Offline activities such as offline purchases and store visits

    • User segments such as email lists, cookies list, user accounts list, etc.

    • User profiles such as CRM data and scoring

    • User association such as CRM Onboarding

    • User dissociation

    • User suppression requests such as GDPR Suppression requests, and Opt-Out Management

    You upload files associated with a document import definition:

    • Files represent the data.

    • Document imports represent what mediarithmics should do with the data.

    If you need to track users in real-time, you should read

    The two steps for bulk import are:

    1. Create the document import definition to tell mediarithmics what you are importing

    2. Upload files associated with the document import definition. Each uploaded file creates a new document import execution.

    How to choose between creating a new document import or adding a new file to an existing document import? Our recommendation is to create a new document import each time you have a new set of files to upload. For example, if you upload CRM profiles every night, you should create a new "User profiles from CRM - " document import every night instead of just uploading new files to a unique "User profiles from CRM" document import.

    When importing data, you need to properly add . This will ensure your data is associated with the proper .

    Document imports define what you are about to upload in one or multiple files.

    A document import object has the following properties:

    POST https://api.mediarithmics.com/v1/datamarts/:datamartId/document_imports

    Name
    Type
    Description
    Name
    Type
    Description

    Response:

    Here is a sample request using curl:

    GET https://api.mediarithmics.com/v1/datamarts/:datamartId/document_imports

    You can list all document imports for a datamart or search them with filters.

    Name
    Type
    Description
    Name
    Type
    Description

    The query is paginated as described in .

    GET https://api.mediarithmics.com/v1/datamarts/:datamartId/document_imports/:importId

    Name
    Type
    Description

    PUT https://api.mediarithmics.com/v1/datamarts/:datamartId/document_imports/:importId

    Name
    Type
    Description
    Name
    Type
    Description

    DELETE https://api.mediarithmics.com/v1/datamarts/:datamartId/document_imports/:importId

    Removes a document import you don't want to see anymore in the system.

    Name
    Type
    Description

    A file upload creates an execution.

    After creation, the execution is at the PENDING status. It goes into the RUNNING status when the import starts and SUCCEEDED status once the platform has correctly imported the file.

    POST https://api.mediarithmics.com/v1/datamarts/:datamartId/document_imports/:importId/executions

    You create an execution and upload a file with this endpoint.

    Name
    Type
    Description
    Name
    Type
    Description

    See an example:

    You retrieve metadata about the created execution, notably and id property you can use to track the execution.

    GET https://api.mediarithmics.com/v1/datamarts/:datamartId/document_imports/:importId/executions

    You can list all executions for a document, import and retrieve useful data like their status, execution time and error messages.

    Name
    Type
    Description

    GET https://api.mediarithmics.com/v1/datamarts/:datamartId/document_imports/:importId/executions/:executionId

    Get a specific execution and retrieves useful data like its status, execution time and error messages.

    Name
    Type
    Description

    POST https://api.mediarithmics.com/v1/datamarts/:datamartId/document_imports/:importId/executions/:executionId/action

    Cancel a specific execution

    Name
    Type
    Description
    Name
    Type
    Description

    The cancellation of an execution will only work if the status of this executions is "PENDING"

    If you need to import larger files than 100Mbytes, you can split them before using the upload API and call it multiple times.

    You can split massive files using the shell command.

    The format of the imported data. APPLICATION_X_NDJSONor TEXT_CSVIt should match the file format of the upload file, e.g. .csv or .ndjson. The csv format can be chosen only for USER_SEGMENT imports.

    encoding

    String

    Encoding of the data that will be imported. Usuallyutf-8

    name

    String

    The name of your import.

    priority

    Enum

    LOW, MEDIUM or HIGH

    use_processing_pipeline

    Boolean

    Use this parameter if the import should go through activity analyzers or session aggregation for instance. Values are true or false. Default is false

    shuffle_lines

    Boolean

    Will shuffle the lines of the file for better performance. Values are : true or false. Default is true

    document_types

    string

    Filter on specific document types. Supported values areUSER_PROFILE, USER_ACTIVITY or USER_SEGMENT .Multiple filters can be separated with commas.Examples : &document_types=USER_PROFILE or &document_types=USER_PROFILE,USER_ACTIVITY

    order_by

    string

    ID sorts result by default, you can specify &order_by=name to sort them by name

    executionId*

    integer

    The ID of the execution (usually retrieved from "create execution" or "list executions" requests)

    executionId*

    string

    The ID of the execution (usually retrieved from "create execution" or "list executions" requests)

    field

    type

    description

    document_type

    Enum

    The type of data you want to import. Should be USER_ACTIVITY, USER_SEGMENT, USER_PROFILE,

    USER_CHOICE,

    USER_IDENTIFIERS_DELETION , or USER_IDENTIFIERS_ASSOCIATION_DECLARATIONS

    mime_type

    datamartId

    integer

    The ID of the datamart in which your data will be imported

    data

    object

    The document import object you wish to create

    datamartId

    integer

    The ID of the datamart

    keywords

    string

    The keywords to match with document import names. It is case sensitive.Examples:

    mime_type

    string

    Filter on a specific mime type. Supported values are APPLICATION_X_NDJSON or TEXT_CSV .

    datamartId

    integer

    The ID of the datamart

    importId

    integer

    The ID of the document import

    datamartId

    integer

    The ID of the datamart

    importId

    integer

    The ID of the document import

    data

    object

    The document import object to put

    datamartId

    integer

    The ID of the datamart

    importId

    integer

    The ID of the document import

    datamartId*

    string

    The ID of the datamart

    importId*

    string

    The ID of the document import

    Content-Type*

    string

    Your upload configuration.

    datamartId*

    integer

    The ID of the datamart

    importId*

    integer

    The ID of document import

    datamartId*

    integer

    The ID of the datamart

    importId*

    integer

    The ID of the document import

    datamartId*

    string

    The ID of the datamart

    importId*

    string

    The ID of the document import

    body*

    json

    Must be: {"action":"CANCEL"}

    How it works

    For maximum performance:

    • Ensure a maximum size for each file of 100M.

    • Use the document import for multiple records when there will be more than 1,000 per file.

    Each line in the uploaded file is a command to execute. Depending on the document import type, you have different commands available.

    User identifiers in imports

    Only one identifier is allowed per line. For example, you shouldn't specify the user agent ID if the Email Hash is already used in a line.

    However, you don't have to always use the same type of identifier in your document. For example, one line could use the user account ID while another uses the email hash.

    Document import

    Create a document import

    Path Parameters

    Request Body

    List document imports

    Path Parameters

    Query Parameters

    Get a document import

    Path Parameters

    Update a document import

    Path Parameters

    Request Body

    Remove a document import

    Path Parameters

    File upload

    Create an execution

    Path Parameters

    Headers

    List executions

    Path Parameters

    Get an execution

    Path Parameters

    Cancel an execution

    Path Parameters

    Request Body

    Splitting large files

    the real-time tracking guide.
    user identifiers
    UserPoint
    using our API guide

    Enum

    // Sample document import object
    {
        "document_type": "USER_ACTIVITY",
        "mime_type": "APPLICATION_X_NDJSON",
        "encoding": "utf-8",
        "name": "<YOUR_DOCUMENT_IMPORT_NAME>"
    }
    {
      "status": "ok",
      "data": {
        "id": "36271",
        "datafarm_key": "DF_KEY",
        "datamart_id": "DATAMART_ID",
        "document_type": "USER_PROFILE",
        "mime_type": "APPLICATION_X_NDJSON",
        "encoding": "utf-8",
        "name": "YOUR_DOCUMENT_IMPORT_NAME",
        "priority": "MEDIUM",
        "shuffle_lines" : true, 
        "use_processing_pipeline" : false
      }
    }
    curl -X POST \
      "https://api.mediarithmics.com/v1/datamarts/<DATAMART_ID>/document_imports"
      -H 'Authorization: <YOUR_API_TOKEN>'
      -H 'Content-Type: application/json'
      -d '{
              "document_type": "USER_ACTIVITY",
              "mime_type": "APPLICATION_X_NDJSON",
              "encoding": "utf-8",
              "name": "<YOUR_DOCUMENT_IMPORT_NAME>"
          }'
    {
      "status": "ok",
      "data": [
        {
          "id": "19538",
          "datafarm_key": "DF_KEY",
          "datamart_id": "DATAMART_ID",
          "document_type": "USER_PROFILE",
          "mime_type": "APPLICATION_X_NDJSON",
          "encoding": "utf-8",
          "name": "December 2020 user profiles",
          "priority": "MEDIUM",
          "shuffle_lines" : true, 
          "use_processing_pipeline" : false
        },
        {
          "id": "19552",
          "datafarm_key": "DF_KEY",
          "datamart_id": "DATAMART_ID",
          "document_type": "USER_PROFILE",
          "mime_type": "APPLICATION_X_NDJSON",
          "encoding": "utf-8",
          "name": "January 2021 user profiles",
          "priority": "MEDIUM",
          "shuffle_lines" : true, 
          "use_processing_pipeline" : false
        },
        {
          "id": "19553",
          "datafarm_key": "DF_EU_2020_02",
          "datamart_id": "1509",
          "document_type": "USER_PROFILE",
          "mime_type": "APPLICATION_X_NDJSON",
          "encoding": "utf-8",
          "name": "February 2021 user profiles",
          "priority": "MEDIUM",
          "shuffle_lines" : true, 
          "use_processing_pipeline" : false
        }
      ],
      "count": 3,
      "total": 3,
      "first_result": 0,
      "max_result": 50,
      "max_results": 50
    }
    {
      "status": "ok",
      "data": {
        "id": "36271",
        "datafarm_key": "DF_KEY",
        "datamart_id": "DATAMART_ID",
        "document_type": "USER_PROFILE",
        "mime_type": "APPLICATION_X_NDJSON",
        "encoding": "utf-8",
        "name": "December 2020 user profiles",
        "priority": "MEDIUM",
        "shuffle_lines" : true, 
        "use_processing_pipeline" : false
      }
    }
    {
      "status": "ok",
      "data": {
        "id": "36271",
        "datafarm_key": "DF_KEY",
        "datamart_id": "DATAMART_ID",
        "document_type": "USER_PROFILE",
        "mime_type": "APPLICATION_X_NDJSON",
        "encoding": "utf-8",
        "name": "YOUR_DOCUMENT_IMPORT_NAME",
        "priority": "MEDIUM",
        "shuffle_lines" : true, 
        "use_processing_pipeline" : false
      }
    }
    {
        "status": "ok",
        "data": {
            "parameters": null,
            "result": null,
            "error": null,
            "id": "11597785",
            "status": "PENDING",
            "creation_date": 1609410143659,
            "start_date": null,
            "duration": null,
            "organisation_id": "1426",
            "user_id": null,
            "cancel_status": null,
            "debug": null,
            "is_retryable": false,
            "permalink_uri": "MTowOjA6NDI1MzAxMg==",
            "num_tasks": null,
            "completed_tasks": null,
            "erroneous_tasks": null,
            "retry_count": 0,
            "job_type": "DOCUMENT_IMPORT",
            "import_mode": "MANUAL_FILE",
            "import_type": null
        }
    }
    curl --location --request POST 'https://api.mediarithmics.com/v1/datamarts/:datamartId/document_imports/:executionId/executions/' \
    --header 'Content-Type: application/x-ndjson; \
    --header 'Authorization: api:TOKEN' \
    --data-binary '@/Users/username/path/to/the/file.ndjson'
    {
        "status": "ok",
        "data": [
            {
                "parameters": {
                    "datamart_id": 1609,
                    "document_import_id": 19718,
                    "mime_type": "APPLICATION_X_NDJSON",
                    "document_type": "USER_PROFILE",
                    "input_file_name": "requestBody9664967795462448677asRaw",
                    "file_uri": "mics://data_file/tenants/1426/datamarts/1509/document_imports/19518/requestBody9664967795462448677asRaw-2020-12-31_10.22.23-KzgivDim3y.json",
                    "number_of_lines": 4,
                    "segment_id": null
                },
                "result": {
                    "total_success": 4,
                    "total_failure": 0,
                    "input_file_name": "requestBody9664967795462448677asRaw",
                    "input_file_uri": "mics://data_file/tenants/1426/datamarts/1509/document_imports/19518/requestBody9664967795462448677asRaw-2020-12-31_10.22.23-KzgivDim3y.json",
                    "error_file_uri": "mics://data_file/tenants/1426/datamarts/1509/document_imports/19518/requestBody9664967795462448677asRaw-2020-12-31_10.22.23-KzgivDim3y_errors.csv",
                    "possible_issue_on_identifiers": false,
                    "top_identifiers": {}
                },
                "error": null,
                "id": "11597785",
                "status": "SUCCEEDED",
                "creation_date": 1609410143659,
                "start_date": 1609410150976,
                "duration": 3059,
                "organisation_id": "1426",
                "user_id": null,
                "cancel_status": null,
                "debug": null,
                "is_retryable": false,
                "permalink_uri": "MTowOjA6NDI1MzAxMg==",
                "num_tasks": 4,
                "completed_tasks": 4,
                "erroneous_tasks": 0,
                "retry_count": 0,
                "job_type": "DOCUMENT_IMPORT",
                "import_mode": "MANUAL_FILE",
                "import_type": null,
                "end_date": 1609410154035
            },
            {
                "parameters": {
                    "datamart_id": 1609,
                    "document_import_id": 19718,
                    "mime_type": "APPLICATION_X_NDJSON",
                    "document_type": "USER_PROFILE",
                    "input_file_name": "requestBody17471990940413569967asRaw",
                    "file_uri": "mics://data_file/tenants/1426/datamarts/1509/document_imports/19518/requestBody17471990940413569967asRaw-2020-10-19_09.54.45-JvP1ssxKSu.json",
                    "number_of_lines": 4,
                    "segment_id": null
                },
                "result": {
                    "total_success": 0,
                    "total_failure": 4,
                    "input_file_name": "requestBody17471990940413569967asRaw",
                    "input_file_uri": "mics://data_file/tenants/1426/datamarts/1509/document_imports/19518/requestBody17471990940413569967asRaw-2020-10-19_09.54.45-JvP1ssxKSu.json",
                    "error_file_uri": "mics://data_file/tenants/1426/datamarts/1509/document_imports/19518/requestBody17471990940413569967asRaw-2020-10-19_09.54.45-JvP1ssxKSu_errors.csv",
                    "possible_issue_on_identifiers": false,
                    "top_identifiers": {}
                },
                "error": {
                    "message": "0 success, 4 failures\nSaved errors:\nNo profile id found while upserting a user profile Error id = 9d5016ea-6b7b-4c64-bc74-60ba207e3bed.\nNo profile id found while upserting a user profile Error id = 99f8d9bb-4c94-49ea-8bb2-934bc6056cac.\nNo profile id found while upserting a user profile Error id = d1216b0e-619c-4d92-9098-cc5ae4ac8e16.\nNo profile id found while upserting a user profile Error id = a92d3258-163c-4b9d-949e-94f9006cd77d.\n"
                },
                "id": "11170897",
                "status": "SUCCEEDED",
                "creation_date": 1603101286198,
                "start_date": 1603101317674,
                "duration": 1062,
                "organisation_id": "1426",
                "user_id": null,
                "cancel_status": null,
                "debug": null,
                "is_retryable": false,
                "permalink_uri": "MTowOjA6MzgyNjEyNA==",
                "num_tasks": 4,
                "completed_tasks": 0,
                "erroneous_tasks": 4,
                "retry_count": 0,
                "job_type": "DOCUMENT_IMPORT",
                "import_mode": "MANUAL_FILE",
                "import_type": null,
                "end_date": 1603101318736
            }
        ],
        "count": 2,
        "total": 2,
        "first_result": 0,
        "max_result": 50,
        "max_results": 50
    }
    {
        "status": "ok",
        "data": {
            "parameters": {
                "datamart_id": 1609,
                "document_import_id": 19718,
                "mime_type": "APPLICATION_X_NDJSON",
                "document_type": "USER_PROFILE",
                "input_file_name": "requestBody9664967795462448677asRaw",
                "file_uri": "mics://data_file/tenants/1426/datamarts/1509/document_imports/19518/requestBody9664967795462448677asRaw-2020-12-31_10.22.23-KzgivDim3y.json",
                "number_of_lines": 4,
                "segment_id": null
            },
            "result": {
                "total_success": 4,
                "total_failure": 0,
                "input_file_name": "requestBody9664967795462448677asRaw",
                "input_file_uri": "mics://data_file/tenants/1426/datamarts/1509/document_imports/19518/requestBody9664967795462448677asRaw-2020-12-31_10.22.23-KzgivDim3y.json",
                "error_file_uri": "mics://data_file/tenants/1426/datamarts/1509/document_imports/19518/requestBody9664967795462448677asRaw-2020-12-31_10.22.23-KzgivDim3y_errors.csv",
                "possible_issue_on_identifiers": false,
                "top_identifiers": {}
            },
            "error": null,
            "id": "11597785",
            "status": "SUCCEEDED",
            "creation_date": 1609410143659,
            "start_date": 1609410150976,
            "duration": 3059,
            "organisation_id": "1426",
            "user_id": null,
            "cancel_status": null,
            "debug": null,
            "is_retryable": false,
            "permalink_uri": "MTowOjA6NDI1MzAxMg==",
            "num_tasks": 4,
            "completed_tasks": 4,
            "erroneous_tasks": 0,
            "retry_count": 0,
            "job_type": "DOCUMENT_IMPORT",
            "import_mode": "MANUAL_FILE",
            "import_type": null,
            "end_date": 1609410154035
        }
    }
    {
      "status": "ok",
      "data": {
        "parameters": null,
        "result": null,
        "error": null,
        "id": "22747195",
        "status": "CANCELED",
        "creation_date": 1646060596034,
        "start_date": null,
        "duration": null,
        "organisation_id": "1581",
        "user_id": null,
        "cancel_status": "REQUESTED",
        "debug": null,
        "is_retryable": false,
        "community_id": "1581",
        "num_tasks": null,
        "completed_tasks": null,
        "erroneous_tasks": null,
        "retry_count": 0,
        "permalink_uri": null,
        "job_type": "DOCUMENT_IMPORT",
        "import_mode": "MANUAL_FILE",
        "import_type": null
      }
    }
    split -l <LINE_NUMBER> ./your/file/path
    fox
  • jumps

  • over

  • lazy

  • dog.

  • ‘
  • ,

  • ;

  • ?

  • !

  • /

  • similar text
    etc.
    type UserProfile {
      id: ID!
      creation_ts: Timestamp
      email: String
      age: Int
      active: Boolean
    }
    // Origin activity
    {
        ...
        "$ts": 1632753811859,
        "other_date": "2021-09-27T14:43:31.859Z",
        "other_ts": 1632753811859
        ...
    }
    type UserActivity {
        ...
        ts: Timestamp @TreeIndex(index:"USER_INDEX")
        other_date: Date
        other_ts: Timestamp
        date: Date @Function(name:"ISODate", params:["ts"]) 
        ...
    }
    
    ## Doing SELECT { ts other_date other_ts date } ...
    ## returns 
    ##     "ts": 1632753811859,
    ##     "other_date": "2021-09-27T14:43:31.859Z",
    ##     "other_ts": 1632753811859,
    ##     "date": "2021-09-27T14:43:31.859Z",
    // Origin activity
    {
        ...
        "other_date": 1632753811859,
        ...
    }
    
    
    type UserActivity {
        # This won't work as received data is a timestamp.
        other_date: Date
    }
    
    ## SELECT { other_date } ...
    ## throws an error
    type UserPoint @TreeIndexRoot(index:"USER_INDEX"){
    }
    type UserEvent {
       id:ID!
       ts:Timestamp! 
       # url and referrr properties are now available in WHERE clauses
       url:String @TreeIndex(index:"USER_INDEX")
       referrer:String @TreeIndex(index:"USER_INDEX")
    }
    type myType {
       mystring:String @TreeIndex(index:"USER_INDEX", data_type: "text")
       secondstring:String @TreeIndex(index:"USER_INDEX", data_type: "keyword")
    }
    type UserEvent {
       id:ID!
       ts:Timestamp! 
       name:String!
       # We are creating shortcuts to the $url, $referrer and $items properties
       # that are normaly in a $properties object in the user event.
       # This will make them easier to query
       url:String @Property(path:"$properties.$url")
       referrer:String @Property(path:"$properties.$referrer")
       products:[Product] @Property(path:"$properties.$items")
    }
    
    type Product {
       # Here we simply change the name into id and name instead of $id and $name
       id: String @TreeIndex(index:"USER_INDEX") @Property(path:"$id")
       name: String @TreeIndex(index:"USER_INDEX") @Property(path:"$name")
    }
    type UserPoint {
        # What should have been declared
        creation_ts: Timestamp! @Property(path:"$creation_ts")
        # What  is declared as a shortcut
        creation_ts: Timestamp!
    }
    type Product {
       # We do have to use the @Property directive as those properties
       # don't exist in the default schema for a Product object type
       id: String @Property(path:"$id")
       name: String @Property(path:"$name")
    }
    type MyType {
        channel_id: String @Property(paths:["$site_id", "$app_id"])
    }
    type MyType {
        creative_id:String @Property(path:"[parent].[parent].$origin.$creative_id")
    }
    # UserEvent type has been renamed ArticleView
    # Not really interesting and should be avoided
    type ArticleView @Mirror(object_type:"UserEvent"){}
    
    # More advanced usage : ArticleView object are UserEvents
    # with a name of "navigation.article"
    type ArticleView @Mirror(object_type:"UserEvent", filter:"name == \"navigation.article\""){}
    type UserPoint @TreeIndexRoot(index:"USER_INDEX"){
      ###
      basketviews: [BasketView]
      productviews: [ProductView]
    }
    
    type BasketView @Mirror(object_type:"UserEvent", filter:"name == \"$basket_view\""){}
    type ProductView @Mirror(object_type:"UserEvent", filter:"name == \"$page_view\""){}
    type MyType {
        # creation_date is a Date created from the timestamp creation_ts
        creation_date:Date! @Function(name:"ISODate", params:["creation_ts"])
    }
    type UserDevicePoint  {
      id:ID! @TreeIndex(index:"USER_INDEX")
      ...
      mappings:[UserAgentMapping!]! @Function(name:"ThirdPartyCookieMappings", params:["id"])
    }
    
    type UserAgentMapping  {
       last_seen:Timestamp
       user_agent_id:String
       vector_id:String
    }
    type UserAgent  {
       id:ID! @TreeIndex(index:"USER_INDEX")
       user_agent_info:UserAgentInfo @Function(name:"DeviceInfo", params:["id"])
    }
    type UserAgentInfo  {
       form_factor:FormFactor
       brand:String
       browser_family:BrowserFamily
       browser_version:String
       carrier:String
       model:String
       os_family:OperatingSystemFamily
       os_version:String
       agent_type:UserAgentType
    }
    
    ### The following enums are predefined.
    ### It is not necessary to define them 
    
    enum FormFactor {
        WEARABLE_COMPUTER
        TABLET
        SMARTPHONE
        GAME_CONSOLE
        SMART_TV
        PERSONAL_COMPUTER
        OTHER
    }
    
    enum BrowserFamily {
        OTHER
        CHROME
        IE
        FIREFOX
        SAFARI
        OPERA
        STOCK_ANDROID
        BOT
        EMAIL_CLIENT
        MICROSOFT_EDGE
    }
    
    enum OperatingSystemFamily {
        OTHER
        WINDOWS
        MAC_OS
        LINUX
        ANDROID
        IOS
    }
    
    enum UserAgentType {
        WEB_BROWSER
        MOBILE_APP
    }
    type UserSegment  {
       id:ID! @ReferenceTable(type:"CORE_OBJECT", model_type:"SEGMENTS") @TreeIndex(index:"USER_INDEX")
    }
    
    type UserActivity  {
       channel_id:String @ReferenceTable(model_type:"CHANNELS", type:"CORE_OBJECT") @TreeIndex(index:"USER_INDEX") @Property(paths:["$site_id", "$app_id"])
    }
    
    type UserProfile  {
       compartment_id:String! @ReferenceTable(model_type:"COMPARTMENTS", type:"CORE_OBJECT") @TreeIndex(index:"USER_INDEX")
    }
    
    type UserEvent {
       channel_id:String @ReferenceTable(model_type:"CHANNELS", type:"CORE_OBJECT") @Property(paths:["[parent].$site_id", "[parent].$app_id"]) @TreeIndex(index:"USER_INDEX")
    }
    type UserAccount  {
       id:ID!
       # This property won't be usable in Edge segment queries
       compartment_id:String! 
       # This property will be usable in Edge segment queries
       user_account_id:String! @TreeIndex(index:"USER_INDEX") @EdgeAvailability
    }
    type UserPoint {
      id: ID!
      accounts: [UserAccount]
      …
      rfm_score: RfmScore @ComputedField(technical_name = “RfmScore”) @TreeIndex(index:"USER_INDEX")
    }
    
    type RfmScore {
      …
    }
    type UserProfile {
      …
      loyalty: Loyalty
    }
    
    type Loyalty {
      cards:[LoyaltyCards]
    }
    
    type LoyaltyCards {
      card_id : String! @UpdateStrategyKey
      benefits : String
      last_visit_date : String
    }
    # Schema extract
    
    type UserProfile {
       compartment_id : String!
       user_account_id : String
       segmentations: [Segmentation]
    }
    
    type Segmentation @UpdateValueObject {
       type: String
       label: String
    }
    # DO
    type UserAgent  {
       creation_ts:Timestamp! @TreeIndex(index:"USER_INDEX")
       creation_date:Date! @Function(name:"ISODate", params:["creation_ts"])
       user_agent_info:UserAgentInfo @Function(params:["id"], name:"DeviceInfo")
       id:ID!
       last_activity_ts:Timestamp
    }
    
    # DON'T
    type UserAgent  {
       creation_ts:Timestamp! 
       creation_date:Date! @Function(name:"ISODate", params:["creation_ts"]) @TreeIndex(index:"USER_INDEX")
       user_agent_info:UserAgentInfo @Function(params:["id"], name:"DeviceInfo")
       id:ID!
       last_activity_ts:Timestamp
    }
    # Only do if in a specific scenario requiring it
    type UserPoint @TreeIndexRoot(index:"USER_INDEX"){
      ###
      activities: [UserActivity!]!
      events:[UserEvent!]!
    }
    
    type UserActivity {
      ###
      events: [UserEvent!]!
    }
    
    type UserEvent @Mirror(object_type:"UserEvent") {
       name:String! @TreeIndex(index:"USER_INDEX")
       id:ID!
       ts:Timestamp!
    }

    Timestamps and dates

    Both types can are compatible with Date operators in queries. Only use one @TreeIndex directive when creating a date from a timestamp : this will save space in the index and both types have the same capabilities in the query.

    Directives

    @TreeIndexRoot

    @TreeIndex

    The @TreeIndex directive is mandatory for some default properties. They already have that directive in the default schema, and you shouldn't remove it, or your schema won't be validated.

    The value of the index in @TreeIndex should always be USER_INDEX.

    String indexed as text

    String indexed as keyword

    @Property

    Taking value from multiple paths

    Available tokens

    @Mirror

    Sample usage: custom types with filters

    @Function

    ISODate

    ThirdPartyCookieMappings

    See user_agent_id section in the device identifiers documentation for more information on the user_agent_id formatting (including partners' 3P cookies).

    DeviceInfo (legacy)

    This function is only used on datamarts referencing the legacy type UserAgent.

    For datamarts referencing the new type UserDevicePoint, we suggest to use the previous function: ThirdPartyCookieMappings.

    @ReferenceTable

    @EdgeAvailability

    @ComputedField

    @UpdateStrategyKey

    @UpdateValueObject

    Best practices

    Do not index ISODate function result

    UserEvent indexed twice

    ISODate
    Aggregation operations
    OTQL queries
    in great details here.
    Edge segments
    Computed Field Function
    targeted updates on objects with an ID property in a UserProfile
    targeted updates on objects that do not not have ID properties in a UserProfile
    defining your schema

    OTQL examples

    This page provides examples of OTQL queries, based on simplified schemas. The objective is to be less technical and illustrate how works our language by different use cases.

    Basic queries

    To begin, we'll talk about fundamentals of the syntaxe language. How it works and what it's the excepted result for each query. It will give you additional informations about OTQL.

    It's better to start reading the queries, if you didn't to it yet, before continue.

    Schema example

    For the following examples, we consider the runtime schema below:

    type UserPoint {
        id : ID!
        activities : [UserActivity!]!
        profiles : [UserProfile!]!
    }
    
    type UserActivity {
        id : ID!
        events : [UserEvent!]!
    }
    
    type UserEvent {
        id : ID!
        name : String
    }
    
    type UserProfile {
        id : ID!
        age : String
    }

    If we want to represent a userpoint, it will be object tree. For illustrate it, we could considerate it like this :

    Representation of an userpoint

    The different steps of an OTQL query

    Even if the syntaxe of an OTQL query is close to a SQL one, the execution isn't the same at all. We talk about object tree and not column. This main difference gets lots of consequences and one of them is how the query is executed.

    Query resolution is a two phases process

    1. Narrow queried object mentioned in FROM by applying a WHERE clause on it or/and on any sub-object's fields

    When WHERE clause is applied on sub-object's field, if at least one sub-object validates the condition then all parent objects validate it as well.

    2. Return only desired objects & fields by listing them in SELECT clause

    Finally the query returns :

    As you can see, despite the WHERE clause on $transaction_confirmed events, the query returns $page_view events since SELECT is applied from UserPoint.

    1. Narrow queried object mentioned in FROM by applying a WHERE clause on it or/and on any sub-object's fields

    2. Return only desired objects & fields by listing them in SELECT clause

    Here the query returns :

    In this example, the UserPoint id=3 was not picked in the WHERE clause since it doesn't have any $transaction_confirmed event attached to it.

    As you could see, the WHERE can filter only object in defined by the FROM . It gives you the ability to start the query where you need, it defines the scope of the query resolution and where the other operators are executed.

    If you want to pick only a specific event, you will have to change the context. The FROM allows you to do so.

    Here the query returns :

    However specifying a sub-object also limit the scope of the predicate. For example, use FROM UserEvent doesn't give you access to UserPoint fields (like profiles).

    Another way to get specific fields values : use @filter in the SELECT part to only retrieve elements you need

    You can also use if you don't want to change the scope of your query but you need to get only specific elements. It is completely independent of the WHERE clause and the filter is applied after the WHERE clause execution.

    The first step will be the same as the one mentionned previously (narrow queried object mentioned in FROM using the WHERE clause).

    But during the second phase, the @filter will be apply on selected objects.

    Thefore, only $page_view are returned by the query :

    You can add multiple conditions in the WHERE clause using .

    As previously demonstrated, it's quite easy to add conditions in sub-objects scope (FROM). However if you need to execute your query in a specific scope and apply condition from an other object, you will have to use JOIN.

    Note: the join is automatically resolved by UserPoint, there is no need to provide join constraint.

    By the way, it is also possible to directly make the JOIN in UserProfile to get the same result :

    This is the runtime schema for examples below

    This is the runtime schema for examples below

    Use case: Select all UserPoint who are celebrating their birthday today and are between 18 and 28 years old (rolling years).

    Use case: Select all UserPoint who are celebrating their birthday in the next 7 days and are between 18 and 28 years old (rolling years).

    @filter can be quite hard to understand, so let's see some examples to clarify its usage.

    This is the runtime schema for examples below

    Use case: I want to retrieve, for each user, all URLs of type "newsarticle" and category "actu" that were browsed yesterday.

    If I use the following query :

    This query returns many empty events, making the result unusable. Although the events are filtered, I haven’t excluded UserPoint that don’t contain any events with the clause.

    To fix this, I need to add a WHERE clause to ensure each UserPoint has at least one event which matches the clause.

    Here, the result is an improvement over the previous one, displaying only the events with a url of a page with the type "newsarticle" and the category "actu".

    Now, if we want to retrieve information from activities while still filtering the events, we need to refine the query further.

    As you can see, some events may be empty because the filter is not applied at the activities level. This means the returned activities contain at least one events which matches the clause.

    If you try applying the filter at a higher level, specifically at the activity level:

    By removing the event filter, the query now returns all events from activities that contain at least one page that matches the clause, rather than only pages that match.

    To fix this, the first solution is to add another @filter to exclude unnecessary elements from both activities and events.

    This query filters out unnecessary elements from both events and activities, but it is quite lengthy and difficult to read.

    The second solution is to apply an empty @filter at the activities level in addition to the events level one:

    The empty filter removes any events that are directly empty from the activities.

    User profiles import

    Use this feature to UPSERT or DELETE in your datamart.

    Use the endpoints to create a with theUSER_PROFILEdocument type and APPLICATION_X_NDJSON mime type. Only ndjson data is supported for user profiles.

    Then, create anwith your user profile import commands formatted in ndjson .

    Each line in the uploaded file can have the following properties:

    Same explanation with multiple userpoints

    Change the scope of your query

    Use FROM to chose your execution context

    Get condition on different sub-object Tree

    Add a condition from another Object Tree

    Scoring operator

    Use case : Count UserPoint who bought more than X€ of product of the IT category

    Use case : Count UserPoint who bought in average more than X€ of product of the IT category

    Use case : Count UserPoint who bought more than X€ of product of the IT or Book category

    Date operators

    Be aware that now is evaluated at the start of the segment calculation, which may result in a discrepancy between the expected and actual values.

    Filters

    The empty filter only removes empty sub-objects. If you add another field that contains data, the filter will not remove the events

    @filter
    boolean operators
    Introduction to OTQL
    In this example, the UserEvent id=3 validates the WHERE which means UserActivity id=2 is selected and therefore UserPoint id=1 is returned from the query.
    This query means : "Get all event’s name by user with at least one transaction confirmed"
    Like we seen, one transaction confirmed validate all the userpoint
    The SELECT only be apply in userpoint still in the list, after the WHERE filter
    Apply the WHERE clause on your data
    @filter remove all the object which doesn't match with its clause
    In this example, the two conditions need to be validated
    Step 1 : Apply the first WHERE clause
    Step 2 : Create an intersection with the second WHERE
    Step 3 : Execute the selection in the new scope
    // SELECT <objects fields or aggregates> # fields returned
    // FROM <object collection> # where the query will be executed
    // WHERE <object tree expression> # filter applied
    
    SELECT { activities { events { name } } }
    FROM UserPoint 
    WHERE activities { events { name = "$transaction_confirmed" } }
    [
       {
          activities : [ { events : [ { name : "$page_view" } ] },
                         { events : [ { name : "$page_view" }, 
                                      { name : "$transaction_confirmed" } ] } ] 
       } 
    ]
    # Example : Get all event’s name by user with at least one transaction confirmed
    SELECT { activities { events { name } } }
    FROM UserPoint 
    WHERE activities { events { name = "$transaction_confirmed" } }
    [
       {
          activities : [ { events : [ { name : "$page_view" }, 
                                      { name : "$transaction_confirmed" } ] } ]
       }, 
       {
          activities : [ { events : [ { name : "$page_view" }, 
                                      { name : "$transaction_confirmed" } ] }, 
                         { events : [ { name : "$page_view" } ] } ]
       }
     ]
    # Example : Get the name of each event where the name is "$trasaction_confirmed"
    # Here, we just want to be sure this query return only events we want
    SELECT { name }
    FROM UserEvent 
    WHERE name = "$transaction_confirmed"
    [ 
        { 
            name : "$transaction_confirmed"
        }
    ]
    # Example : Get events named "$page_view" by user with at least one transaction confirmed
    SELECT { activities { events @filter(clause:"name = \"$page_view\"") { name } } }
    FROM UserPoint 
    WHERE activities { events { name = “$transaction_confirmed” } }
    [
       {
          activities : [ { events : [ { name : "$page_view" } ] } ]
       }, 
       {
          activities : [ { events : [ { name : "$page_view" } ] }, 
                         { events : [ { name : "$page_view" } ] } ]
       }
     ]
    # Example : Get event’s names by user with at least one transaction confirmed 
    # and an age between 20 and 30 years old
    SELECT { activities { events { name } } }
    FROM UserPoint WHERE profiles { age = "20-30" } 
      AND activities {events { name = "$transaction_confirmed" } }
    [
      {
          activities : [ { events : [ { name : "$page_view" }, 
                                      { name : "$transaction_confirmed" } ] }, 
                         { events : [ { name : "$page_view" } ] } ]
       }
     ]
    # Example : Get event’s names by events named "$transaction_confirmed" 
    # and where the user is between 20 and 30 years old
    SELECT { name }
    FROM UserEvent WHERE name = "$transaction_confirmed"
    JOIN UserPoint WHERE profiles { age == "20-30" }
    [ 
        { 
            name : "$transaction_confirmed"
        }
    ]
    # Example : Get event’s names by events named "$transaction_confirmed" 
    # and where the user is between 20 and 30 years old
    SELECT { name }
    FROM UserEvent WHERE name = "$transaction_confirmed"
    JOIN UserProfile WHERE age == "20-30"
    type UserPoint  @TreeIndexRoot(index:"USER_INDEX") {
       id:ID!
       activity_events:[ActivityEvent!]!
    }
    
    type ActivityEvent  @Mirror(object_type:"UserEvent") {
       order:Order @Property(path:"$properties.order")
    }
    
    type Order  {
       order_products:[OrderProduct]!
       date: Timestamp! 
    }
    
    type OrderProduct  {
       id:String @TreeIndex(index:"USER_INDEX")
       price: Float @TreeIndex(index:"USER_INDEX") # in €
       category:String @TreeIndex(index:"USER_INDEX") # possible value : "IT" or "Book"
    }
    # More than 1000€ in one order : 
    SELECT @count{} FROM UserPoint
    WHERE activity_events { 
        order { 
            order_products @ScoreField(name: "price") @ScoreSum(min: 1000) { 
                category="IT" 
            }
        }
    }
    
    # More than 1000€ in cross orders (explicite): 
    SELECT @count {} FROM UserPoint
    WHERE activity_events @ScoreSum(min : 1000, result:"boolean_value") {
        order { 
            order_products @ScoreField(name:"price") @ScoreSum(result:"score_value") {
                category="IT"
            }
        }
    }
    
    # More than 1000€ in cross orders (implicite): 
    SELECT @count {} FROM UserPoint
    WHERE activity_events @ScoreSum(min : 1000) {
        order { 
            order_products @ScoreField(name:"price") {
                category="IT"
            }
        }
    }
    
    # More than 1000€ in cross orders this last 10 days: 
    SELECT @count {} FROM UserPoint
    WHERE activity_events @ScoreSum(min : 1000) {
        order { 
            order_products @ScoreField(name:"price") {
                category="IT"
            }
            AND date > "now-10d"
        }
    }
    
    # More than 1000€ in cross orders with at least products which cost 10€: 
    SELECT @count {} FROM UserPoint
    WHERE activity_events @ScoreSum(min : 1000) {
    	order {
    	    order_products @ScoreField(name: "price") @ScoreSum(min: 10, result:"score_value") { 
              category="IT" 
          }
       }
    }
    
    # More than 1000€ in cross orders with at least 10 products : 
    SELECT @count {} FROM UserPoint
    WHERE activity_events @ScoreSum(min : 1000) {
    	order {
    	    order_products @ScoreField(name: "price") @ScoreSum(result:"score_value") { 
              category="IT" 
          }
          AND order_products @ScoreSum(min: 10) {
    	        category="IT"
    	    }
       }
    }
    
    # More than 1000€ in cross orders with at least one product which costs more than 10€ : 
    SELECT @count {} FROM UserPoint
    WHERE activity_events @ScoreSum(min : 1000) {
    	order {
    	    order_products @ScoreField(name: "price") @ScoreSum(result:"score_value") { 
              category="IT" 
          }
          AND order_products @ScoreField(name: "price") @ScoreMax(min: 10) {
    	        category="IT"
    	    }
       }
    }
    
    # WARNING : DOES NOT WORK 
    
    # More than 1000€ in cross orders with at least 10 orders more than 100€ : 
    SELECT @count {} FROM UserPoint
    WHERE activity_events @ScoreSum(min : 1000) {
    	order @ScoreSum(min: 10, result: "score_value") {
          @ScoreSum(min: 100, result: "boolean_value") {
               order_products @ScoreField(name: "price") @ScoreSum(result:"score_value") { 
                  category="IT" 
               }
           }
       }
    }
    # More than 1000€ in one order : 
    SELECT @count {} FROM UserPoint
    WHERE activity_events { 
        order { 
            order_products @ScoreField(name: "price") @ScoreAvg(min: 1000) { 
                category="IT" 
            }
        }
    }
    
    # More than 1000€ in cross orders : 
    SELECT @count {} FROM UserPoint
    WHERE activity_events @ScoreAvg(min : 1000) {
        order { 
            order_products @ScoreField(name:"price") @ScoreSum(result:"score_value") {
                category="IT"
            }
        }
    }
    # More than 1000€ in cross orders in IT or Book category : 
    SELECT @count {} FROM UserPoint
    WHERE activity_events @ScoreSum(min : 1000) {
        order { 
            order_products @ScoreField(name:"price") @ScoreSum(result:"score_value") {
                category="IT"
                OR category="BOOK"
            }
        }
    }
    
    # Same result : 
    #Doesn't work yet
    SELECT @count {} FROM UserPoint
    WHERE activity_events @ScoreSum(min : 1000) {
        order { 
            order_products @ScoreField(name:"price") @ScoreSum(result:"score_value") {
                category="IT"
            },
            order_products @ScoreField(name:"price") @ScoreSum(result:"score_value") {
                category="BOOK"
            }
        }
    }
    
    # More than 1000€ in cross orders in only with product of IT or Book category : 
    # maximum of separately IT products and Book products is superior to 1000€
    SELECT @count {} FROM UserPoint
    WHERE activity_events @ScoreSum(min : 1000) {
        order { 
            order_products @ScoreField(name:"price") @ScoreSum(result:"score_value") {
                category="IT"
            }
            OR  order_products @ScoreField(name:"price") @ScoreSum(result:"score_value") {
                category="BOOK"
            }
        }
    }
    
    # More than 1000€ in cross orders of products in IT and products in Book category : 
    SELECT @count {} FROM UserPoint
    WHERE activity_events @ScoreSum(min : 1000) {
        order { 
            order_products @ScoreField(name:"price") @ScoreSum(result:"score_value") {
                category="IT"
                OR category="BOOK"
            }
        }
    }
    
    # More than 1000€ in cross orders in IT and Book category : 
    SELECT @count {} FROM UserPoint
    WHERE activity_events @ScoreSum(min : 1000) {
        order { 
            order_products @ScoreField(name:"price") @ScoreSum(result:"score_value") {
                category="IT"
            }
        }
    AND activity_events @ScoreSum(min : 1000) {
        order { 
            order_products @ScoreField(name:"price") @ScoreSum(result:"score_value") {
                category="BOOK"
            }
        }
    }
    
    # More than 1000€ in cross orders with at least 10 IT products and 10 BOOK products : 
    SELECT @count {} FROM UserPoint
    WHERE activity_events @ScoreSum(min : 1000) {
        order { 
            order_products @ScoreField(name: "amount") @ScoreSum(){
                category="IT"
                OR category="BOOK"
            } 
            AND order_products @ScoreSum(min: 10) {
                category="IT"
            } 
            AND order_products @ScoreSum(min: 10) {
                category="BOOK"
            }
        }
    }
    
    ### DUPLICATE WITH PREVIOUS QUERY
    # More than 1000€ in cross orders in IT or Book category with at least 10€ of each in each order: 
    SELECT @count {} FROM UserPoint
    WHERE activity_events @ScoreSum(min : 1000) {
        order { 
            order_products @ScoreField(name: "amount") @ScoreSum(){
                category="IT"
                OR category="BOOK"
            } 
            AND order_products @Scorefield(name: "amount") @ScoreSum(min: 10) {
                category="IT"
            } 
            AND order_products @Scorefield(name: "amount") @ScoreSum(min: 10) {
                category="BOOK"
            }
        }
    }
    type UserPoint  @TreeIndexRoot(index:"USER_INDEX") {
       id:ID!
       profiles:[UserProfile!]!
    }
    
    type UserProfile  {
       id:ID!
       birth_date:Date @TreeIndex(index:"USER_INDEX")
    }
    SELECT { id } 
    FROM UserPoint 
    WHERE profiles { birth_date IN ["now-18y/d", "now-19y/d", "now-20y/d", "now-21y/d", 
        "now-22y/d", "now-23y/d", "now-24y/d", "now-25y/d", "now-26y/d", "now-27y/d", "now-28y/d"]
    }
    SELECT { id } 
    FROM UserPoint 
    WHERE profiles { ( birth_date >= "now-18y/d" AND birth_date < "now+7d-18y" ) OR
    ( birth_date >= "now-19y/d" AND birth_date < "now+7d-19y" ) OR
    ( birth_date >= "now-20y/d" AND birth_date < "now+7d-20y" ) OR
    ( birth_date >= "now-21y/d" AND birth_date < "now+7d-21y" ) OR
    ( birth_date >= "now-22y/d" AND birth_date < "now+7d-22y" ) OR
    ( birth_date >= "now-23y/d" AND birth_date < "now+7d-23y" ) OR
    ( birth_date >= "now-24y/d" AND birth_date < "now+7d-24y" ) OR
    ( birth_date >= "now-25y/d" AND birth_date < "now+7d-25y" ) OR
    ( birth_date >= "now-26y/d" AND birth_date < "now+7d-26y" ) OR
    ( birth_date >= "now-27y/d" AND birth_date < "now+7d-27y" ) OR
    ( birth_date >= "now-28y/d" AND birth_date < "now+7d-28y" ) }
    type UserPoint  @TreeIndexRoot(index:"USER_INDEX") {
       id:ID!
       events:[UserEvent!]!
       activities:[UserActivity!]!
    }
    
    type UserActivity  {
       id:ID!
       events:[UserEvent!]!
    }
    
    type UserEvent  @Mirror(object_type:"UserEvent") {
       id:ID!
       event_name:String @Property(path:"$event_name") @TreeIndex(index:"USER_INDEX")
    }
    SELECT { events @filter(clause: "page_type == \"newsarticle\" AND page_category == \"actu\""){ url } } 
    FROM UserPoint 
    WHERE activities { ts >= "now-1d/d" }
    // This query returns
    [
      [
        {
          "events": [
            {
              "url": "xxx"
            }
          ]
        },
        {
          "events": []
        },
        {
          "events": [
              {
                "url": "xxx"
              },
              {
                "url": "xxx"
              },
              {
                "url": "xxx"
              }
            ]
        },
        {
          "events": []
        },
    //...
      ]
    ]
    SELECT { events @filter(clause: "page_type == \"newsarticle\" AND page_category == \"actu\""){ page_type page _category url } } 
    FROM UserPoint 
    WHERE activities { ts >= "now-1d/d" } AND events { page_type == "newsarticle" AND page_category == "actu" }
    // This query returns
    [
      [
        {
          "events": [
            {
              "page_type": "newsarticle",
              "page_category": "actu",
              "url": "xxx"
            }
          ]
        },
        {
          "events": [
            {
              "page_type": "newsarticle",
              "page_category": "actu",
              "url": "xxx"
            },
            {
              "page_type": "newsarticle",
              "page_category": "actu",
              "url": "xxx"
            },
            {
              "page_type": "newsarticle",
              "page_category": "actu",
              "url": "xxx"
            }
          ]
        }
      ]
    ]
    SELECT { activities { events @filter(clause: "page_type == \"newsarticle\" AND page_category == \"actu\""){ page_type page_category url } } }
    FROM UserPoint 
    WHERE activities { ts >= "now-1d/d" } AND events { page_type == "newsarticle" AND page_category == "actu" }
    [
      [
        {
          "activities": [
            {
              "events": [
                {
                  "page_type": "newsarticle",
                  "page_category": "actu",
                  "url": "xxx"
                },
                {
                  "page_type": "newsarticle",
                  "page_category": "actu",
                  "url": "xxx"
                },
                {
                  "page_type": "newsarticle",
                  "page_category": "actu",
                  "url": "xxx"
                }
              ]
            },
            {
              "events": []
            },
            {
              "events": [
                {
                  "page_type": "newsarticle",
                  "page_category": "actu",
                  "url": "xxx"
                }
              ]
            }
          ]
        }
      ]
    ]
    SELECT { activities @filter(clause: "events { page_type == \"newsarticle\" AND page_category == \"actu\"}"){ events { page_type page_category url } }
    FROM UserPoint 
    WHERE activities { ts >= "now-1d/d" } AND events { page_type == "newsarticle" AND page_category == "actu" }
    [
      [
        {
          "activities": [
            {
              "events": [
                {
                  "page_type": "newsarticle",
                  "page_category": "actu",
                  "url": "xxx"
                }
              ]
            },
            {
              "events": [
                {
                  "page_type": "newsarticle",
                  "page_category": "actu",
                  "url": "xxx"
                },
                {
                  "page_type": "newsarticle",
                  "page_category": "actu",
                  "url": "xxx"
                },
                {
                  "page_type": "newsarticle",
                  "page_category": "actu",
                  "url": "xxx"
                },
                {
                  "page_type": "video",
                  "page_category": "sport",
                  "url": "xxx"
                },
                {
                  "page_type": "video",
                  "page_category": "sport",
                  "url": "xxx"
                }
              ]
            }
        ]
    ]
    SELECT { activities @filter(clause: "events { page_type == \"newsarticle\" AND page_category == \"actu\"}"){ 
        events @filter(clause: "page_type == \"newsarticle\" AND page_category == \"actu\""){ page_type page_category url } } }
    FROM UserPoint 
    WHERE activities { ts >= "now-1d/d" } AND events { page_type == "newsarticle" AND page_category == "actu" }
    [
      [
        {
          "activities": [
            {
              "events": [
                {
                  "page_type": "newsarticle",
                  "page_category": "actu",
                  "url": "xxx"
                }
              ]
            },
            {
              "events": [
                {
                  "page_type": "newsarticle",
                  "page_category": "actu",
                  "url": "xxx"
                },
                {
                  "page_type": "newsarticle",
                  "page_category": "actu",
                  "url": "xxx"
                },
                {
                  "page_type": "newsarticle",
                  "page_category": "actu",
                  "url": "xxx"
                }
              ]
            }
        ]
    ]
    SELECT @filter{ activities { events @filter(clause: "page_type == \"newsarticle\" AND page_category == \"actu\""){ page_type page_category url } } }
    FROM UserPoint 
    WHERE activities { ts >= "now-1d/d" } AND events { page_type == "newsarticle" AND page_category == "actu" }
    [
      [
        {
          "activities": [
            {
              "events": [
                {
                  "page_type": "newsarticle",
                  "page_category": "actu",
                  "url": "xxx"
                }
              ]
            },
            {
              "events": [
                {
                  "page_type": "newsarticle",
                  "page_category": "actu",
                  "url": "xxx"
                },
                {
                  "page_type": "newsarticle",
                  "page_category": "actu",
                  "url": "xxx"
                },
                {
                  "page_type": "newsarticle",
                  "page_category": "actu",
                  "url": "xxx"
                }
              ]
            }
        ]
    ]
    SELECT @filter{ activities { id events @filter(clause: "page_type == \"newsarticle\" AND page_category == \"actu\""){ url } } }
    FROM UserPoint 
    WHERE activities { ts >= "now-1d/d" } AND events { page_type == "newsarticle" AND page_category == "actu" }
    [
      [
        {
          "activities": [
            {
              "events": [
                {
                  "url": "xxx"
                },
                "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
              ]
            },
            {
              "events": [],
              "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
            }
          ]
        }
      ]
    ]
    property
    type
    description

    operation

    Enum

    Either UPSERT or DELETE

    compartment_id

    String (Optional)

    First create the document import using the call below. You can also reuse a document import that was previously created

    Each user profile import you do will be a new execution of the document import created. Here is an example :

    When doing an UPSERT if you want to update existing profiles in your datamart you should use the update_strategy property.

    If you wish to perform targeted updates on existing profiles without overwriting the whole existing user profile object, you should use the PARTIAL_UPDATE or PARTIAL_DELETE values of the update_strategy property.

    There are 2 main usage for these strategies :

    1. Dealing with arrays of objects

    If you're dealing with arrays of objects, these strategies work together with two directives that should be defined on the schema of the datamart you are working on. In this case, you should first update the schema in order to include the directives.

    If you want to make targeted updates on a object that has "id-like" field that can be used to identify the object, use @UpdateStrategyKey

    • Mark the field with the directive inside the given object you would like to make updates on. The field that has the directive will serve to identify the given object based on the value of this field in the update request.

      • For example of where the directive is needed, see use cases #1 to #5 below.

    If you want to make targeted updates on a object that does not have a field that can be used to identify the object you should use @UpdateValueObject

    • Mark the object with the directive : send in the payload with the new value of the object and it will override the previous value.

      • For example of where the directive is needed, see use case #6 and #7 below.

    1. Dealing with objects

    When there are no arrays of objects involved, you can still use the PARTIAL_UPDATE but the no directive is necessary. For examples, check use cases #8 to #10.

    For a non mandatory value you can also set a given field to null (but not an object directly). For instance in the previous example you could have done the following :

    Schema related constraints :

    The update request must respect the datamart schema :

    • If a property is in the payload of the request but not declared in the schema, the whole request will fail. However, if a property is already present in the profile but not declared in the schema, it will not be overwritten by a partial update or delete. In fact it will not be possible to update such property unless using FORCE_REPLACE

    • If the types of the properties in the payload of the request do not respect the schema, the whole request will fail.

    Limitations :

    • If a property in the schema has a directive such as @Property(path: “[parent].property”) (referencing [parent] in path) : this property cannot be updated with the partial update

    • Updatable properties cannot be computed values such as : computed field, ML function, results of function.

    • @UpdateValueObject cannot be used with @UpdateStrategyKey in the same object

    When importing user profiles using UPSERT, if you wish to update existing profiles by completely overwriting the existing profiles you should use the FORCE_REPLACE value of the update_strategy property: the user profile will be completely replaced by the object passed in the user_profile property.

    property
    type
    description

    force_replace

    Boolean (Optional)

    Mandatory when the operation is UPSERT. If true, then the User Profile will be completely replaced by the object passed in the user_profile field. If false, the object passed in the user_profile field will be merged with the existing User Profile of the UserPoint.

    merge_objects

    Boolean (Optional)

    More details on merge_objects behavior :

    How-to

    You can, of course, upload multiple user profiles at once. Note the uploaded data is in ndjson and not json. That means the different profiles are not separated by commas, but by a line separator \n

    User profile import command

    user profiles
    bulk import
    document import
    execution
    curl -X POST \
      https://api.mediarithmics.com/v1/datamarts/<DATAMART_ID>/document_imports \
      -H 'Authorization: <YOUR_API_TOKEN>' \
      -H 'Content-Type: application/json' \
      -d '{
    	"document_type": "USER_PROFILE",
    	"mime_type": "APPLICATION_X_NDJSON",
    	"encoding": "utf-8",
    	"name": "<YOUR_DOCUMENT_IMPORT_NAME>"
    }'
    # Here we use the combination of compartment_id and user_account_id acting as identifier
    curl -X POST \
      https://api.mediarithmics.com/v1/datamarts/<DATAMART_ID>/document_imports/<DOCUMENT_IMPORT_ID>/executions \
      -H 'Authorization: <API_TOKEN>' \
      -H 'Content-Type: application/x-ndjson' \
      -d '{ 
            "operation": "UPSERT",
            "compartment_id": "<COMPARTMENT_ID>", 
            "user_account_id": "<USER_ACCOUNT_ID>",
            "user_profile": {
                  this": "is",
                  "a":"test"
            }
          }'
    # Schema extract
    
    type UserProfile {
       compartment_id : String!
       user_account_id : String
       loyalty: [Loyalty]
    }
    
    type Loyalty {
       cards : [Cards]
    }
    
    type Cards {
       card_id: String! @UpdateStrategyKey
       benefits: String
       last_visit_date: String
    }
    // Existing profile
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "loyalty": {
        "cards": [
          {
            "card_id": "abc",
            "benefits": 500,
            "last_visit_date": "2024-01-01"
          }
        ]
      }
    }
    
    //Profile in update payload with update_strategy == PARTIAL_UPDATE
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "loyalty": {
        "cards": [ //adding a new cards object
          {
            "card_id": "def",
            "benefits": 100,
            "last_visit_date": "2025-01-01"
          }
        ]
      }
    }
    
    //New profile
    
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "loyalty": {
        "cards": [ // the cards object contains both cards
          {
            "card_id": "abc",
            "benefits": 500,
            "last_visit_date": "2024-01-01"
          },
          {
            "card_id": "def",
            "benefits": 100,
            "last_visit_date": "2025-01-01"
          }
        ]
      }
    }
    # Schema extract
    
    type UserProfile {
       compartment_id : String!
       user_account_id : String
       loyalty: [Loyalty]
    }
    
    type Loyalty {
       cards : [Cards]
    }
    
    type Cards {
       card_id: String! @UpdateStrategyKey
       benefits: String
       last_visit_date: String
    }
    // Existing profile
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "loyalty": {
        "cards": [
          {
            "card_id": "abc",
            "benefits": 500,
            "last_visit_date": "2024-01-01"
          }
        ]
      }
    }
    
    //Profile in update payload with update_strategy == PARTIAL_UPDATE
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "loyalty": {
        "cards": [ //request changing the benefits value of the existing card
          {
            "card_id": "abc", // value of the field marked with @UpdateStrategyKey of the inner object to update
            "benefits": 100
          }
        ]
      }
    }
    
    //New profile
    
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "loyalty": {
        "cards": [ // 
          {
            "card_id": "abc",
            "benefits": 100, // value has been updated
            "last_visit_date": "2024-01-01"
          }
        ]
      }
    }
    // Extract of existing profile
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "my_array_of_scalars": [1,2,3],
      ...
    }
    
    //Profile in update payload with update_strategy == PARTIAL_UPDATE
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "my_array_of_scalars": [4,5,6],
      ...
    }
    
    //New profile
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "my_array_of_scalars": [4,5,6], // the value of the property has been replaced by the new value
      ...
    }
    
    # Schema extract
    
    type UserProfile {
       compartment_id : String!
       user_account_id : String
       loyalty: [Loyalty]
    }
    
    type Loyalty {
       cards : [Cards]
    }
    
    type Cards {
       card_id: String! @UpdateStrategyKey
       benefits: String
       last_visit_date: String
    }
    // Existing profile
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "loyalty": {
        "cards": [
          {
            "card_id": "abc",
            "benefits": 500,
            "last_visit_date": "2024-01-01"
          }
        ]
      }
    }
    
    //Profile in update payload with update_strategy == PARTIAL_UPDATE
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "loyalty": {
        "cards": [ 
          {
            "card_id": "abc",
            "benefits": null // set the value to null
          }
        ]
      }
    }
    
    //New profile
    
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "loyalty": {
        "cards": [ // benefits value has been cleared
          {
            "card_id": "abc",
            "last_visit_date": "2024-01-01"
          }
        ]
      }
    }
    # Schema extract
    
    type UserProfile {
       compartment_id : String!
       user_account_id : String
       loyalty: [Loyalty]
    }
    
    type Loyalty {
       cards : [Cards]
    }
    
    type Cards {
       card_id: String! @UpdateStrategyKey
       benefits: String
       last_visit_date: String
    }
    // Existing profile
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "loyalty": {
        "cards": [
          {
            "card_id": "abc",
            "benefits": 500,
            "last_visit_date": "2024-01-01"
          }
        ]
      }
    }
    
    //Profile in update payload with update_strategy == PARTIAL_UPDATE
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "loyalty": {
        "cards": [ 
          {
            "card_id": "abc",
            "benefits": 100 //updating exsisting object
          },
          {
            "card_id": "def", //adding a new object
            "benefits": 600,
            "last_visit_date": "2025-01-01"
          }
        ]
      }
    }
    
    //New profile
    
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "loyalty": {
        "cards": [
          {
            "card_id": "abc",
            "benefits": 100, // value has been updated
            "last_visit_date": "2024-01-01"
          },
          {
            "card_id": "def", // object has been added
            "benefits": 600,
            "last_visit_date": "2025-01-01"
          }
        ]
      }
    }
    # Schema extract
    
    type UserProfile {
       compartment_id : String!
       user_account_id : String
       loyalty: [Loyalty]
    }
    
    type Loyalty {
       cards : [Cards]
    }
    
    type Cards {
       card_id: String! @UpdateStrategyKey
       benefits: String
       last_visit_date: String
    }
    //Existing profile
    
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "loyalty": {
        "cards": [
          {
            "card_id": "abc",
            "benefits": 100,
            "last_visit_date": "2024-01-01"
          },
          {
            "card_id": "def",
            "benefits": 600,
            "last_visit_date": "2025-01-01"
          }
        ]
      }
    }
    
    //Profile in update payload with update_strategy == PARTIAL_DELETE
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "loyalty": {
        "cards": [ 
          {
            "card_id": "abc" // value of the field marked with @UpdateStrategyKey of the inner object to delete
          }
        ]
      }
    }
    
    //New profile
    
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "loyalty": {
        "cards": [ // the card with card_id = "abc" has been deleted
          {
            "card_id": "def",
            "benefits": 600,
            "last_visit_date": "2025-01-01"
          }
        ]
      }
    }
    
    # Schema extract
    
    type UserProfile {
       compartment_id : String!
       user_account_id : String
       segmentations: [Segmentation]
    }
    
    type Segmentation @UpdateValueObject {
       type: String
       label: String
    }
    //Existing profile
    
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "segmentations": [
        { "type": "segRFM", "label": "seg1" },
        { "type": "segRFM", "label": "seg2" }
      ]
    }
    
    //Profile in update payload with update_strategy == PARTIAL_UPDATE
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "segmentations": [ // contains the new value of the object
        { "type": "segOther", "label": "seg3" },
        { "type": "segOther", "label": "seg4" }
      ]
    }
    
    //New profile
    
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "segmentations": [ //full array of objects was replaced
        { "type": "segOther", "label": "seg3" },
        { "type": "segOther", "label": "seg4" }
      ]
    }
    
    # Schema extract
    
    type UserProfile {
       compartment_id : String!
       user_account_id : String
       geolocation: Geolocation
    }
    
    type Geolocation @UpdateValueObject {
       address: String
       city: String
       postal_code : String
    }
    //Existing profile
    
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "geolocation": 
        { "address": "1 first avenue", 
          "city": "new york",
          "postal_code" :"0101" 
        }
    }
    
    //Profile in update payload with update_strategy == PARTIAL_UPDATE
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "geolocation": 
        { "address": "1 first avenue", 
          "city": "new york"
        }
    }
    
    //New profile
    
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "geolocation": 
        { "address": "1 first avenue", 
          "city": "new york"
        }
    }
    
    # Schema extract
    
    type UserProfile {
       compartment_id : String!
       user_account_id : String
       first_name: String
       last_name : String
    }
    //Existing profile
    
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "first_name" : "john"
      "last_name" : "doe"
    }
    
    //Profile in update payload with update_strategy == PARTIAL_UPDATE
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "first_name" : null
      "last_name" : "smith"
    }
    
    //New profile
    
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "last_name" : "smith"
    }
    
    # Schema extract
    
    type UserProfile {
       compartment_id : String!
       user_account_id : String
       geo_location: GeoLocation
    }
    
    type GeoLocation {
       address: String
       postal_code: String
       city: String
       country: String
    }
    //Existing profile
    
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "geo_location": {
        "address": "1 main street",
        "city": "paris",
        "postal_code" : "0001",
        "country" : "France"
      }
    }
    
    //Profile in update payload with update_strategy == PARTIAL_UPDATE
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
     "geo_location": {
        "address": null,
        "city": "New york",
      }
    }
    
    //New profile
    
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "geo_location": {
        "city": "new york",
        "postal_code" : "0001",
        "country" : "France"
      }
    }
    
    # Schema extract
    
    type UserProfile {
       compartment_id : String!
       user_account_id : String
       geo_location: GeoLocation
    }
    
    type GeoLocation {
       address: String
       postal_code: String
       city: String
       country: String
    }
    //Existing profile
    
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "geo_location": {
        "address": "1 main street",
        "city": "paris",
        "postal_code" : "0001",
        "country" : "France"
      }
    }
    
    //Profile in update payload with update_strategy == PARTIAL_UPDATE
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
     "geo_location": {
        "address": "52 fifth avenue",
        "city": "New York City",
        "postal_code" : "12345",
        "country" : "USA"
      }
    }
    
    //New profile
    
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "geo_location": {
        "address": "52 fifth avenue",
        "city": "New York City",
        "postal_code" : "12345",
        "country" : "USA"
      }
    }
    
    #This is allowed
    type LoyaltyCard {
      card_id:String @UpdateStrategyKey
      benefits: Int
      last_visit_date: String
      other_information : [OtherInformation]
    }
    type OtherInformation {
    	info_id: String @UpdateStrategyKey
    }
    
    ################################
    
    #This is not allowed
    type LoyaltyCard {
      card_id:String @UpdateStrategyKey
      benefits: Int @UpdateStrategyKey
      last_visit_date: Date  
    }
    
    # Stored profile:
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "loyalty": {
        "cards": [
          {
            "benefits": 200,
            "card_id": "abc",
            "last_visit_date": "2024-01-01"
          }
        ]
      }
    }
    
    
    # New profile in request payload
    curl -X POST \
      https://api.mediarithmics.com/v1/datamarts/<DATAMART_ID>/document_imports/<DOCUMENT_IMPORT_ID>/executions \
      -H 'Authorization: <API_TOKEN>' \
      -H 'Content-Type: application/x-ndjson' \
      -d '{ 
            "operation": "UPSERT",
            "compartment_id": "<COMPARTMENT_ID>", 
            "user_account_id": "<USER_ACCOUNT_ID>",
            "update_strategy": "FORCE_REPLACE",
            "user_profile": {
              "compartment_id": "<COMPARTMENT_ID>",
              "user_account_id": "<USER_ACCOUNT_ID>",
              "loyalty": {
                "cards": [
                  {
                    "benefits": 500,
                    "card_id": "xyz",
                    "last_visit_date": "2025-01-01"
                  }
                ]
              }
            }
          }'
    
    # New saved profile:
    {
      "compartment_id": "<COMPARTMENT_ID>",
      "user_account_id": "<USER_ACCOUNT_ID>",
      "loyalty": {
        "cards": [
          {
            "benefits": 500,
            "card_id": "xyz",
            "last_visit_date": "2025-01-01"
          }
        ]
      }
    }
    # Stored profile:
    {
      "my_property_1": "value1",
      "my_property_2": "value1",
      "my_array_property": ["value1"]
      "my_array_object_property": [
        {
          "my_sub_array_object_property_1": "value1",
          "my_sub_array_object_property_2": "value1"
        }
      ],
      "my_object_property": {
        "my_sub_object_property_1": "value1",
        "my_sub_object_property_2": "value1"
      }    
    }
    
    
    # New profile in request payload
    curl -X POST \
      https://api.mediarithmics.com/v1/datamarts/<DATAMART_ID>/document_imports/<DOCUMENT_IMPORT_ID>/executions \
      -H 'Authorization: <API_TOKEN>' \
      -H 'Content-Type: application/x-ndjson' \
      -d '{ 
            "operation": "UPSERT",
            "compartment_id": "<COMPARTMENT_ID>", 
            "user_account_id": "<USER_ACCOUNT_ID>",
            "force_replace": false,
            "merge_objects": true,
            "user_profile": {
              "my_property_2": "value2",
              "my_property_3": "value3",
              "my_array_property": ["value2"]
              "my_array_object_property": [
                {
                  "my_sub_array_object_property_2": "value2"
                  "my_sub_array_object_property_3": "value3"
                }
              ],
              "my_object_property": {
                "my_sub_object_property_2": "value2"
                "my_sub_object_property_3": "value3"
              }    
            }
          }'
    
    # New saved profile:
    {
      "my_property_1": "value1",
      "my_property_2": "value2", # override scalar property
      "my_property_3": "value3",
      "my_array_property": ["value1","value2"] # merge arrays
      "my_array_object_property": [ # merge arrays
        {
          "my_sub_array_object_property_1": "value1"
          "my_sub_array_object_property_2": "value1"
        },
        {
          "my_sub_array_object_property_2": "value2"
          "my_sub_array_object_property_3": "value3"
        }
      ],
      "my_object_property": { # merge objects
        "my_sub_object_property_1": "value1"
        "my_sub_object_property_2": "value2" # override scalar property within object
        "my_sub_object_property_3": "value3"
      }    
    }

    When importing profiles with identifiers, only one identifier is allowed per line. For example, you shouldn't specify the user agent ID if the Email Hash is already used in a line.

    Example

    Available update strategies when updating existing user profiles

    PARTIAL_UPDATE and PARTIAL_DELETE

    You should use only one of the directive in a given object

    #1 - Add an object in array of objects - PARTIAL_UPDATE using the @UpdateStrategyKey directive

    #2 - Update a property in an array of objects - PARTIAL_UPDATE using the @UpdateStrategyKey directive

    Remark : arrays of scalar values are treated as scalars. See example below :

    #3 - Delete a property inside an array of objects - PARTIAL_UPDATE using the @UpdateStrategyKey directive

    #4 - Update object inside an array and add new object - PARTIAL_UPDATE using the @UpdateStrategyKey directive

    #5 - Delete an object in an array of objects - PARTIAL_DELETE using the @UpdateStrategyKey directive

    If you wish to delete a specific property value inside an object, you should use PARTIAL_UPDATE. Please refer to use case #3.

    #6 - Override an array of objects - PARTIAL_UPDATE using the @UpdateValueObject directive

    #7 - Override an object - PARTIAL_UPDATE using the @UpdateValueObject directive

    #8 - Update properties inside the UserProfile - PARTIAL_UPDATE with no directive

    #9 - Update a property inside an object - PARTIAL_UPDATE with no directive

    #10 - Override an object - PARTIAL_UPDATE with no directive

    Constraints and limitations

    • It is possible to define a hierarchy of inner objects while using @UpdateStrategyKey at each level

    • However, @UpdateStrategyKey should only be set to one property inside a given object

    FORCE_REPLACE

    Legacy parameters

    The Compartment ID, acting as a user identifier in correlation with user_account_id

    user_account_id

    String (Optional)

    The User Account ID, acting as an identifier in correlation with compartment_id

    email_hash

    String (Optional)

    The Email Hash, acting as an identifier

    user_agent_id

    String (Optional)

    The User Agent ID, acting as an identifier

    update_strategy

    Enum (Optional)

    Only considered when operation == UPSERT Values are PARTIAL_UPDATE, PARTIAL_DELETE, FORCE_REPLACE

    user_profile

    JSON Object (Optional)

    Mandatory when operation == UPSERT.

    JSON Object representing the User Profile. Please refer to the user profile object for more information.

    Only considered if force_replace is false.

    Manage the comportement between two objects with a same property.

    If false (default value), the new object overrides the existing one.

    If true the new object is merged in deep to the existing one (see example).

    Datamart replication

    The datamart replication feature allows you to replicate the data ingested by mediarithmics in an external solution of your choice. For now, we are integrated with:

    • Google Cloud Platform - Pub/Sub

    • Microsoft Azure - Event Hubs (Alpha)

    This module is not included in the default plan. Contact your Account manager to activate it.

    How it works

    Replication

    We replicate the update and delete operations from your for the following objects:

    • (for datamart user_point_system_version before v202205)

    • (for datamart

    When creating a datamart replication, you can select which object(s) to replicate.

    There are currently 2 versions of Datamart replications:

    Version
    Format
    Supported destination

    Your replication can be in one of the following status:

    • ACTIVE: All data processed by your datamart will be replicated to your external solution.

    • PAUSED: No data processed by your datamart will be replicated to your external solution.

    • ERROR: The system is no longer able to replicate messages. In this case, check your external solution (expired instance, invalid credentials, etc). If you can't find anything wrong, please contact your Account manager.

    You can run an initial synchronization for one or multiple ACTIVE datamart replications. This operation replicates all existing documents selected in the datamart replication and stored within the mediarithmics platform into your cloud environment.

    Depending on your needs, you have several ways to trigger an initial synchronization:

    For a single datamart replication:

    1. Locate the replication in the list.

    2. Click the caret-down icon, then select New Initial Synchronization.

    For multiple datamart replications:

    1. Click the New Initial Synchronization button.

    2. Select the datamart replications you want to synchronize.

    3. Click Execute Initial Synchronization(s).

    All selected datamart replications will receive a set of UPDATE operations representing all existing elements (for example, UserProfile) in your datamart.

    We convert datamart operations in a standardized output format: operation = {ts, doc_type, doc_id, op, value}

    Field
    Type
    Comment
    Version availability

    To help filtering the topic, replication adds some metadata on message (attributes in PubSub and properties in EventHub)

    Metadata key
    Comment

    This format is the original replication format. It was designed to work with a streaming architecture (like Dataflow or Databricks) but has some limitations with tools needing a schema (like BigQuery)

    A new activity will trigger a replicated UserActivity operation. You will receive a similar message in your external solution as shown in this example.

    A new user agent will trigger a replicated UserAgent operation like the one bellow

    A new user device point will trigger a replication UserDevicePoint operation like the one bellow

    A new user device technical id will trigger a replicated UserDeviceTechnicalId operation like the ones bellow

    This version introduce a schema to help integration.

    This format is almost the same as Legacy one, but with Avro binary format.

    For datamarts with user_point_system_version anterior to v202205, device identifiers are stored as , and replicated as UserAgent operations (doc_id exemple: 4700c85f-17e3-4304-aa7f-dc140173b08d:vec:32453299893).

    However for datamarts leveraging the user_point_system_version v202205, device identifiers are stored as , and replicated through UserDevicePoint and UserDeviceTechnicalId operations.

    In the case of a datamart that is upgraded to theuser_point_system_version v202205:

    • New device identifiers are directly stored and replicated using the device point formats,

    • Existing device identifiers that were previously stored in the UserAgent format are progressively migrated.

    This migration is seemless within the datamart, however it is reflected on your datamart replication. For each migrated device identifier, you will receive:

    • A DELETE operation with the doc_type User Agent

    • Two UPDATE operations with doc_type UserDevicePoint and doc_type UserDeviceTechnicalId

    After migration, no more UserAgent operations will be produced

    You need to have an instance of the external solution where you want to replicate your mediarithmics data.

    Depending on the external solution, you will need to fulfill some requirements.

    You will need:

    • A Google Cloud Platform account

    • A Google Cloud Platform project: ;

    • An Access Control on this project: ;

    Click on Create Service Account :

    Give your service account a name, select the right account access (Pub/Sub Publisher, Pub/Sub Editor) and save.

    Once your Service Account is created, you can generate your key :

    credentials.json file example:

    • To create a Google Cloud Platform Pub/Sub instance. Pub/Sub documentation: until Quickstart setup > Create service account credentials (included) should be enough to begin.

    NOTE: Here is the Google Pub/Sub Pricing documentation:

    You will need:

    • A Microsoft Azure account

    • A Resource Group, an Event Hubs namespace, and an Event Hub:

    • A connection string over the namespace or the Event Hub:

    credentials.txt file example:

    NOTE: Here is the Microsoft Azure Event Hubs Pricing documentation:

    You can access replications in the datamart settings in your navigator application.

    1. Select the organisation on which there is the datamart you want to replicate.

    2. Click on Settings.

    3. Click on the Datamarts tab and then click the Datamart menu entry.

    To create a new replication:

    1. Go to the subtab.

    2. Click New Replication.

    3. Select a Replication type matching the external solution of your choice.

    example for Google Pub/Sub :

    You can change the replication status using the status button.

    If the system is no longer able to replicate the messages, the replication status will be set to ERROR. In this case, check your external solution (expired instance, invalid credentials, etc). If you can't find anything wrong, please contact your Account manager.

    A dashboard listing every Initial Synchronization that was done on your datamart is available in the same Replications subtab.

    For now, you will have to ask your Account manager to run an initial synchronization. Later, you will be able to run an initial synchronization yourself by clicking New Execution. You must have at least one active replication and you can't run an initial synchronization more than once a week.

    While an initial synchronization is running, you can't change the status of your replications. The initial synchronization will only replicate the data for active replications.

    The active replications are still running during initial synchronizations. Messages from the initial synchronization and live messages (tag, import, etc.) from the active replications are mixed.

    POST https://api.mediarithmics.com/v1/datamarts/:datamartId/replications

    Name
    Type
    Description
    Name
    Type
    Description

    POST https://api.mediarithmics.com/v1/datamarts/:datamartId/replications/:replicationId/credentials

    Name
    Type
    Description
    Name
    Type
    Description

    GET https://api.mediarithmics.com/v1/datamarts/:datamartId/replications/:replicationId

    Name
    Type
    Description

    POST https://api.mediarithmics.com/v1/datamarts/:datamartId/replication_job_executions

    Name
    Type
    Description
    Name
    Type
    Description
    user_point_system_version
    v202205)
  • UserDeviceTechnicalId (for datamart user_point_system_version v202205)

  • UserActivity

  • UserSegment

  • UserProfile

  • UserAccount

  • UserEmail

  • Parent UserPoint (when UserPoint are merging)

  • Enumeration

    The object type :UserActivity, UserProfile, UserSegment, UserAgent, UserAccount, UserEmail, UserPoint or UserPointParent

    All

    ctx_id

    UUID

    The userpoint id

    Version 2

    doc_id

    String

    The object unique id. depending on doc_type

    All

    op

    String

    The operation type UPDATE or DELETE

    All

    value

    JSON Object

    The object value. depending on doc_type.

    All

    Browser info and device info

    UserDevicePoint

    {{user_point_id}}:{{user_device_point_id}}

    Browser info and device info

    UserDeviceTechnicalId

    {{user_point_id}}:{{user_device_point_id}}:{{user_device_technical_id}}

    Empty (you already have the user_device_technical_id in the doc_id)

    UserActivity

    {{user_point_id}}:{{user_activity_id}}

    Detailed activity

    UserSegment

    {{user_point_id}}:{{segment_id}}

    Segment info

    UserProfile

    {{user_point_id}}:{{compartment_id}}:{{user_account_id}}

    Detailed profile

    UserAccount

    {{user_point_id}}:{{compartment_id}}:{{user_account_id}}

    Empty (you already have the user_account_id in the doc_id)

    UserEmail

    {{user_point_id}}:{{email_hash}}

    User's email hash

    UserPointParent

    {{user_point_id}}

    It is the ID of the UserPoint which is merged on the oldest one (the kept one).

    Message <current_user_point_id> merged with <the_kept_user_point_id>

    To create and activate your service accounts (generate credentials file): https://cloud.google.com/iam/docs/understanding-service-accounts https://cloud.google.com/compute/docs/access/create-enable-service-accounts-for-instances

    TO SUM IT UP: You can click here https://console.cloud.google.com/iam-admin/serviceaccounts, create a service account, and edit it to create a Key in a JSON format (this is the credential file);

    Save your connection string in a credentials.txt file. It would be your credentials file to upload in mediarithmics platform.

    Select the datamart you want to replicate.

  • In the Replications subtab, you will see a table dedicated to your Datamart Replications.

  • Complete configuration information (see Prerequisites as help to configure advanced fields).

  • Click Select a File to upload your credentials file and click on Update.

  • Click Save Replication to create your new replication.

  • You will see your new replication in the Replications subtab.

  • status

    string

    Status of the replication. Need to be "PAUSED" at the creation

    type

    string

    GOOGLE_PUBSUB or AZURE_EVENT_HUBS

    project_id

    string

    Google project ID. Only for GOOGLE_PUBSUB

    topic_id

    string

    Google PubSub topic ID.Only for GOOGLE_PUBSUB

    event_hub_name

    string

    Azure event hub name. Only for AZURE_EVENT_HUBS

    datamart_id

    string

    As per the Path parameter

    replication_filters

    array

    Optional.

    List of documents to replicate. If not provided, all documents will be replicated

    replication_filters > document

    string

    Name of the document to replicate among USER_SEGMENT, USER_EMAIL, USER_ACCOUNT, USER_PROFILE, USER_DEVICE_POINT, USER_AGENT, USER_DEVICE_TECHNICAL_ID, USER_ACTIVITY, USER_POINT

    replication_filters > filter

    string

    Not used at the moment

    Version 1 (Legacy)

    JSON format

    Google Cloud Platform - Pub/Sub Microsoft Azure - Event Hubs

    Version 2

    Avro Binary format

    Google Cloud Platform - Pub/Sub

    ts

    UNIX Timestamp in ms (Long)

    The mutation date

    All

    doc_type

    doc_id

    value

    UserPoint

    {{user_point_id}}

    Empty (you already have the user_point_id in the doc_id)

    UserAgent

    doc_type

    The message doc_type

    {
       "ts": 1676627112685,
       "doc_type": "UserActivity",
       "doc_id": "XXXXXXX-XXXX-XXX-XXXXXXXX:XXXXXX-XXXXX-XXXX-XXXX-XXXXXXXXXX",
       "op":" UPDATE",
       "value":{
           "$type":"SITE_VISIT",
           "$source":"XXXX",
           "etc": "etc"
       }
    }
    {
       "ts":1676627112685,
       "doc_type":"UserAgent",
       "doc_id":"4700c85f-17e3-4304-aa7f-dc140173b08d:vec:32453299893",
       "op":"UPDATE",
       "value":{
          "$os_family":"LINUX",
          "$brand":null,
          "$os_version":null,
          "$form_factor":"PERSONAL_COMPUTER",
          "$carrier":null,
          "$model":null,
          "$creation_ts":0,
          "$browser_family":"FIREFOX"
       }
    }
    {
       "ts":1676627112685,
       "doc_type":"UserDevicePoint",
       "doc_id":"4700c85f-17e3-4304-aa7f-dc140173b08d:udp:-32453299893",
       "op":"UPDATE",
       "value":{
          "$os_family":"LINUX",
          "$brand":null,
          "$os_version":null,
          "$form_factor":"PERSONAL_COMPUTER",
          "$carrier":null,
          "$model":null,
          "$creation_ts":0,
          "$browser_family":"FIREFOX"
       }
    }
    // exemple with a MumId 
    {
       "ts":1676627112685,
       "doc_type":"UserDeviceTechnicalId",
       "doc_id":"4700c85f-17e3-4304-aa7f-dc140173b08d:udp:-32453299893:mum:7231822539",
       "op":"UPDATE",
       "value":{}
    }
    
    // exemple with an installationId
    {
       "ts":1676627112685,
       "doc_type":"UserDeviceTechnicalId",
       "doc_id":"4700c85f-17e3-4304-aa7f-dc140173b08d:udp:-32453299893:ins:1001:aZmFhOTVlM2ItMGRhOC00NDZlLWFhODMtNjZlZGI0YjNiNTk2",
       "op":"UPDATE",
       "value":{}
    }
    {
      "type": "record",
      "name": "OperationRecord",
      "namespace": "com.mediarithmics.replication.format",
      "fields": [
        {
          "name": "ts",
          "type": {
            "type": "long",
            "logicalType": "timestamp-micros"
          }
        },
        {
          "name": "doc_type",
          "type": {
            "name": "DocumentType",
            "type": "enum",
            "symbols": [
              "UserPoint",
              "UserActivity",
              "UserProfile",
              "UserSegment",
              "UserDevicePoint",
              "UserDeviceTechnicalId",
              "UserAgent",
              "UserAccount",
              "UserEmail"
            ]
          }
        },
        {
          "name": "doc_id",
          "type": "string",
          "doc": "It will always start with the ctx_id (ie: user_point) followed by ':' and other internal ids. It identifies uniquely a document."
        },
        {
          "name": "ctx_id",
          "type": {
            "type": "string",
            "logicalType": "uuid"
          },
          "doc": "The UserPoint id"
        },
        {
          "name": "op",
          "type": "string",
          "doc": "UPDATE or DELETE"
        },
        {
          "name": "value",
          "type": "string",
          "doc": "The object in JSON format"
        }
      ]
    }
    {
      "type": "service_account",
      "project_id": "xxx-xxx-xx",
      "private_key_id": "xxxxxxx",
      "private_key": "-----BEGIN PRIVATE KEY-----\n xxxxxxx \n-----END PRIVATE KEY-----\n",
      "client_email": "xxx@project_id.iam.gserviceaccount.com",
      "client_id": "xxxxxx",
      "auth_uri": "https://accounts.google.com/o/oauth2/auth",
      "token_uri": "https://oauth2.googleapis.com/token",
      "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
      "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/projetc_id.iam.gserviceaccount.com"
    }
    Endpoint=sb://<FQDN>/;SharedAccessKeyName=<KeyName>;SharedAccessKey=<KeyValue>

    datamartId

    integer

    The ID of the datamart

    version

    integer

    Version of the datamart replication to be created. Check Versionning for more info.

    name

    string

    The name of the API Token

    {
    	"status": "PAUSED",
    	"name": ,
    	"project_id": "test",				
    	"topic_id": "test",
    	"datamart_id": "1649",
    	"type": "GOOGLE_PUBSUB",		 
    	"replication_filters": [{
    		"document": "USER_SEGMENT",
    		"filter": null,
    	}, {
    		"document": "USER_ACCOUNT",
    		"filter": null,
    	}, { … }]
    }
    

    datamartId

    integer

    The ID of the datamart

    replicationId

    integer

    The ID of the datamart replication

    file

    form

    The path of the file that contain the credentials

    curl --location 'https://api.mediarithmics.com/v1/datamarts/:datamartID/replications/:replicationID/credentials' \
    --header 'Authorization: api:XXX' \
    --form 'file=@"/XXX/service-account.json"'

    datamartId

    integer

    The ID of the datamart

    replicationId

    integer

    The ID of the datamart replication

    {
    	"id": "1234",
    	"version" 2,
    	"status": "PAUSED",
    	"name": ,
    	"project_id": "test",				
    	"topic_id": "test",
    	"datamart_id": "1649",
    	"type": "GOOGLE_PUBSUB",	
    	"credentials_uri": "internal_path_to_credential_uri"	 
    	"replication_filters": [{
    		"id": "1",
    		"replication_id": "1234",
    		"document": "USER_SEGMENT",
    		"filter": null,
    	}, {
    		"id": "2",
    		"replication_id": "1234",
    		"document": "USER_ACCOUNT",
    		"filter": null,
    	}, { … }]
    }
    

    datamartId

    integer

    The ID of the datamart

    replication_ids

    integer

    The IDs of the replication

    {
    	"replication_ids": ["123", "456"]
    }

    Object filtering

    Note that you cannot update the objects selection once set. You will need to create a new datamart replication in that case.

    Versionning

    Please note that:

    • Any new GCP Pub/Sub replication will be created in Version 2

    • You cannot upgrade a datamart replication from Version 1 to Version 2

    Replication status

    Initial synchronization

    Please note that if you run an initial synchronization you might receive a large volume of messages. Processing them can be expensive, depending on your cloud provider.

    Output messages

    Object formats based on doc_type

    Message metadata

    Legacy JSON Format

    Examples

    Avro Binary Format

    The target topic should reference the schema and the encoding as BINARY to take full advantages of the format.

    Upgrade of datamarts to user_point_system_version v202205

    For instance, a migration of a user agent with a doc_id 4700c85f-17e3-4304-aa7f-dc140173b08d:vec:7231822539 will produce

    • 1 DELETE operation with doc_type UserAgent the same doc_id

    • 2 UPDATE operations:

      • 1 with doc_type UserDevicePoint and the following doc_id: 4700c85f-17e3-4304-aa7f-dc140173b08d:udp:-32453299893

      • 1 with doc_type UserDeviceTechnicalId and the following doc_id 4700c85f-17e3-4304-aa7f-dc140173b08d:udp:-32453299893:mum:7231822539

    Setting up replications

    Prerequisites

    Google Pub/Sub

    Microsoft Azure Event Hubs (Alpha)

    Listing your replications

    Creating & starting a replication

    When a Replication is created, its status is automatically set to Paused. To start your replication, you will have to activate it. If the system can't replicate your datamart on activation, you will see an error.

    When a replication can't be activated, it is usually due to an error on credentials, so you might want to verify your replication configuration and your credentials file first.

    Activating / pausing a replication

    In case of an error with your external solution, you will need to recreate your replication to rebind it to a new working external solution with good credentials and the right specific information.

    Executing an initial synchronization

    We replicate all operations. No filtering is possible.

    Please note that you might receive a large volume of messages while running an initial synchronization. Processing them can be expensive, depending on your cloud provider.

    API documentation

    Create a replication

    Path Parameters

    Request Body

    Add credentials to replication

    Path Parameters

    Request Body

    Curl example

    Retrieve a replication

    Path Parameters

    Launch initial synchronization on one replication

    Path Parameters

    Request Body

    Datamart
    UserPoint
    UserAgent
    UserDevicePoint
    User Agents
    User Device Points and User Device Technical Ids
    https://cloud.google.com/resource-manager/docs/creating-managing-projects
    https://cloud.google.com/resource-manager/docs/access-control-proj
    https://cloud.google.com/pubsub/docs/quickstart-py-mac
    https://cloud.google.com/pubsub/pricing
    https://docs.microsoft.com/en-us/azure/event-hubs/event-hubs-create
    https://docs.microsoft.com/en-us/azure/event-hubs/event-hubs-get-connection-string
    https://azure.microsoft.com/en-us/pricing/details/event-hubs/
    Replications

    doc_type

    {{user_point_id}}:{{vector_id}}

    The format varies
    The format varies

    OTQL queries

    This page provides a formal description of OTQL capabilities.

    Introduction

    The Object Tree Query Language (OTQL) has been designed to help to search and calculate aggregates on a large collection of object trees. The object tree is defined in the schema using the @TreeIndexRoot and the @TreeIndex directives.

    OTQL queries help you :

    • Build segments

    • Explore data

    An OTQL query looks like an SQL query.

    SELECT { id name } FROM Product WHERE price > 50.0

    It is composed of three parts:

    • A SELECT Operation: It gives indications on what needs to be done: extracting field values or calculating aggregates

    • A FROM starting Object Type: It defines the starting object type in the evaluation process

    • A WHERE Object Tree Expression: It defines a logical expression mixing boolean operators and field operators to connect different objects in the object tree.

    There are two kinds of operations:

    • Selection Operations are similar to a GraphQL operation and return a list of objects containing the required fields.

    • Aggregation Operations return aggregated values (count, stats, histograms, ...) calculated on the selected objects.

    Here are some examples of requests you can do with OTQL :

    Imagining the following Object Tree:

    You could build queries starting from all UserPoint, all UserActivity, UserEvent, UserEmail or UserAccount

    The expression contained in the WHERE clause is composed of a list of predicates, separated by logical operators AND, OR, and NOT . Parenthesis can be used to group together two predicates with a logical operator.

    Examples :

    Each predicate doesn't return directly a boolean but a score, 1 if the condition is respected else 0. At the end the score is compared to 0 and return true if it's higher than 0 else return false. These operator keep the same priority as boolean ones. The logical operators work as below :

    As we are querying an Object Tree, and as predicates are only possible on a leaf (e.g. fields that only contain a scalar value), it is natural to have a way of going from the root to each of the leaves by traversing the tree.

    Braces symbols {} are used to traverse the tree through link fields. The sub-query written in the braces will be evaluated on each item in the linked list.

    Let's see it in action.

    Let's say we built a schema corresponding to the following Object Tree.

    The following query will return all the UserPoint that have at least one UserEvent whose name is $transaction_confirmed .

    As the root of the Object Tree is the UserPoint in this example, we'll need to start from there. And then follow the activities link to the associated UserActivity and then the events link to the associated UserEvent.

    The latest query returns items with at least one of the events have a $transaction_confirmed name. We return every user that did at least one purchase and at least one visit.

    If we instead want the users that bought things through at least 3 different visits (frequent buyers), we will use a scoring operator.

    Each time there is a pair of braces { } and a sub-query written in the braces, there is implicitly a score calculated for the sub-query. By default, the score will be the number of items matching the sub-query.

    Only returns score if the nested sub-query has a score superior or equal to min.

    As said above, by default, score values are equal to the number of items matching a sub-query when following a link.

    However, your Object Tree leaves have some number typed fields (Int or Float). It is possible to use those values as the score of a sub-query.

    Select a specific field in which the numeric value used as the score is stored.

    The information of which field is selected bubble up still it didn't catch by a @ScoreSum

    With the possibility to use score in a field, you may want to return the calculated score of a @ScoreSum and not only it a sub-query validate the condition or not. This is why we add a new parameters to @ScoreSum :result.

    Only returns score if the nested sub-query has a score superior or equal to min.

    It is possible to use these two ways at the same time but be careful, it is currently not possible to grow up a @ScoreField after a @ScoreSum(result: "boolean_score").

    Example of possible use case :

    However the following use case can't be written :

    Using conditional and scoring ways in the same query is useful for many use case whose won't be detailed here. A specific page has been created for regroup examples of them if you want to .

    The following operators are available to work with dates :

    • >= Greater or equal

    • > Greater

    • <= Lower or equal

    Dates can be formatted either

    • in ISO8601 format (time part is optional) 2012-09-27, 2012-09-27T12:42:00

    • in a timestamp in milliseconds 1549365498507

    The idea of the date match syntax is to define a relative date compared to an anchor date. The anchor date is either now or a date (ISO8601 or timestamp format) followed by ||.

    The expression begins with the anchor date and is followed by one or more math expressions :

    • +1h adds one hour

    • -1d substracts one day

    • /d rounds down to the nearest day

    Example, assuming now is 2001-01-01 12:00:00 :

    The supported units are the following :

    Date operator
    description

    Only the indexed fields of type String are eligible. Depending on the specified data_type in the schema, the String operator will behave differently.

    All operators are case-insensitive. .

    String operator
    description

    The same transformation is done on the text data before storage is also done on the comparison value.

    Below are some examples comparing the ingested and stored values, along with a demonstration of the match function:

    Value ingested
    Values stored
    Value matching
    Value not matching

    All operators are case-sensitive. .

    String operator
    description

    You can use the IN operator as a shortcut to filter on multiple values of the same field.

    This is used to evaluate the value of a field and check if it is defined or not. The predicate can be applied in any indexed field in the schema and return a boolean.

    Field Value
    Return

    ****

    You may want to add another list of predicates FROM various objects. To do so, use JOIN clause to mention another object right after the FROM/WHERE clauses. It's possible to apply multiple JOIN in the same query.

    In the Query Tools, we return 10 elements by default but you can easily override this by using the LIMIT clause followed by the number of elements required:

    Note that the LIMIT clause will be ignored when using @count or @cardinality directives.

    They are simply selecting fields. Every field present can be selected.

    , the WHERE expression gives you the ability to filter a sublist of objects at FROM level. You also have the capability to filter in or out the data returned by the query using the @filter directive in SELECT :

    Option
    Mandatory
    Usage

    Here are some tips to properly use the @filter directive in your queries:

    • Filter multiple fields (note that you can used OR or AND between fields, based on the required filter logic):

    • Filter in multiple values for a given fields:

    • Filter out multiple values for a given fields:

    • Combine AND & OR filters:

    • Filter by a subfield:

    When filter_empty:true option is provided, the following elements will be filtered out:

    • An optional array which is empty

    • An object which is empty and either optional or inside an array

    • A mandatory array where the following conditions are met :

    The following query retrieves userpoints, activities, events and some of their field for each UserPoint that has an event named "display".

    Let's assume it gives the following result :

    The user might be surprised to find "click" events in this result. However remember that the where clause only filter the roots (i.e the UserPoints). To retrieve only "display" events, the user will need to add an @filter clause as follow:

    Assuming the same data, this query would produce the following result :

    The @filter predicate also filters by default empty result in its scope. To illustrate this, we reduce our query to retrieve only the score fields :

    Still the same data, the result is the following:

    You'll notice that two display events have disappeared. Since they don't have a score, they would be empty object. Actually, this "filter empty" behavior can be set using a second optional parameter to the @filter directive. If we set it to false, we will obtain the following result :

    One might think that the previous result still contains a lot of noise (4 events retrieved for only one score). You can add an extra @filter before the object name to lighten the result:

    You will get the following result :

    @filter can be used to filter a field by a condition on a sub-field.

    The aggregation operations are initiated by a directive in the SELECT clause. They take into account the filter defined in the WHERE clause, however they are not compatible with the @filter directive that you can use in the SELECT clause.

    This directive is used to count the number of objects verifying the query

    Those directives calculate a value per bucket created in the bucket directive, or with only one bucket containing all elements if you don't use bucket directives.

    • @avg: average value for a specific field (only applies to numeric values)

    • @min: minimum value for a specific field (only applies to numeric values)

    • @max: maximum value for a specific field (only applies to numeric values)

    • @sum: sum of value for a specific field (only applies to numeric values)

    • @cardinality: count of distinct values

    Those directives separate values into buckets

    • @map one bucket per field value

    • @histogram aggregated count on a specific field. The interval can be modified regarding the business needs

    • @date_histogram aggregated count by a period of an object associated with a date. Allowed intervals are 1M for a month and XXD for a XX number of days.

    It is possible to add an alias to the field expression. This alias is then used in the output to identify the field result.

    You usually enter OTQL queries directly in tools like the navigator. However, they can be saved and managed by code as objects. Some features will require you to link an object to an OTQL query, instead of just saving the query as text.

    POST https://api.mediarithmics.com/v1/datamarts/:datamartId/queries

    Create an OTQL query in the platform before creating an export based on this query

    Name
    Type
    Description
    Name
    Type
    Description

    POST https://api.mediarithmics.com/v1/datamarts/:datamartId/query_check/otql

    Create an OTQL query in the platform before creating an export based on this query

    Name
    Type
    Description
    Name
    Type
    Description

    You can execute queries in the different tools that mediarithmics offer, or using our API.

    POST https://api.mediarithmics.com/v1/datamarts/:datamart_id/query_executions/otql?use_cache=true

    Executes an OTQL query on the specified datamart

    Name
    Type
    Description
    Name
    Type
    Description
    Name
    Type
    Description

    When setting the use_cache query parameter to TRUE, the system returns the query from the cache if available.

    To know if the returned value is from the cache or a new query execution, look at the cache_hit property from the response. Its value is TRUE if the response comes from the cache and FALSE otherwise.

    When not setting the use_cache query parameter or setting its value to FALSE, the cache system is skipped. The query will be executed and its value won't be stored. You can't use this to force a cache update .

    Running the query SELECT ... FROM ... WHERE ts >= "now-1h" (with a Date Math format from ) will return the same result now, in five minutes and during the next hour if using the cache.

    Our engine tries to automatically optimize queries before running them. For example, a query with multiple OR operators can use the IN operator instead if it is better.

    middle

    PredicateA OR PredicateB

    max(ScoreA, ScoreB)

    low

    Calculate the average from the sub-query matching scores and returns true if it's superior or equal to min.

    args

    description

    min : Float

    minimum required score for the nested sub-query to be returned

    Takes the maximum score from the sub-query matching scores and returns true if it's superior or equal to min.

    args

    description

    min : Float

    minimum required score for the nested sub-query to be returned

    By default, the score will be the number of items matching the sub-query. So using @ScoreMax or @ScoreAvg like that is useless because each score from the sub-query will be 1. It's why you should apply a modification on the score calculation.

    ,
    @ScoreAvg
    or
    @ScoreMax
    .

    Multiply the score by the factor. Can be used to boost a sub-query over another one.

    args

    description

    factor: Float

    Constant float which multiply the score

    # Select UserPoints having spent at least 1000 orders, where IT product count twice 
    SELECT (...) FROM UserPoint
    WHERE activity_events @ScoreSum(min : 1000) {
        order { 
          order_products @ScoreBoost(factor: 2.0) @ScoreSum(result: "score_value") {
                category="IT"
          },
          order_products @ScoreSum() {
                category!="IT"
            }
        }
    }

    Calculate the average from the sub-query matching scores and returns it if it's superior or equal to min args

    args

    description

    min : Float

    minimum required score for the nested sub-query to be returned

    result : String

    Takes the maximum score from the sub-query matching scores and returns it if it's superior or equal to min

    args

    description

    min : Float

    minimum required score for the nested sub-query to be returned

    result : String

    < Lower

  • = or == Equal

  • != Not equal

  • in a Date Math format, defining a relative date

    d

    Days

    h or H

    Hours

    m

    Minutes

    s

    Seconds

    hameçon hameÇon ligne et bouchon

    hamecon

    aujourd'hui

    aujourd'hui

    aujourd'hui

    aujourd hui aujourd hui

    s'inscrire

    s'inscrire

    s'inscrire

    s inscrire inscrire s

    100

    100

    100

    1000 10

    100 900 km

    100 900 km

    100 900 km 100 900 km

    100900 100,900

    km/h

    km h

    km/h km h

    kmh

    100km/h

    100km h

    100km/h 100km h km/h

    100 km

    H&M

    h m

    H&M h m

    hm

    £1,000 1,000 1,000+

    1,000

    £1,000 1,000 1,000+

    1000 000 1.000

    1.000

    1.000

    1.000

    1000 000 1,000

    chou-fleur chou- fleur chou fleur

    chou fleur

    chou-fleur chou- fleur chou fleur chou fleur

    chou_fleur choufleur

    chou_fleur

    chou_fleur

    chou_fleur

    chou fleur choufleur chou-fleur

    recherche.aspx

    recherche.aspx

    recherche.aspx

    recette aspx

    test@mics.com

    test mics.com

    test@mics.com test mics.com

    @ mics

    myField = ""

    True

    myField = [ ]

    True

    myField = null

    False

    myField = undefined

    False

    (NoField)

    False

    Tha array is empty
  • The other mandatory selections of the parent object are only empty arrays

  • This parent object can be filtered

  • Monitor data integration

  • Check the volumetry

  • Build data exports

  • ...

  • SELECT [Operation] FROM [Object Type] WHERE [Object Tree Expression]
    # Counts number of new users in the past 7 days
    SELECT @count{} FROM UserPoint WHERE creation_date >= "now-7d/d"
    
    # Counts the number of transactions on a specific site (channel) 7 days ago
    SELECT @count{} FROM UserEvent 
    WHERE name = "$transaction_confirmed" 
            AND date = "now-7d/d"
            AND channel_id = 2419
    
    # Counts the number of profiles with female gender
    SELECT @count{} FROM UserProfile WHERE gender = "W"
    
    # Lists all categories from universes in events done on a specific channel
    SELECT { universe { category @map }} FROM UserEvent WHERE channel_id = 2417
    
    # Lists all event names collected in the platform
    SELECT {name @map} FROM UserEvent
    
    # Number of users having at least 3 events related to laptops in the past 15 days
    SELECT @count{} FROM UserPoint 
    WHERE activities { events @ScoreSum(min:3) {
            category = "Laptop" AND date >= "now-15d/d"
            }}
    
    # Number of transactions per site and per day
    SELECT { channel_id @map { date @date_histogram } } FROM UserEvent WHERE name = "$transaction_confirmed"
    
    # Number of users having an account but no emails
    SELECT @count{} FROM UserPoint where accounts{} and not emails{}
    UserPoint
    ├── UserActivity
    │   └── UserEvent
    ├── UserEmail
    └── UserAccount
    # Selects all names from all UserPoint
    SELECT {name} FROM UserPoint
    
    # Selects all names from all UserActivity
    SELECT {name} FROM UserActivity
    # Equivalent of
    SELECT {activities { name }} FROM UserPoint
    
    # Selects all names from all UserEvent
    SELECT {name} FROM UserEvent
    # Equivalent of
    SELECT { activities { events { name }}} FROM UserPoint
     SELECT (...) FROM (...) WHERE (PredicateA AND PredicateB) OR PredicateC
     SELECT (...) FROM (...) WHERE PredicateA AND (PredicateB OR PredicateC)
     SELECT (...) FROM (...) WHERE price > 50.0
      SELECT (...) FROM (...) WHERE price > 50.0 AND last_modified_date > "now-10d"

    Logical operator

    Real operation

    Priority

    NOT PredicateA

    if ( ScoreA > 0) then 0 else 1

    high

    PredicateA AND PredicateB

    SELECT (...) FROM (...) 
    WHERE price > 50.0 AND last_modified_date > "now-10d"
    # ( price > 50.0 ) x ( last_modified_date > "now-10d" )
    
    SELECT (...) FROM (...) 
    WHERE price > 50.0 AND last_modified_date > "now-10d" OR  price > 100.0 AND last_modified_date > "now-20d"
    # (( price > 50.0 ) x ( last_modified_date > "now-10d" )) + (( price > 100.0 ) x ( last_modified_date > "now-20d" ))
    # Functional tree
    UserPoint
    └─ UserActivity
       └─ UserEvent
    
    # Associated schema
    type UserPoint @TreeIndexRoot(index:"USER_INDEX") {
     # activities is a link field to UserActivity objects
     activities: [UserActivity]
    }
    
    type UserActivity {
     # events is a link field to UserEvent objects
     events: [UserEvent]
    }
    
    type UserEvent {
     name: String @TreeIndex(index_name: "USER_INDEX")
     amount: Int @TreeIndex(index_name: "USER_INDEX")
     date: Timestamp! 
    }
    
    # A UserPoint can have 0..n User Activity
    # Each UserActivity can have 0..m UserEvent
    # UserEvent has a "name" String field, an "amount" Int field and a "date" Timestamp field 
    SELECT (...) FROM UserPoint WHERE activities { events { name = "$transaction_confirmed" } }

    args

    description

    min : Float

    minimum required score for the nested sub-query to be returned

    # Select UserPoint that bought things through at least 3 different visits
    SELECT (...) FROM UserPoint
    WHERE activities @ScoreSum(min: 3.0){ events { name = "$transaction_confirmed" } }
    
    # Select UserPoint that have at least 1 activity that contains at least 3 $transaction_confirmed events
    SELECT (...) FROM UserPoint
    WHERE activities { events @ScoreSum(min: 3.0) { name = "$transaction_confirmed" } }

    args

    description

    name: String

    The name of the field selected

    # Using @ScoreField alone is useless because it could be replace by logical operator
    SELECT (...) FROM UserPoint
    WHERE activity {
        events @ScoreField(name:"amount") {
            name = "$transaction_confirmed"
        }
    }
    
    # Can be written
    SELECT (...) FROM UserPoint
    WHERE activity {
        events {
            name = "$transaction_confirmed"
        }
    }

    args

    description

    min : Float

    minimum required score for the nested sub-query to be returned

    result : String

    # Select UserPoint having spent in average more than 1000 in one activity of events with a amount superior than 10
    SELECT (...) FROM UserPoint
    WHERE activity @ScoreAvg(min : 1000) { events @ScoreField(name:"amount") @ScoreSum(min 10, result:"score_value") { 
        name = "$transaction_confirmed" } }
    
    # Select UserPoint having spent in average in one activity, more than 1000 events with a amount superior than 10 
    SELECT (...) FROM UserPoint
    WHERE activity @ScoreAvg(min : 1000) { events @ScoreField(name:"amount") @ScoreSum(min: 10, result:"boolean_value") { 
        name = "$transaction_confirmed" } }
    # We wanted : 
    # Count UserPoint having spent more than 1000€ in cross orders with at least 10 orders more than 100€ : 
    SELECT (...) FROM UserPoint
    WHERE activity_events @ScoreSum(min : 1000) {
    	order @ScoreSum(min: 10, result: "score_value") {
          @ScoreSum(min: 100, result: "boolean_value") {
               order_products @ScoreField(name: "price") @ScoreSum(result:"score_value") { 
                  category="IT" 
               }
           }
       }
    }
    # But the query return :
    # Count UserPoint having spent more than 1000 orders with at least 10 orders more than 100€
    SELECT (...) FROM UserPoint WHERE activities {creation_ts <= "2012-09-27"}
    SELECT (...) FROM UserPoint WHERE activities {creation_ts > "1549365498507"}
    SELECT (...) FROM UserPoint WHERE activities {creation_ts > "now-7d"}
    now+1h // Resolves to: 2001-01-01 13:00:00
    now-1h // Resolves to: 2001-01-01 11:00:00
    now-1h/d // Resolves to: 2001-01-01 00:00:00
    2001.02.01||+1M/d // Resolves to: 2001-03-01 00:00:00

    y

    Years

    M

    Months

    w

    match(fieldName, comparisonValue, operator = "or")

    Returns true if words in the text contained in fieldName match words in comparisonValue operator defines how words are matched. Defaults to "or".

    • "or": returns true if at least one word in fieldName matches a word in comparisonValue

    • "and": returns true only if all words in comparisonValue are found in fieldName

    starts_with(fieldName, comparisonValue)

    Returns true if a word of the text contained in fieldName starts with one of the words contained in comparisonValue.

    # Doing
    (...) WHERE match(url_as_text, "Hello World!")
    
    # Will search in the text values for words matching 'hello' or 'world'
    https://www.hello.com/
    https://www.world.com/
    https://www.hello.com/world/
    (...)

    Métamorphosé

    métamorphosé

    Métamorphosé métamorphosé

    metamorphose métamorphos métamorphosés

    hameçon, ligne et bouchon

    starts_with(fieldName, comparisonValue)

    Returns true if the exact value contained in fieldName starts with the exact value passed in comparisonValue.

    = or ==

    Returns true if the exact value contained in fieldName is equal with the exact value passed in comparisonValue.

    (...) WHERE starts_with(mykeyword, "Hello World!")
    (...) WHERE mykeyword == "Hello World!"
    # Total sold in events for channel IDs 2456, 5489, 1426
    SELECT {events {basket { amount @sum}}} FROM UserActivity 
    WHERE channel_id IN ["2456","5489","1426"]
    
    # Equivalent of WHERE channel_id = "2456" OR channel_id = "5489" OR channel_id = "1426"
    # Return all UserPoint with a profile 
    SELECT { id } FROM UserPoint WHERE is_defined(profiles) 
    
    # Return all UserPoint with an email in their profile 
    SELECT { id } FROM UserPoint WHERE profiles{is_defined(email)}

    myField = “example”

    True

    myField = [“example”]

    True

    myField = [null]

    # Get the activity “$transaction_confirmed” of UserPoint of the segment id “1234“
    SELECT { id }
    FROM ActivityEvent WHERE name=="$transaction_confirmed"
    JOIN Userpoint WHERE segments { id="1234" }
    # Get only 5 or fewer activities named “$transaction_confirmed”
    SELECT { id }
    FROM ActivityEvent WHERE name=="$transaction_confirmed"
    LIMIT 5
    SELECT { id }
    FROM ActivityEvent WHERE name=="$transaction_confirmed"
    LIMIT 100 
    # This query returns 100 (or fewer) activities named “$transaction_confirmed”
    SELECT @count{ }
    FROM ActivityEvent WHERE name=="$transaction_confirmed"
    LIMIT 5
    # Return the count of all activities named "$transaction_confirmed"
    # Example: Return - 21,866,076
    # Select id and name in the root level
    SELECT { id name } FROM UserPoint
    
    # Select name in UserPoint and creation_ts and id in emails linked to the UserPoint
    SELECT { name emails { creation_ts id } } FROM UserPoint
    {<OBJECT> @filter(clause: "<FIELD_NAME> == \"<FIELD_VALUE>\"", 
    filter_empty: <BOOLEAN>) {<FIELD_NAME_1> <FIELD_NAME_2>}

    clause

    Yes

    Used to list fields names & values that you want to filter in/out

    filter_empty

    No

    Used to filter out empty object. Set to true by default.

    @filter(clause: "category == \"CAT_1\" OR referrer == \"REF\"")
    @filter(clause: "category == \"CAT_1\" OR category == \"CAT_2\"")
    @filter(clause: "category != \"CAT_1\" AND category != \"CAT_2\"")
    @filter(clause: "(category == \"CAT_1\" OR category == \"CAT_2\") AND 
    referrer == \"REF\"")
    @filter(clause: "events { category == \"CAT_1\" } ")
    select { id { activities { id events { name score } }  } }
    from UserPoint
    where { activities { events { name  == "display" } }  }
    [
      {
        "id": "up1",
        "activities": [
          {
            "id": "a1",
            "events": [
              { "name": "display",  "score": 123 },
              { "name": "click"}
            ]
          },
          {
            "id": "a2",
            "events": [ { "name": "display" } ]
          }
        ]
      },
      {
        "id": "up2",
        "activities": [
          {
            "id": "a3",
            "events": [ { "name": "click" } ]
          },
          {
            "id": "a4",
            "events": [ { "name": "display" } ]
          }
        ]
      }
    ]
    select { id { activities { id events @filter(clause: "name == \"display\"") { name score } }  } }
    from UserPoint
    where { activities { events { name  == "display" } }  }
      [
       {
        "id": "up1",
        "activities": [
          {
            "id": "a1",
            "events": [
              { "name": "display",  "score": 123 }
            ]
          },
          {
            "id": "a2",
            "events": [ { "name": "display" } ]
          }
        ]
      },
      {
        "id": "up2",
        "activities": [
          {
            "id": "a3",
            "events": []
          },
          {
            "id": "a4",
            "events": [ { "name": "display" } ]
          }
        ]
      }
    ]
    select { { activities { events @filter(clause: "name == \"display\"") { score } }  } }
    from UserPoint
    where { activities { events { name  == "display" } }  }
    [
      {
        "activities": [
          { "events": [ { "score": 123 } ] },
          { "events": [ ] }
        ]
      },
      {
        "activities": [
          { "events": [] },
          { "events": [] }
        ]
      }
    ]
    select { { activities { 
                 events @filter(clause: "name == \"display\"", filter_empty: false) { score } }  } }
    from UserPoint
    where { activities { events { name  == "display" } }}
    
    //result 
    
    [
      {
        "activities": [
          { "events": [ { "score": 123 } ] },
          { "events": [ {} ] }
        ]
      },
      {
        "activities": [
          { "events": [] },
          { "events": [ {} ] }
        ]
      }
    ]
    select @filter { { activities { 
                 events @filter(clause: "name == \"display\"") { score } }  } }
    from UserPoint
    where { activities { events { name  == "display" } }}
    [
      {
        "activities": [ { "events": [ { "score": 123 } ] }   ]
      }
    ]
    SELECT { activities @filter(clause: "events {is_defined(event_name) AND event_name == \"display\"}") 
        { events { event_name } } }
    FROM UserPoint
    where { activities { events { name  == "display" }}}
    # Counts the number of UserPoint
    SELECT @count {} FROM UserPoint
    
    # Counts number of new users in the past 7 days
    SELECT @count{} FROM UserPoint WHERE creation_date >= "now-7d/d"
    # Average basket amount between two specific dates
    SELECT {basket {amount @avg}} FROM UserEvent 
    WHERE {date >= "2020-12-01" AND date <= "2020-12-31" }
    # Minimum basket amount between two specific dates
    SELECT {basket {amount @min}} FROM UserEvent 
    WHERE { date >= "2020-06-20" AND date <= "2020-06-25” }
    # Maximum basket amount between two specific dates
    SELECT {basket {amount @max}} FROM UserEvent 
    WHERE { date >= "2020-06-20" AND date <= "2020-06-25”}
    # Sum of basket amounts between two specific dates
    SELECT {order{amount @sum }} FROM ActivityEvent 
    WHERE {date >= "2020-06-20" AND date <= "2020-06-25”}
    # Number of channels in a datamart
    SELECT {channel_id @cardinality} FROM ActivityEvent
    
    # Number of cookies associated with UserPoint in a specific segment
    SELECT  {agents{id @cardinality}} FROM UserPoint 
    WHERE segments {id=”XXXX”}
    SELECT { channel_id @map  {     # map the values of channel id in several buckets 
                session_duration @avg       # The average duration        
            }
    } FROM UserActivity
    
    # Data
    # channel ID : 1234, count : 654987987987, session_duration: 100
    # channel ID : 1235, count : 987987965465, session_duration: 1500
    SELECT { order { amount @histogram(interval:50)}}
    FROM UserEvent WHERE date >= "now-7d"
    
    # Data
    # Key: 0, count: 97681
    # Key: 50, count: 50324
    # Key: 100, count: 33164
    # Key: 150, count: 36528
    # Mere use of @date_histogram directive: selecting all page_view events 
    # in the last 30 days 
    SELECT { date @date_histogram(interval:"1d") } 
    FROM UserEvent
    WHERE name = "page_view" and date >= "now-30d/d"
    
    # @date_histogram used together with @map directive with default interval (days)
    SELECT { channel_id @map {date @date_histogram }} 
    FROM UserEvent
    WHERE name = "$transaction_confirmed"
    
    # Data
    # Key: 2416, count: 27563351
    #             2018-01-16T00:00:00.000Z 330
    #             2018-01-17T00:00:00.000Z 331
    #             2018-01-18T00:00:00.000Z 3332
    #             ...
    # Key: 2417, count: 65498798
    # ...
    
    # Force an interval of one month
    SELECT { channel_id @map {date @date_histogram(interval: "1M") } }
    FROM UserEvent
    WHERE name = "$transaction_confirmed"
    SELECT {
            numberOfChannels: channel_id @cardinality # The approximate number of distinc values 
            averageDuration: duration @avg            # The average duration
            mininumDuration: duration @min            # map the values of channel id in several buckets 
    } FROM UserEvent

    datamartId

    integer

    The ID of the datamart

    Body

    object

    Payload

    {
      "status": "ok",
      "data": 
        {
          "id": "50409", // ID of the query to retrieve for the next steps
          "datamart_id": "1509",
          "query_language": "OTQL",
          "minor_version": null,
          "major_version": null,
          "query_text": "SELECT {id} FROM UserPoint",
          "favorite": false
        }
    }
    {
        "status": "error",
        "error": "cannot save invalid query, cause: Syntax error while parsing document \"nawak\". Invalid input 'n', expected Comments or select (line 1, column 1):\nnawak\n^",
        "error_code": "BAD_REQUEST_DATA",
        "error_id": "ef292c4e-1eab-4a7f-8fb2-77d797139be9"
    }
    // Creating a query payload
    {
        "query_text": "SELECT {id} FROM UserPoint", // Your query
        "datamart_id": "<ASSOCIATED_DATAMART_ID>",
        "query_language": "OTQL"
    }

    datamartId

    integer

    The ID of the datamart

    Body

    object

    Payload

    // If valid
    {
        "status": "ok",
        "data": {
            "type": "VALID",
            "validation": {
                "parameters": []
            },
            "status": "ok"
        }
    }
    
    // If invalid
    {
        "status": "ok",
        "data": {
            "type": "PARSING_ERROR",
            "error": {
                "message": "Syntax error while parsing document \"nawak\". Invalid input 'n', expected Comments or select (line 1, column 1):\nnawak\n^",
                "position": {
                    "row": 1,
                    "col": 1
                },
                "error_type": "PARSING"
            },
            "status": "error"
        }
    // Checking a query payload
    {
        "query": "SELECT {id} FROM UserPoint" // Your query
    }

    datamart_id

    integer

    The ID of the datamart

    use_cache

    boolean

    Optimize the response time using the cache.

    Body

    string

    OTQL query to execute

    {
        "status": "ok",
        "data": {
            "took": 112015,
            "timed_out": false,
            "offset": null,
            "limit": null,
            "result_type": "COUNT",
            "precision": "FULL_PRECISION",
            "sampling_ratio": null,
            "rows": [
                {
                    "count": 80975924
                }
            ],
            "cache_hit": true
        }
    }
    {
        "status": "error",
        "error": "Service Unavailable",
        "error_code": "SERVICE_UNAVAILABLE",
        "error_id": "482416e1-2d93-484a-948b-615b639b5e4f"
    }

    The fields in the queries are completely related to how you built your schema.

    FROM - Starting object type

    You target object types with the FROM. In the example, the link field is activities, but we don't do SELECT (...) FROM activities.

    WHERE - Object tree expressions

    Logical operators

    Tree exploration

    Scoring operator

    Changing the way scores are calculated

    Using this calculated score

    Go forward

    Date operators

    Date Math format

    String operators

    With data_type: text :

    Diacritical marks (e.g. é, è, à, ç), number/digits, and word/expression containing apostrophe are usually stored as-is which means that you will need to provide the same value in the match function.

    With data_type: keyword :

    In operator

    This operator offers better performances than multiple OR operators.

    Is_defined operator

    JOIN operations

    LIMIT operations

    It's not possible to return more than 10 000 elements with LIMIT. The query will fail if you try it.

    LIMIT operator isn't applied during the segment calculation.

    If you create a User Query Segment with a LIMIT, it will be ignored and return all UserPoint who respect the WHERE clause.

    If you're using an aggregation directive such as @map and you want to extend the number of buckets returned, you need to use the limit parameter of the aggregation directive (for instance: @map(limit:200)) and not the LIMIT clause. More details available hereunder.

    SELECT operations

    Filters

    Tips

    Please note that the @filter directive cannot be used at the same time as aggregation operations such as @map, @date_histogram, ...

    Example 1 - Usage of clause

    Example 2 - Usage of filter_empty

    Example 3 - Usage of extra @filter

    Example 3 - Usage of @filter sub-field

    Aggregation Operations

    @count

    Metrics directives

    Fields used with metrics directives should have the @TreeIndex directive in your schema.

    Bucket directives

    Fields used with bucket directives should have the @TreeIndex directive in your schema.

    @map does not count null values

    You can use the limit function to extend the number or elements that can be returned by the directive (default: 50, maximum: 50 000) :

    SELECT { name @map(limit:200) } FROM UserEvent

    Please note that you cannot use bucket directives with metrics.

    Aliases

    Managing queries

    Features asking you to save queries to reference them usually want to leverage this for performances optimisation.

    Creating a query

    Path Parameters

    Request Body

    Check a query

    Path Parameters

    Request Body

    Executing queries

    Execute a query

    Path Parameters

    Query Parameters

    Request Body

    Query cache

    The cache expiration delay is 12 hour.

    Queries optimization

    go forward
    Values are stored as a set of words, transformed
    Values are considered as a single word. No transformation is made
    in the schema
    As we saw earler in this documentation
    Date operators

    ScoreA x ScoreB

    # Select UserPoint having spent at 1000 in one event
    SELECT (...) FROM UserPoint
    WHERE activity { 
        events @ScoreField(name:"amount") @ScoreSum(min : 1000) { 
            name = "$transaction_confirmed" 
        } 
    }
    
    # Select UserPoint having spent at 1000 in one activity
    SELECT (...) FROM UserPoint
    WHERE activity @ScoreSum(min : 1000) { 
        events @ScoreField(name:"amount") { 
            name = "$transaction_confirmed" 
        } 
    }

    Two values possibles :

    • "boolean_value" (by default) : reduce the returned score value to 0 or 1. It has the same comportment as the previous one explain in conditional predicate.

    • "score_value" : return the real score value.

    # Select UserPoint having spent more than 1000€ through $transaction_confirmed events during the past year
    SELECT (...) FROM UserPoint 
    WHERE activities { 
        events @ScoreField(name: "amount") @ScoreSum(min: 1000) { 
            name = "$transaction_confirmed" AND date >= "now-1y/y" 
        } 
    }
    
    # Select UserPoint having spent more than 1000€ in cross orders with at least products which cost 10€: 
    SELECT (...) FROM UserPoint
    WHERE activity_events @ScoreSum(min : 1000) {
    	order {
    	    order_products @ScoreField(name: "amount") @ScoreSum(min: 10, result:"score_value") { 
              category="IT" 
          }
       }
    }

    Weeks

    hameçon ligne et bouchon

    True

    By default, the score will be the number of items matching the sub-query. So using @ScoreMax or @ScoreAvg like that is useless because each score from the sub-query will be 1. It's why you should apply a modification on the score calculation.

    Be sure sub-field selected in @ScoreField exist in any field. Add a condition if the query return an error

    Two values possibles :

    • "boolean_value" (by default) : reduce the returned score value to 0 or 1.

    • "score_value" : return the real score value.

    # Select user points having spent on average at least 1000 through $transaction_confirmed events during the past year  
    SELECT (...) FROM UserPoint 
    WHERE activities { 
        events @ScoreField(name: "amount") @ScoreAvg(min: 1000) { 
            name = "$transaction_confirmed" AND date >= "now-1y/y" 
        } 
    }
    
    # Select user points having spent in average more than 1000€ by orders with at least products which cost 10€: 
    SELECT (...) FROM UserPoint
    WHERE activity_events @ScoreAvg(min : 1000) {
    	order {
    	    order_products @ScoreField(name: "amount") @ScoreSum(min: 10, result:"score_value") { 
              category="IT" 
          }
       }
    }

    Two values possibles :

    • "boolean_value" (by default) : reduce the returned score value to 0 or 1.

    • "score_value" : return the real score value.

    # Select user points with at least 1 activity that contains at least 1 $transaction_confirmed event with amount >= 1000 during the past year  
    SELECT (...) FROM UserPoint 
    WHERE activities { 
        events @ScoreField(name: "amount") @ScoreMax(min: 1000) { 
            name = "$transaction_confirmed" AND date >= "now-1y/y" 
        } 
    } 
    SELECT (...) FROM UserPoint
    WHERE activity @ScoreSum(min : 1000) {
        events @ScoreField(name:"amount") { 
            name = "$transaction_confirmed" 
        }
    }
    
    # To be sure field "amount" exist 
    SELECT (...) FROM UserPoint
    WHERE activity @ScoreSum(min : 1000) {
        events @ScoreField(name:"amount") { 
            is_defined(amount) AND 
            name = "$transaction_confirmed" 
        }
    }

    UserActivity & UserEvent

    User activity management is at the core of audience management services.

    A UserActivity is a collection of events (UserEvent) done by a single user in a given period of time. For instance, mediarithmics considers that a website activity is a session of no more than 30mn on a given website. An UserActivity is also linked to its referrer (like Google, Yahoo!, ...), if an user switch of referrer an go back to the same website, it will be considered like a new activity. Events can be given any name and any properties, but some predefined names and properties can be used to trigger specific treatment on the data.

    You send UserEvent to mediarithmics, that are aggregated and encapsulated into UserActivity. Some UserActivity only have one UserEvent, but some can have multiple UserEvent.

    To visualize user activities for a specific user, go to the navigator > Audience > Monitoring and select a user id.

    You can then view the complete JSON for each activity.

    User activities and events can be indexed and queried using APIs and/or the query engine, if their properties fit the object tree schema.

    When an activity is ingested via the real time tracking pipeline, it will trigger some dedicated processes like , , ...

    A minimal user activity is an object with the following properties.

    Their type is SITE_VISIT. They have those additional base properties :

    field
    type
    description

    Their type is APP_VISIT. They have those additional base properties :

    field
    type
    description

    Their type is Ct_VISIT. They have those additional base properties :

    field
    type
    description

    If you have multiple sites/apps (Mobile or CTV) you can create a channel for each one of them. Each channel will have an ID, representing either a site ID or an app ID.

    When you attach site IDs or app IDs to your user activities, you link them to the corresponding channel.

    This is useful for to a site or an app, or when you'll want to create queries and segments, allowing you to select only users having activities on a specific site or app.

    A user identifier is either a user account, a user email, or a user agent.

    Property
    Type
    Description

    In the mediarithmics vocabulary, the activity origin refers to the last digital channel leading to user interaction. It is key information to be used to analyze the results and the performance of marketing activities.

    This interaction can be a Touch (the user views a banner or an email) or a Visit (the user visits a web site or an app). In both cases, the $origin object of the is used to capture the information related to the originating channel.

    The $origin object is a customizable object with predefined properties as follows:

    The origin of user activity is calculated in different ways depending on the activity type (Touch/Visit) and source (Tag/API):

    • for a visit on a site or an app: from the analysis of the referrer and/or the query parameters provided in the destination URL (like the UTM parameters used by Google Analytics)

    • for touch events generated by campaigns delivered by the mediarithmics platform, the origin is automatically calculated from campaign information

    • for touch events (pixel events in emails or banners) the origin is calculated from the properties provided in the event (predefined properties)

    Here is the table of correspondence between mediarithmics origin fields and Google Analytics parameters:

    Here is the table of correspondence between mediarithmics origin fields and AT Internet parameter:The structure of the xtor parameter is as follows:

    The xtor parameter is automatically analyzed to fill the following origin fields:

    According to , source may be related to marketing channel.Here is the table of correspondance between AT Internet source and mediarithmics channel origin field

    When the user event is declared through a tag it is possible to add predefined event properties to declare an activity origin.

    Here is the list of the predefined properties :

    In mediarithmics, each unique activity is stored with 4 different accesses in this order:

    Datamart_id, user_point_id, ts and unique_key.

    It means that when those 4 parameters are identical between 2 activities, the new one cancels and replaces the old one. If one of the parameter differs then a new activity is created.

    This unique key is an uuid format. It can be calculated by the platform or the user itself.

    The best practice is to used uuid-v1 when generated by the user as it’s not a random value but calculated on the timestamp and a unique String.

    • mediarithmics tag through user-event-front: the unique_key is generated by the platform.

    • mediarithmics apis through datamart-front: the unique_key can be calculated by the user. If empty, it’s generated by the platform.

    • mediartihmics document import: the unique_key can be calculated by the user. If empty, it’s generated by the platform.

    When generated manually, the user has to select a key property (such as an order_id, a unique id generated on client size) or properties concatenation in order for the String to be unique.

    The uuid-v1 also need a timestamp to be generated and it's highly recommended to select the activity's one.

    See additional documentation

    A User Event is an object composed of an event name and a list of properties. Each property is composed of a name and a value.

    Using some predefined event names will allow you to have useful adapted automatic processing on some of your events.

    Using some predefined event properties will allow you to have useful adapted automatic processing on some of your events.

    Below is the JSON schema for a single activity, according to the rules enacted in this documentation.

    The activity type : - SITE_VISITfor activities happening on a channel of type site - APP_VISITfor activities happening on a channel of type app

    -CTV_VISIT for activities happening on a channel of type CTV - DISPLAY_AD for activities involving ad view and ad click events. See for more information. - EMAIL when users read a mail or click in a link inside it. For more information, see . - TOUCH for other activities

    $session_status

    String enum

    The sessions status, automatically updated by mediarithmics. NO_SESSION, IN_SESSION, CLOSED_SESSION

    $ttl

    Integer

    The Time To Live in minutes for the storage of this activity. 0 means no expiration

    $user_agent_info

    object

    Optional. Information of the device

    $user_agent_id

    String

    The identifier of the user device as provided by the user id mapping service. ex: vec:89090939434 ⚠️ Legacy, please use $user_identifiers instead

    $user_account_id

    (in addition to $compartment_id)

    String

    The user account id of the user ⚠️ Legacy, please use $user_identifiers instead

    $compartment_id

    (in addition to

    $user_account_id)

    Integer

    The ID of the compartment associated with this activity ⚠️ Legacy, please use $user_identifiers instead

    $email_hash

    Email Hash Object

    The email hash object { “$hash”:…, “$email”:…} ⚠️ Legacy, please use $user_identifiers instead

    $user_identifiers

    List of

    A list of all identifiers relative to the activity. You can have many of each type. ⚠️ Use this list rather than the legacy properties ($user_agent_id, $user_account_id & $compartment_id, $email_hash)

    $origin

    The activity origin

    $location

    The activity location

    $events

    List of

    A list of user events attached to this activity

    $unique_key

    String

    The unique_key of the activity formatted as an uuid-v1. If empty, the platform generates one automatically

    [any custom property]

    Any

    The value of a custom property

    The ID of the compartment associated with this activity

    $user_account_id

    String

    The user account id of the user

    $expiration_ts

    Timestamp (Optional)

    The account's expiration timestamp

    The email hash

    $email

    String (Optional)

    The "raw" email

    $expiration_ts

    Timestamp (Optional)

    The email's expiration timestamp

    The user agent id Currently support agent type : - vector id : vec:vector_id ; e.g.: vec:89090939434

    $expiration_ts

    Timestamp (Optional)

    The agent's expiration timestamp

    $os_family

    Enum

    The operating system family of the device. Possible values: WINDOWS, MAC_OS, LINUX, ANDROID, IOS, TIZEN, WEB_OS, ANDROID_TV, GOOGLE_TV, TV_OS, FIRE_TV, ROKU_TV

    $browser_family

    Enum

    If the device is a browser.

    Possible values: OTHER, CHROME, IE, FIREFOX, SAFARI, OPERA, STOCK_ANDROID, BOT, EMAIL_CLIENT, MICROSOFT_EDGE.

    $browser_version

    String

    The version of the browser.

    $brand

    String

    The brand of the device (ex.: "Apple")

    $model

    String

    The model of the device (ex.: "Iphone 14")

    $os_version

    String

    The version of the operating system (ex.: "macOS 10.15 Catalina")

    $carrier

    String

    The service provider that ensures connectivity of the device (ex: "AT&T")

    $raw_value

    String

    Raw user agent value

    $agent_type

    Enum

    Indicates the type of device. Possible values: WEB_BROWSER MOBILE_APP or CTV_APP

    The country’s name

    $region

    String (Optional)

    The region’s name

    $iso_region

    String (Optional)

    The region iso (ISO 3166-2)

    $city

    String (Optional)

    The city’s name

    $iso_city

    String (Optional)

    The city iso (UN/LOCODE)

    $zip_code

    String (Optional)

    The zip code

    $latlon

    Array[Double, Double]

    The latitude and longitude where the first element is the latitude and the second the longitude

    the source of the traffic. ex: google.com, news-foo.com, ...

    $campaign_name

    the campaign name

    $campaign_technical_name

    the campaign technical name

    $campaign_id

    the campaign id

    $sub_campaign_technical_name

    the sub campaign (Ad Group) technical name

    $sub_campaign_id

    the sub campaign (Ad Group) id

    $message_id

    $message_technical_name

    $keywords

    the keywords used in the search ex:sport+shoes

    $creative_name

    the creative name

    $creative_technical_name

    the creative technical name

    $creative_id

    the creative id

    $engagement_content_id

    $social_network

    the social network

    $referral_path

    the URL of the referral

    $log_id

    the custom unique identifier for the activity origin

    $gclid

    the unique identifier for a Google AdWords click

    for an activity inserted through the API, the origin fields can be directly filled with the relevant data.

    utm_source = base loyalty program

    $campaign_name

    utm_campaign

    utm_campaign = back to school

    $creative_name

    utm_content

    utm_content = template 1

    $keywords

    utm_term

    utm_term = sport+shoes or $keywords = sport+shoes

    $gclid

    gclid

    Google Click Identifier

    7880 when xtor=AD-7880

    $creative_name

    C

    when xtor=AD-3030-

    $email

    AD

    $rtb_display

    AL

    $affiliation

    $campaign_name=back to school

    $campaign_technical_name

    $ctn

    $ctn=DISPLAY-BACK-TO-SCHOOL

    $campaign_id

    $caid

    $caid=8989

    $sub_campaign_technical_name

    $scatn

    $scatn=STRATEGY-1, the sub campaign technical name is equivalent to the ad group technical name

    $sub_campaign_id

    $scaid

    $scaid=8782, sub campaign id is equivalent to the ad group id

    $creative_name

    $creative_name

    $creative_technical_name

    $crtn

    $crtn=special-banner

    $keywords

    $keywords

    $keywords = sport+shoes

    $social network

    $social_network

    $referral path

    $referral_path

    $log_id

    $log_id

    unique custom identifier

    $gclid

    $gclid

    Google Click Identifier

    The user has viewed an item

    $item_list_view

    The user has viewed a list of items

    $basket_view

    The user has viewed the basket

    $transaction_confirmed

    The user has completed a transaction

    $conversion

    The user has completed a conversion. This event is either registered by the integrator or automatically craeted by the platform when a goal is met.

    $app_install

    The user has installed an app

    $app_update

    The user has updated an app

    $app_open

    The user has opened an app or resumed it

    $ad_view

    The user has been exposed to a display add

    $ad_click

    The user has clicked on an app

    $email_view

    The user has opened an email

    $email_click

    The user has opened a link in an email

    $set_user_choice

    The user has given consent or objected to a

    Technical name of a sub campaign associated to the event when .

    $creative_technical_name

    Technical name of a creative associated to the event

    $processing_token

    Token of the associated when event name is $set_user_choice.

    $choice_acceptance_value

    Acceptance value of the when event name is $set_user_choice.

    field

    type

    description

    $ts

    Long

    The timestamp of the activity. For a session, it should correspond to the start date (Unix Epoch Time in milliseconds)

    $type

    $site_id

    String

    The site ID (channel)

    $session_duration

    Integer

    $app_id

    String

    The mobile app ID (channel)

    $session_duration

    Integer (Optional)

    $ctv_id

    String

    The CTV ID (channel)

    $session_duration

    Integer (Optional)

    field

    type

    description

    $type

    Constant String

    USER_ACCOUNT

    $compartment_id

    field

    type

    description

    $type

    Constant String

    USER_EMAIL

    $hash

    field

    type

    description

    $type

    Constant String

    USER_AGENT

    $user_agent_id

    $initial_ts

    Timestamp

    Timestamp at which device has been seen

    $form_factor

    Enum

    field

    type

    description

    $source

    String (Optional)

    The location source (IP, GPS, OTHER)

    $country

    origin field

    description

    $ts

    $channel

    the communication channel. ex: cpc, newsletter, banner, video, ...

    origin field

    url parameters

    example / description

    $channel

    utm_medium

    utm_medium = email or $channel = email

    $source

    xtor=A-B-C-D-E-F-G-H

    origin field

    xtor field

    example / description

    $source

    A

    EPR when xtor=EPR-14234

    $campaign_name

    source

    channel

    EPR

    $email

    EREC

    $email

    origin field

    predefined event properties

    example / description

    $source

    $source

    $source=crm_database

    $campaign_name

    {
        "$ts": 3489009384393,
        "$event_name": "$transaction_confirmed", // Conversion detected
        "$properties": {
            "$items": [
                {
                     "$id": "product_ID", // Used to filter in funnel analytics
                     "$qty": 20, // Used for conversion amounts
                     "$price": 102.8, // Used or conversion amounts
                     "$brand": "Apple" // Used to filter in funnel analytics
                     "$category1": "Category 1", // Used to filter in funnel analytics
                     "$category2": "Category 2", // Used to filter in funnel analytics
                     "$category3": "Category 3", // Used to filter in funnel analytics
                     "$category4": "Category 4" // Used to filter in funnel analytics
                 },
                 {
                     "$id": "product_ID2",
                     "$qty": 12,
                     "$price": 3.4,
                     "$brand": "Microsoft"
                 }
            ],
            "$currency": "EUR"
        }
    }

    event name

    description

    $page_view

    The user has viewed a page. Events with this event name only serve in session aggregation to have correct information on the user activity. They will be dropped when the session closes, and you won't see them on the platform anymore. If you wish to keep a record of the pages a user viewed in your site and create queries based on that data, you should name your event differently. You can also use the $item_view event name if your pages show products.

    $home_view

    The user has viewed the home page

    property name

    description

    $items

    An array of products associated with the event. Mainly used in products tracking for e-commerce sites. Example value : [{"$id":"ProductID1"},{"$id":"ProductID2"}]

    Each item has the $id, $ean, $qty , $price, $brand, $name, $category1, $category2, $category3 and $category4predefined properties.

    $campaign_technical_name

    Technical name of a campaign associated to the event when tracking ads exposure.

    {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "$ref": "#/definitions/UserActivity",
        "definitions": {
            "UserActivity": {
                "oneOf": [
                    {
                        "$ref": "#/definitions/GenericUserActivity"
                    },
                    {
                        "$ref": "#/definitions/SiteVisitUserActivity"
                    },
                    {
                        "$ref": "#/definitions/AppVisitUserActivity"
                    },
                    {
                        "$ref": "#/definitions/CTVVisitUserActivity"
                    }
                ]
            },
            "GenericUserActivity": {
                "type": "object",
                "properties": {
                    "$ts": {
                        "$ref": "#/definitions/Timestamp"
                    },
                    "$session_status": {
                        "$ref": "#/definitions/UserActivitySessionStatus"
                    },
                    "$ttl": {
                        "type": "number"
                    },
                    "$user_agent_id": {
                        "$ref": "#/definitions/Nullable%3CID%3E"
                    },
                    "$user_account_id": {
                        "$ref": "#/definitions/Nullable%3CID%3E"
                    },
                    "$compartment_id": {
                        "$ref": "#/definitions/Nullable%3CID%3E"
                    },
                    "$email_hash": {
                        "$ref": "#/definitions/Nullable%3Calias-1071211137-70767-70920-1071211137-0-212510%3Cdef-interface-792792747-896-1013-792792747-0-7494%2C%22%24type%22%3E%3E"
                    },
                    "$user_identifiers": {
                        "$ref": "#/definitions/Nullable%3Cdef-alias-792792747-1226-1323-792792747-0-7494%5B%5D%3E"
                    },
                    "$origin": {
                        "$ref": "#/definitions/Nullable%3CUserActivityOrigin%3E"
                    },
                    "$location": {
                        "$ref": "#/definitions/Nullable%3CUserActivityLocation%3E"
                    },
                    "$unique_key": {
                        "$ref": "#/definitions/UUID"
                    },
                    "$type": {
                        "type": "string",
                        "enum": [
                            "DISPLAY_AD",
                            "EMAIL",
                            "TOUCH",
                            "USER_SCENARIO_START",
                            "USER_SCENARIO_STOP",
                            "USER_SCENARIO_NODE_ENTER",
                            "USER_SCENARIO_NODE_EXIT"
                        ]
                    },
                    "$events": {
                        "type": "array",
                        "items": {
                            "$ref": "#/definitions/UserActivityEvent"
                        }
                    }
                },
                "required": [
                    "$email_hash",
                    "$events",
                    "$location",
                    "$origin",
                    "$session_status",
                    "$ts",
                    "$ttl",
                    "$type"
                ],
                "additionalProperties": {
                    "$ref": "#/definitions/JsonType"
                }
            },
            "Timestamp": {
                "type": "number"
            },
            "UserActivitySessionStatus": {
                "type": "string",
                "enum": [
                    "NO_SESSION",
                    "IN_SESSION",
                    "CLOSED_SESSION"
                ]
            },
            "Nullable<ID>": {
                "anyOf": [
                    {
                        "$ref": "#/definitions/ID"
                    },
                    {
                        "type": "null"
                    }
                ]
            },
            "ID": {
                "type": "string"
            },
            "Nullable<alias-1071211137-70767-70920-1071211137-0-212510<def-interface-792792747-896-1013-792792747-0-7494,\"$type\">>": {
                "anyOf": [
                    {
                        "type": "object",
                        "properties": {
                            "$hash": {
                                "type": "string"
                            },
                            "$email": {
                                "$ref": "#/definitions/Nullable%3Cstring%3E"
                            }
                        },
                        "required": [
                            "$hash"
                        ],
                        "additionalProperties": false
                    },
                    {
                        "type": "null"
                    }
                ]
            },
            "Nullable<string>": {
                "type": [
                    "string",
                    "null"
                ]
            },
            "Nullable<def-alias-792792747-1226-1323-792792747-0-7494[]>": {
                "anyOf": [
                    {
                        "type": "array",
                        "items": {
                            "$ref": "#/definitions/UserIdentifier"
                        }
                    },
                    {
                        "type": "null"
                    }
                ]
            },
            "UserIdentifier": {
                "anyOf": [
                    {
                        "$ref": "#/definitions/UserEmailIdentifier"
                    },
                    {
                        "$ref": "#/definitions/UserAccountIdentifier"
                    },
                    {
                        "$ref": "#/definitions/UserAgentIdentifier"
                    }
                ]
            },
            "UserEmailIdentifier": {
                "type": "object",
                "properties": {
                    "$type": {
                        "type": "string",
                        "const": "USER_EMAIL"
                    },
                    "$hash": {
                        "type": "string"
                    },
                    "$email": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    }
                },
                "required": [
                    "$type",
                    "$hash"
                ],
                "additionalProperties": false
            },
            "UserAccountIdentifier": {
                "type": "object",
                "properties": {
                    "$type": {
                        "type": "string",
                        "const": "USER_ACCOUNT"
                    },
                    "$user_account_id": {
                        "$ref": "#/definitions/ID"
                    },
                    "$compartment_id": {
                        "$ref": "#/definitions/ID"
                    }
                },
                "required": [
                    "$type",
                    "$user_account_id",
                    "$compartment_id"
                ],
                "additionalProperties": false
            },
            "UserAgentIdentifier": {
                "type": "object",
                "properties": {
                    "$type": {
                        "type": "string",
                        "const": "USER_AGENT"
                    },
                    "$user_agent_id": {
                        "$ref": "#/definitions/ID"
                    }
                },
                "required": [
                    "$type",
                    "$user_agent_id"
                ],
                "additionalProperties": false
            },
            "Nullable<UserActivityOrigin>": {
                "anyOf": [
                    {
                        "$ref": "#/definitions/UserActivityOrigin"
                    },
                    {
                        "type": "null"
                    }
                ]
            },
            "UserActivityOrigin": {
                "type": "object",
                "properties": {
                    "$campaign_id": {
                        "$ref": "#/definitions/Nullable%3Cnumber%3E"
                    },
                    "$campaign_name": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$channel": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$creative_id": {
                        "$ref": "#/definitions/Nullable%3Cnumber%3E"
                    },
                    "$creative_name": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$engagement_content_id": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$gclid": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$keywords": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$log_id": {
                        "$ref": "#/definitions/Nullable%3CID%3E"
                    },
                    "$message_id": {
                        "$ref": "#/definitions/Nullable%3Cnumber%3E"
                    },
                    "$message_technical_name": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$referral_path": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$social_network": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$source": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$sub_campaign_id": {
                        "$ref": "#/definitions/Nullable%3Cnumber%3E"
                    },
                    "$sub_campaign_technical_name": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$ts": {
                        "type": "number"
                    }
                },
                "additionalProperties": {
                    "$ref": "#/definitions/JsonType"
                }
            },
            "Nullable<number>": {
                "type": [
                    "number",
                    "null"
                ]
            },
            "JsonType": {
                "anyOf": [
                    {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    {
                        "$ref": "#/definitions/Nullable%3Cnumber%3E"
                    },
                    {
                        "type": "boolean"
                    },
                    {
                        "type": "object"
                    },
                    {
                        "type": "array",
                        "items": {}
                    },
                    {
                        "not": {}
                    }
                ]
            },
            "Nullable<UserActivityLocation>": {
                "anyOf": [
                    {
                        "$ref": "#/definitions/UserActivityLocation"
                    },
                    {
                        "type": "null"
                    }
                ]
            },
            "UserActivityLocation": {
                "type": "object",
                "properties": {
                    "$source": {
                        "$ref": "#/definitions/LocationSource"
                    },
                    "$country": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$region": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$iso_region": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$city": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$iso_city": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$zip_code": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$latlon": {
                        "$ref": "#/definitions/Nullable%3Cnumber%5B%5D%3E"
                    }
                },
                "required": [
                    "$latlon"
                ],
                "additionalProperties": {
                    "$ref": "#/definitions/JsonType"
                }
            },
            "LocationSource": {
                "type": "string",
                "enum": [
                    "GPS",
                    "IP",
                    "OTHER"
                ]
            },
            "Nullable<number[]>": {
                "anyOf": [
                    {
                        "type": "array",
                        "items": {
                            "type": "number"
                        }
                    },
                    {
                        "type": "null"
                    }
                ]
            },
            "UUID": {
                "type": "string",
                "pattern": "^[0-9a-fA-F]{8}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{12}$"
            },
            "UserActivityEvent": {
                "anyOf": [
                    {
                        "$ref": "#/definitions/GenericUserActivityEvent"
                    },
                    {
                        "$ref": "#/definitions/AdTrackingEvent"
                    },
                    {
                        "$ref": "#/definitions/SetUserChoiceEvent"
                    },
                    {
                        "$ref": "#/definitions/SetUserProfilePropertiesEvent"
                    },
                    {
                        "$ref": "#/definitions/RetailEvent"
                    },
                    {
                        "$ref": "#/definitions/ConversionEvent"
                    }
                ]
            },
            "GenericUserActivityEvent": {
                "type": "object",
                "properties": {
                    "$ts": {
                        "$ref": "#/definitions/Timestamp"
                    },
                    "$expiration_ts": {
                        "$ref": "#/definitions/Nullable%3CTimestamp%3E"
                    },
                    "$event_name": {
                        "anyOf": [
                            {
                                "$ref": "#/definitions/EventName"
                            },
                            {
                                "type": "string"
                            }
                        ]
                    },
                    "$properties": {
                        "$ref": "#/definitions/Customizable"
                    }
                },
                "required": [
                    "$event_name",
                    "$properties",
                    "$ts"
                ],
                "additionalProperties": {
                    "$ref": "#/definitions/JsonType"
                }
            },
            "Nullable<Timestamp>": {
                "anyOf": [
                    {
                        "$ref": "#/definitions/Timestamp"
                    },
                    {
                        "type": "null"
                    }
                ]
            },
            "EventName": {
                "anyOf": [
                    {
                        "$ref": "#/definitions/DefaultEventName"
                    },
                    {
                        "type": "string"
                    }
                ]
            },
            "DefaultEventName": {
                "type": "string",
                "enum": [
                    "$page_view",
                    "$home_view",
                    "$category_view",
                    "$email_view",
                    "$email_click",
                    "$email_sent",
                    "$email_delivered",
                    "$email_soft_bounce",
                    "$email_hard_bounce",
                    "$email_unsubscribe",
                    "$email_complaint",
                    "$content_corrections"
                ]
            },
            "Customizable": {
                "type": "object",
                "additionalProperties": {
                    "$ref": "#/definitions/JsonType"
                }
            },
            "AdTrackingEvent": {
                "type": "object",
                "properties": {
                    "$ts": {
                        "$ref": "#/definitions/Timestamp"
                    },
                    "$expiration_ts": {
                        "$ref": "#/definitions/Nullable%3CTimestamp%3E"
                    },
                    "$event_name": {
                        "type": "string",
                        "enum": [
                            "$ad_view",
                            "$ad_click"
                        ]
                    },
                    "$properties": {
                        "$ref": "#/definitions/AdTrackingEventProperties"
                    }
                },
                "required": [
                    "$event_name",
                    "$properties",
                    "$ts"
                ],
                "additionalProperties": {
                    "$ref": "#/definitions/JsonType"
                }
            },
            "AdTrackingEventProperties": {
                "type": "object",
                "properties": {
                    "$url": {
                        "type": "string"
                    },
                    "$referrer": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$campaign_technical_name": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$sub_campaign_technical_name": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$creative_technical_name": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$message_technical_name": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$campaign_id": {
                        "$ref": "#/definitions/Nullable%3Cnumber%3E"
                    },
                    "$sub_campaign_id": {
                        "$ref": "#/definitions/Nullable%3Cnumber%3E"
                    },
                    "$message_id": {
                        "$ref": "#/definitions/Nullable%3Cnumber%3E"
                    },
                    "$creative_id": {
                        "$ref": "#/definitions/Nullable%3Cnumber%3E"
                    }
                },
                "additionalProperties": {
                    "$ref": "#/definitions/JsonType"
                },
                "required": [
                    "$url"
                ]
            },
            "SetUserChoiceEvent": {
                "type": "object",
                "properties": {
                    "$ts": {
                        "$ref": "#/definitions/Timestamp"
                    },
                    "$expiration_ts": {
                        "$ref": "#/definitions/Nullable%3CTimestamp%3E"
                    },
                    "$event_name": {
                        "type": "string",
                        "const": "$set_user_choice"
                    },
                    "$properties": {
                        "$ref": "#/definitions/SetUserChoiceEventProperties"
                    }
                },
                "required": [
                    "$event_name",
                    "$properties",
                    "$ts"
                ],
                "additionalProperties": {
                    "$ref": "#/definitions/JsonType"
                }
            },
            "SetUserChoiceEventProperties": {
                "type": "object",
                "properties": {
                    "$url": {
                        "type": "string"
                    },
                    "$referrer": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$processing_token": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$processing_id": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$choice_acceptance_value": {
                        "type": "boolean"
                    },
                    "$choice_source_id": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    }
                },
                "required": [
                    "$choice_acceptance_value",
                    "$url"
                ],
                "additionalProperties": {
                    "$ref": "#/definitions/JsonType"
                }
            },
            "SetUserProfilePropertiesEvent": {
                "type": "object",
                "properties": {
                    "$ts": {
                        "$ref": "#/definitions/Timestamp"
                    },
                    "$expiration_ts": {
                        "$ref": "#/definitions/Nullable%3CTimestamp%3E"
                    },
                    "$event_name": {
                        "type": "string",
                        "const": "$set_user_profile_properties"
                    },
                    "$properties": {
                        "$ref": "#/definitions/Customizable"
                    }
                },
                "required": [
                    "$event_name",
                    "$properties",
                    "$ts"
                ],
                "additionalProperties": {
                    "$ref": "#/definitions/JsonType"
                }
            },
            "RetailEvent": {
                "type": "object",
                "properties": {
                    "$ts": {
                        "$ref": "#/definitions/Timestamp"
                    },
                    "$expiration_ts": {
                        "$ref": "#/definitions/Nullable%3CTimestamp%3E"
                    },
                    "$event_name": {
                        "$ref": "#/definitions/RetailEventName"
                    },
                    "$properties": {
                        "$ref": "#/definitions/RetailEventProperties"
                    }
                },
                "required": [
                    "$event_name",
                    "$properties",
                    "$ts"
                ],
                "additionalProperties": {
                    "$ref": "#/definitions/JsonType"
                }
            },
            "RetailEventName": {
                "type": "string",
                "enum": [
                    "$item_view",
                    "$item_list_view",
                    "$product_view",
                    "$product_list_view",
                    "$basket_view",
                    "$transaction_confirmed"
                ]
            },
            "RetailEventProperties": {
                "type": "object",
                "properties": {
                    "$url": {
                        "type": "string"
                    },
                    "$referrer": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$items": {
                        "$ref": "#/definitions/Nullable%3Cdef-interface-792792747-3521-3897-792792747-0-7494%5B%5D%3E"
                    }
                },
                "additionalProperties": {
                    "$ref": "#/definitions/JsonType"
                },
                "required": [
                    "$url"
                ]
            },
            "Nullable<def-interface-792792747-3521-3897-792792747-0-7494[]>": {
                "anyOf": [
                    {
                        "type": "array",
                        "items": {
                            "$ref": "#/definitions/RetailEventPropertiesItem"
                        }
                    },
                    {
                        "type": "null"
                    }
                ]
            },
            "RetailEventPropertiesItem": {
                "type": "object",
                "properties": {
                    "$id": {
                        "type": "string"
                    },
                    "$ean": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$qty": {
                        "$ref": "#/definitions/Nullable%3Cnumber%3E"
                    },
                    "$price": {
                        "$ref": "#/definitions/Nullable%3Cnumber%3E"
                    },
                    "$brand": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$name": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$category1": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$category2": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$category3": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$category4": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    }
                },
                "required": [
                    "$id"
                ],
                "additionalProperties": {
                    "$ref": "#/definitions/JsonType"
                }
            },
            "ConversionEvent": {
                "type": "object",
                "properties": {
                    "$ts": {
                        "$ref": "#/definitions/Timestamp"
                    },
                    "$expiration_ts": {
                        "$ref": "#/definitions/Nullable%3CTimestamp%3E"
                    },
                    "$event_name": {
                        "type": "string",
                        "const": "$conversion"
                    },
                    "$properties": {
                        "$ref": "#/definitions/ConversionEventProperties"
                    }
                },
                "required": [
                    "$event_name",
                    "$properties",
                    "$ts"
                ],
                "additionalProperties": {
                    "$ref": "#/definitions/JsonType"
                }
            },
            "ConversionEventProperties": {
                "type": "object",
                "properties": {
                    "$conversion_id": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$goal_id": {
                        "$ref": "#/definitions/Nullable%3Cnumber%3E"
                    },
                    "$conversion_technical_id": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$goal_technical_id": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$conversion_value": {
                        "$ref": "#/definitions/Nullable%3Cnumber%3E"
                    },
                    "$log_id": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$conversion_external_id": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    },
                    "$goal_technical_name": {
                        "$ref": "#/definitions/Nullable%3Cstring%3E"
                    }
                },
                "additionalProperties": {
                    "$ref": "#/definitions/JsonType"
                }
            },
            "SiteVisitUserActivity": {
                "type": "object",
                "properties": {
                    "$ts": {
                        "$ref": "#/definitions/Timestamp"
                    },
                    "$session_status": {
                        "$ref": "#/definitions/UserActivitySessionStatus"
                    },
                    "$ttl": {
                        "type": "number"
                    },
                    "$user_agent_id": {
                        "$ref": "#/definitions/Nullable%3CID%3E"
                    },
                    "$user_account_id": {
                        "$ref": "#/definitions/Nullable%3CID%3E"
                    },
                    "$compartment_id": {
                        "$ref": "#/definitions/Nullable%3CID%3E"
                    },
                    "$email_hash": {
                        "$ref": "#/definitions/Nullable%3Calias-1071211137-70767-70920-1071211137-0-212510%3Cdef-interface-792792747-896-1013-792792747-0-7494%2C%22%24type%22%3E%3E"
                    },
                    "$user_identifiers": {
                        "$ref": "#/definitions/Nullable%3Cdef-alias-792792747-1226-1323-792792747-0-7494%5B%5D%3E"
                    },
                    "$origin": {
                        "$ref": "#/definitions/Nullable%3CUserActivityOrigin%3E"
                    },
                    "$location": {
                        "$ref": "#/definitions/Nullable%3CUserActivityLocation%3E"
                    },
                    "$unique_key": {
                        "$ref": "#/definitions/UUID"
                    },
                    "$session_duration": {
                        "$ref": "#/definitions/Nullable%3Cnumber%3E"
                    },
                    "$error_analyzer_id": {
                        "$ref": "#/definitions/Nullable%3CID%3E"
                    },
                    "$analyzer_errors": {
                        "type": "array",
                        "items": {
                            "type": "object"
                        }
                    },
                    "$topics": {
                        "$ref": "#/definitions/Nullable%3Calias-1071211137-70404-70537-1071211137-0-212510%3Cstring%2Calias-1071211137-70404-70537-1071211137-0-212510%3Cstring%2Cnumber%3E%3E%3E"
                    },
                    "$type": {
                        "type": "string",
                        "const": "SITE_VISIT"
                    },
                    "$events": {
                        "type": "array",
                        "items": {
                            "$ref": "#/definitions/UserActivityEvent"
                        }
                    },
                    "$site_id": {
                        "$ref": "#/definitions/ID"
                    }
                },
                "required": [
                    "$email_hash",
                    "$events",
                    "$location",
                    "$origin",
                    "$session_status",
                    "$site_id",
                    "$ts",
                    "$ttl",
                    "$type"
                ],
                "additionalProperties": {
                    "$ref": "#/definitions/JsonType"
                }
            },
            "Nullable<alias-1071211137-70404-70537-1071211137-0-212510<string,alias-1071211137-70404-70537-1071211137-0-212510<string,number>>>": {
                "anyOf": [
                    {
                        "type": "object",
                        "additionalProperties": {
                            "type": "object",
                            "additionalProperties": {
                                "type": "number"
                            }
                        }
                    },
                    {
                        "type": "null"
                    }
                ]
            },
            "AppVisitUserActivity": {
                "type": "object",
                "properties": {
                    "$ts": {
                        "$ref": "#/definitions/Timestamp"
                    },
                    "$session_status": {
                        "$ref": "#/definitions/UserActivitySessionStatus"
                    },
                    "$ttl": {
                        "type": "number"
                    },
                    "$user_agent_id": {
                        "$ref": "#/definitions/Nullable%3CID%3E"
                    },
                    "$user_account_id": {
                        "$ref": "#/definitions/Nullable%3CID%3E"
                    },
                    "$compartment_id": {
                        "$ref": "#/definitions/Nullable%3CID%3E"
                    },
                    "$email_hash": {
                        "$ref": "#/definitions/Nullable%3Calias-1071211137-70767-70920-1071211137-0-212510%3Cdef-interface-792792747-896-1013-792792747-0-7494%2C%22%24type%22%3E%3E"
                    },
                    "$user_identifiers": {
                        "$ref": "#/definitions/Nullable%3Cdef-alias-792792747-1226-1323-792792747-0-7494%5B%5D%3E"
                    },
                    "$origin": {
                        "$ref": "#/definitions/Nullable%3CUserActivityOrigin%3E"
                    },
                    "$location": {
                        "$ref": "#/definitions/Nullable%3CUserActivityLocation%3E"
                    },
                    "$unique_key": {
                        "$ref": "#/definitions/UUID"
                    },
                    "$session_duration": {
                        "$ref": "#/definitions/Nullable%3Cnumber%3E"
                    },
                    "$error_analyzer_id": {
                        "$ref": "#/definitions/Nullable%3CID%3E"
                    },
                    "$analyzer_errors": {
                        "type": "array",
                        "items": {
                            "type": "object"
                        }
                    },
                    "$topics": {
                        "$ref": "#/definitions/Nullable%3Calias-1071211137-70404-70537-1071211137-0-212510%3Cstring%2Calias-1071211137-70404-70537-1071211137-0-212510%3Cstring%2Cnumber%3E%3E%3E"
                    },
                    "$type": {
                        "type": "string",
                        "const": "APP_VISIT"
                    },
                    "$events": {
                        "type": "array",
                        "items": {
                            "anyOf": [
                                {
                                    "$ref": "#/definitions/UserActivityEvent"
                                },
                                {
                                    "$ref": "#/definitions/AppActivityEvent"
                                }
                            ]
                        }
                    },
                    "$app_id": {
                        "$ref": "#/definitions/ID"
                    }
                },
                "required": [
                    "$app_id",
                    "$email_hash",
                    "$events",
                    "$location",
                    "$origin",
                    "$session_status",
                    "$ts",
                    "$ttl",
                    "$type"
                ],
                "additionalProperties": {
                    "$ref": "#/definitions/JsonType"
                }
            },
    		"CTVVisitUserActivity": {
                "type": "object",
                "properties": {
                    "$ts": {
                        "$ref": "#/definitions/Timestamp"
                    },
                    "$session_status": {
                        "$ref": "#/definitions/UserActivitySessionStatus"
                    },
                    "$ttl": {
                        "type": "number"
                    },
                    "$user_agent_id": {
                        "$ref": "#/definitions/Nullable%3CID%3E"
                    },
                    "$user_account_id": {
                        "$ref": "#/definitions/Nullable%3CID%3E"
                    },
                    "$compartment_id": {
                        "$ref": "#/definitions/Nullable%3CID%3E"
                    },
                    "$email_hash": {
                        "$ref": "#/definitions/Nullable%3Calias-1071211137-70767-70920-1071211137-0-212510%3Cdef-interface-792792747-896-1013-792792747-0-7494%2C%22%24type%22%3E%3E"
                    },
                    "$user_identifiers": {
                        "$ref": "#/definitions/Nullable%3Cdef-alias-792792747-1226-1323-792792747-0-7494%5B%5D%3E"
                    },
                    "$origin": {
                        "$ref": "#/definitions/Nullable%3CUserActivityOrigin%3E"
                    },
                    "$location": {
                        "$ref": "#/definitions/Nullable%3CUserActivityLocation%3E"
                    },
                    "$unique_key": {
                        "$ref": "#/definitions/UUID"
                    },
                    "$session_duration": {
                        "$ref": "#/definitions/Nullable%3Cnumber%3E"
                    },
                    "$error_analyzer_id": {
                        "$ref": "#/definitions/Nullable%3CID%3E"
                    },
                    "$analyzer_errors": {
                        "type": "array",
                        "items": {
                            "type": "object"
                        }
                    },
                    "$topics": {
                        "$ref": "#/definitions/Nullable%3Calias-1071211137-70404-70537-1071211137-0-212510%3Cstring%2Calias-1071211137-70404-70537-1071211137-0-212510%3Cstring%2Cnumber%3E%3E%3E"
                    },
                    "$type": {
                        "type": "string",
                        "const": "CTV_VISIT"
                    },
                    "$events": {
                        "type": "array",
                        "items": {
                            "anyOf": [
                                {
                                    "$ref": "#/definitions/UserActivityEvent"
                                },
                                {
                                    "$ref": "#/definitions/AppActivityEvent"
                                }
                            ]
                        }
                    },
                    "$ctv_id": {
                        "$ref": "#/definitions/ID"
                    }
                },
                "required": [
                    "$ctv_id",
                    "$email_hash",
                    "$events",
                    "$location",
                    "$origin",
                    "$session_status",
                    "$ts",
                    "$ttl",
                    "$type"
                ],
                "additionalProperties": {
                    "$ref": "#/definitions/JsonType"
                }
            },
            "AppActivityEvent": {
                "type": "object",
                "properties": {
                    "$event_name": {
                        "type": "string",
                        "enum": [
                            "$app_open",
                            "$app_update",
                            "$app_install"
                        ]
                    },
                    "$properties": {
                        "$ref": "#/definitions/Customizable"
                    }
                },
                "required": [
                    "$event_name",
                    "$properties"
                ],
                "additionalProperties": false
            }
        }
    }
    

    User Activity object

    User activities could be enriched with any custom property, and specific activity types can have additional base properties.

    Base properties names all begin with '$'. That's a good way to differentiate base properties and your custom properties if you don't start your property names with that same character.

    A few things to keep in mind :

    • Always prefer predefined properties to custom properties when they exist, as the platform automates a lot of actions based on those properties. You could miss some critical steps in having well organized data

    • Activities are limited to 8000 characters.

    • For user identification you can :

      • either use $user_identifiers;

      • or use $user_agent_id, $user_account_id, $compartment_id, and $email_hash

    Site visits user activities

    App visits user activities

    CTV visits user activities

    Channels

    User Identifier

    User Account

    User Email

    User Agent

    User Agent info

    Activity Location

    Activity Origin

    Origin calculation

    A user activity can only have one origin. If a user comes back from a different origin in a live session. The current session is closed and a new session is opened with the second origin.

    Origin detection based on Google Analytics parameters (UTM)

    Origin detection based on AT Internet parameter (xtor)

    Marketing Channel inference

    Origin declaration with predefined event properties

    Activity unique key

    Unique key calculation

    User Events object

    Predefined event names

    Always prefer predefined event names to custom events when they exist, as the platform automates a lot of actions based on those names. You could miss some critical steps in having well organized data.

    Predefined event properties

    Always prefer predefined event properties to custom event properties when they exist, as the platform automates a lot of actions based on those names. You could miss some critical steps in having well organized data.

    User Activity JSON schema and TypeScript interfaces

    event rules
    activity analyzers
    attaching data privacy rules
    user activity
    AT Internet documentation about xtor parameter
    https://www.npmjs.com/package/uuid#uuidv1options-buffer-offset

    String enum

    The session duration in seconds.

    The session duration in seconds.

    The session duration in seconds.

    Integer

    String

    String

    Indicates the format of the device. Possible values: PERSONAL_COMPUTER, SMART_TV, GAME_CONSOLE, SMARTPHONE, TABLET, WEARABLE_COMPUTER, OTHER.

    String (Optional)

    $source

    utm_source

    B

    ES

    $campaign_name

    $item_view

    $sub_campaign_technical_name

    There are also activity types specific to :

    - USER_SCENARIO_START when a scenario starts

    - USER_SCENARIO_STOP when a scenario stops

    - USER_SCENARIO_NODE_ENTER when a new scenario node is entered

    - USER_SCENARIO_NODE_EXIT when a scenario node is exited

    ,
    TITAN_OS
    ,
    OTHER
    .
    Ads exposure tracking
    Email views and clicks
    User Agent info
    User Identifier
    Activity Origin
    Activity Location
    User Event
    ad_version7
    ad_version7
    processing activity
    tracking ads exposure
    processing activity
    user choice
    automations