Comment on page
Integrating TV Graphics
How to feed live data into TV graphics systems
The platform provides dynamic data which can be fed into TV Graphics to populate real-time visualisations.
This data is available via two core methods:
- 1.
- 2.Public feeds - these feeds are served via a CDN and data can be exposed for convenience. However this is a slower and less secure method.
You may also choose to create custom feeds that you make using either of these two methods to generate your own formats. For example, using a Lambda to generate your own endpoint.
This document covers the Control API method.
Note that we often refer to "votes", where this data can relate to any form of user selection such as a prediction, rating or other.
- 1.Project ID
- 2.Event ID
- 3.Bearer token
These instructions assume that you have a Studio user account with at least “Viewer” level access. Log in to Studio and navigate to the Project and Event that you plan to use for voting. Please contact Monterosa at [email protected] if you need an account creating for this purpose.
See details of how to generate a bearer token for your account here: Control API - Generating a bearer token
To obtain the Project and Event ID, navigate to the relevant Event in your project, and navigate to Event Settings > Event > Event ID and copy these values.

Example host and project ID
Within the Control API, a vote is an Element with
content_type: vote
. The list of all elements within the vote Event can be obtained by using the REST API call described here - Get ElementsThe request can be performed using a CURL command like the following:
EVENT_ID=<EVENT_ID>
TOKEN=<TOKEN>
curl --request GET
--url "https://studio.monterosa.cloud/api/v2/events/$EVENT_ID/elements?include=stats"
--header "Authorization: Bearer $TOKEN"
The result of that GET request will be a JSON object containing all elements metadata and the aggregated vote results. The most relevant fields of which are:
data
- Includes all the elements data, on each element, we’ll find:attributes.content_type
will specify the type of element you retrieved. Make sure it’s value equalsvote
.state
will specify the state the element is in. The following page documents which values it can take and their meaning: Element Resourceattributes.question
will contain the JSON data for the question we are asking our usersoptions[X].fields["key"].values.all
specifies the textual representation of the option a user votes for. Note thatX
will be the index used to aggregate its stats in the stats section of the JSON.
included
- Will contain an array with the stats for each of the elements with matching indexes to that of the data array. This data is only included if you provide the?include=stats
URL query parameter.attributes.aggregated.voters
will include the total count of votersattributes.aggregated.votes
will include the total count of votesattributes.results[X].votes
will include the total count of votes a specific answer option received. E.g. how many votes a candidate on a reality tv show got.attributes.results_are_final
will indicate if the voting has concluded
Once you have obtained the data you need, and parsed through it to obtain the relevant data, you may need to match the vote statistics to other vote sources to produce a final tally of votes.
Our suggested approach is to match the text used in the question options to the alternatives a vote can have.
The JSON structure can be navigated using a code similar to the following Javascript snippet:
const elements = ...; // The response from the API call
// Map the elements to return for each of them their vote results
elements.data.map((element, index) => {
// Filter out the elements that are not a vote
if (element.attributes.content_type !== "vote") return null;
// Obtain the element id and the key for the question
const elementId = element.id;
const questionKey = element.attributes.question.fields.find((field) => field.key === "text").values.all;
// Fetch options in the element
const options = element.attributes.question.options;
// Fetch the keys from the element by selecting the field with key "text"
// and retrieving the value in "values.all"
const keys = options.map((option) => {
return option.fields
.find((field) => field.key === "text")
.values
.all;
});
// Fetch vote counts from stats by locating in `included` the stats item with the matching index
const stats = elements.included[index];
const votes = stats.attributes.aggregated.results.map(result => result.votes);
return {
elementId: elementId,
key: questionKey,
results: keys.map((key, index) => {
return {
key: key,
votes: votes[index]
}
})
}
})
// Filter out the elements that are not a vote
.filter(result => result != null);
As a result of the snippet above, you’ll receive a JSON response similar to the following (some data is trimmed down for brevity):
[
{
"elementId": "8cbbca06-3f47-4569-b149-634a22ea66ee",
"key": "vote 1 key",
"results": [
{
"key": "vote 1 option 1 key",
"votes": 123
},
{
"key": "vote 1 option 2 key",
"votes": 456
} ]
},
{
"elementId": "913081dd-3b4b-4696-98f2-202558e8ceac",
"key": "vote 2 key",
"results": [
{
"key": "vote 1 option 1 key",
"votes": 789
},
{
"key": "vote 2 option 2 key",
"votes": 963
} ]
}
]
We recommend to use the boolean in
attributes.results_are_final
in the included
stats of the JSON obtained to identify if the Element has been closed. If its value is true
, then you should stop performing requests to the API so as to avoid wasting resources. If the value is false
, continue requesting data by respecting the rate limits as described in the next section.Although we allow for multiple requests per second, we recommend a latency that matches your expectations on data freshness which will usually be multiple seconds between requests (e.g. every minute).
Please contact Monterosa’s support team if you require any further information regarding the implementation of voting integration by sending an email to [email protected]
Last modified 10mo ago