Reporting¶
Note
We introduce a new monetary unit of micros across our product, where one cent equals 10000 micros. One micro is 1-millionth of the local tenant currency. This will allow for a higher level of granularity when specifying the cost (per click).
We are substituting the current CPC values across the API with a bid value, and the actual (incurred) billed cost value - this to allow for better differentiation between the two. This split between bid and billed values is currently utilised for an experimental feature which adjusts the bid value for the quality of the traffic.
This new micros unit, as well as the distinction between bid and billed cost, are to become a core part of the product. We will gradually deprecate any fields with cents and local currency units across the API.
The Reporting API allows you to get statistics about the performance of your ads in a flexible ad-hoc way. It is inspired by APIs like Google Analytics and Yandex Metrica and borrows some terminology from them. It is possible to create a custom-tailored report structure using concepts like dimensions, metrics, filters, and sorting, in the API query.
Dimensions and Metrics¶
Dimensions and metrics are the main concepts used for making requests.
Dimensions¶
A dimension is an attribute of each performance event, and is used for grouping your data. For example, the dimension Country indicates where a click originated from. The Date dimension indicates the date when a particular ad was viewed or clicked. It is also possible to make a report without dimensions; in this case, the total result is calculated. Check the list of currently Supported Dimensions.
Metrics¶
Metrics are numeric values based on quantitative aggregations over dimensions’ values; every query requires at least one metric field to be requested. For example, the metric Clicks indicates the total number of clicks, while ViewCTR indicates the click-through rate for ads. Check the list of currently Supported Metrics.
Note
If you are familiar with SQL, you can think of dimensions as columns used for grouping, and metrics as the results returned by aggregate functions. The tables in most reports organize dimension values into rows, and metrics into columns.
To grasp the different views that a report can generate, below is an example of tabular representation typical for analytics reports:
DIMENSION |
METRIC |
METRIC |
---|---|---|
Country |
Clicks |
ViewCTR |
Netherlands |
1234 |
0.5678 |
Spain |
987 |
0.123 |
France |
64523 |
0.2643 |
If we add a secondary dimension, for example Category, the resulting view could be:
DIMENSION |
DIMENSION |
METRIC |
METRIC |
---|---|---|---|
Country |
Category |
Clicks |
ViewCTR |
Netherlands |
Bicycles |
356 |
0.5678 |
Netherlands |
Camping Gear |
174 |
0.455 |
Netherlands |
Mobile Phones |
546 |
0.0245 |
… |
… |
… |
… |
Spain |
Bicycles |
987 |
0.123 |
Spain |
Camping Gear |
5537 |
0.2311 |
Spain |
Mobile Phones |
987 |
0.123 |
… |
… |
… |
… |
France |
Bicycles |
12743 |
0.2357 |
France |
Camping Gear |
753 |
0.1124 |
France |
Bicycles |
882 |
0.3575 |
The dimensions supported by the reporting API have discrete values (like Netherlands or Bicycles), and the data is split by each such value, over which statistics (like Clicks or Impressions) are calculated.
Supported Dimensions¶
Name |
Type |
Description |
---|---|---|
|
String |
The date when the events happened. See Time Aggregation |
|
Long |
ID of the ad(s) |
am:CPC |
deprecated |
– |
|
Long |
The category ID of the ad(s) |
|
Long |
The region ID of the ad(s) |
|
String |
The campaign ID of the ad(s) |
Note
Date is a special dimension, in that you can specify the granularity of the timeseries breakdown. In other words, data is aggregated over units of time (such as days, weeks, months or years) when calculating metrics over it. See Time Aggregation for options on granularity.
Supported Metrics¶
Name |
Type |
Description |
|
---|---|---|---|
|
Long |
Hit |
Number of clicks |
|
Long |
Hit |
Number of impressions |
|
Long |
Hit |
Number of website clicks |
|
Long |
Hit |
Number of emails |
|
Long |
Hit |
Number of engagements from clicks |
|
Double |
Hit |
Number of clicks leads from impressions, also known as Click-through rate |
|
Double |
Hit |
Number of website leads from clicks |
am:spent |
deprecated |
– |
– |
|
Long |
Hit |
Amount spent (in Micros) |
|
Double |
Hit |
Number of engagements leads from clicks |
am:avgCPC |
deprecated |
– |
– |
|
Double |
Hit |
Average Cost Per Click in micros. |
|
Double |
Hit |
Average Spent Cost Per Click micros |
am:eCPC |
deprecated |
– |
– |
|
Double |
Hit |
Effective cost per website click. Total spent on the ad divided by the number of website clicks in micros |
am:sessionECPC |
deprecated |
– |
– |
|
Double |
Session |
Effective cost per unique sessions with website click. Total spent on the ad divided by the number of unique sessions with website clicks in micros |
|
Long |
Session |
Number of unique sessions with clicks |
|
Long |
Session |
Number of unique sessions with impressions |
|
Long |
Session |
Number of unique sessions with website clicks |
|
Long |
Session |
Number of unique sessions sending emails |
|
Long |
Session |
Number of unique sessions with engagements |
|
Double |
Session |
Number of unique sessions with clicks leads from unique sessions with impressions |
|
Double |
Session |
Number of unique sessions with website leads from unique sessions with clicks |
|
Double |
Session |
Number of unique sessions with engagements leads from unique sessions with clicks |
Scope¶
A scope for a metric defines the level at which that metric is defined — hit, session, or user. For example, am:clicks
and am:impressions
are hit level metrics, since they occur in a hit, whereas am:sessionsWithClicks
and am:sessionsWithImpressions
are session level metrics since there is a single value for these per session. Conceptually, user is the highest level scope and hit is the lowest level scope. We plan to extend support for user-level scoped metrics if there is demand for it.
Time Ranges¶
This field is used to specify one ore more distinct time periods to fetch data for, across which all other query parameters will be the same. Supplying a single range is sufficient for most needs, but the flexibility is provided to ask for multiple at the same time.
Each time range clause is defined as follows:
{
"period": <string>
"from": <string>
"to": <string>
}
There are several predefined period values at your disposal: today
, yesterday
, thisWeek
, lastWeek
, thisMonth
, lastMonth
, thisYear
, and lastYear
, with their obvious meanings. A week runs from Monday to Sunday.
If you use a predefined period for a particular time range, the from and to fields of that time range will be ignored.
To use a custom period, you need to provide the start (from) and end (to) date (both inclusive, tenant timezone assumed) in the following format: YYYY-MM-DD
.
The end date cannot be before the start one. For example:
"timeRanges": [
{
"period": "custom",
"from": "2017-01-01",
"to": "2017-10-22"
}
]
Example with multiple time ranges, mixed custom and predefined:
"timeRanges": [
{
"period": "thisWeek"
},
{
"period": "custom",
"from": "2017-01-08",
"to": "2017-01-15"
}
]
Time Aggregation¶
The aggregate
parameter is used in combination with the am:date
dimension; aggregate
is in fact mandatory when am:date
is used. It specifies the granularity/resolution of the time according to which the metrics data will be grouped in buckets. Possible values are: daily
, weekly
, quarterly
, montly
, yearly
.
Filters¶
To request a subset of your data, use filters. For example, you can filter on particular category, region, or ad ID. Filters can currently be used on any of the supported dimensions (except for am:date
). In the request query, they should be provided as an array of filter clauses which filters out the requested data on particular field values. Each filter clause is of the following form:
{
"field": <string>
"operator": <string>
"value": [<long>, ...]
}
Each filter in the list adds more restriction on the result, i.e., there is implicit AND operation between them.
The only valid operator
at the moment is the set operator in
, and requires an array of values to be passed in the value
field of the filter. For example:
"filters": [
{
"field":"am:adID",
"operator":"in",
"value": [1111,2222,3333]
},
{
"field":"am:regionID",
"operator":"in",
"value": [1234, 5678]
}
]
Note
The API does not allow to filter on the current status of ads, which means the reporting numbers apply for all ads, including those that have been deleted in the meantime. Depending on API clients feedback, we might revisit the API and add support for such filtering in the future.
Sorting¶
To sort the resulting data, use the sorts top-level query field. Sorts is an array of sort clauses, each of the following form:
{
"field": <string>
"direction": <string>
}
A field can be either a valid metric or a valid dimension. It is only permitted to sort on the fields that are requested. There are two directions for sorting: asc
(ascending) and desc
(descending).
The following example sorts first on date in descending order, followed by the ad ID in ascending order.
{
"sorts": [
{
"field":"am:date",
"direction":"desc"
},
{
"field":"am:adID",
"direction":"asc"
}
]
}
Pagination with offset and limit¶
Depending on the amount and shape of the requested data, it is worthwhile to paginate the results, for efficiency. Use the top-level offset
and limit
fields of the request query, with their standard meanings.
Enrichment¶
It is possible to enrich the reports with “handy” ad-related data for which only the present-moment values are available, such as the ad title, or category description. Requesting these fields makes sense only if am:adID
is in the requested dimensions. The supported fields are listed below:
Name |
Type |
Description |
---|---|---|
|
String |
Current title of the ad |
|
Timestamp |
Current start date of the ad |
|
Timestamp |
Current end date of the ad, if applicable |
am:currentAdCPC |
deprecated |
– |
|
Integer |
Current bid micros of the ad |
|
String |
Description of the current top-level category the ad |
|
String |
Description of the current second-level category the ad |
|
String |
Description of the current third-level category the ad, if applicable |
|
String |
Path to the current (first) image of the ad in the smallest resolution (64x64 pixels), if available |
|
String |
Current vendorID of the ad, if available |
|
String |
Description of the current (lowest-level) region of the ad, if applicable |
|
String |
Current externalID of the ad, if available |
|
String |
Current external URL of the ad, if available |
Query and Response¶
Query¶
The metrics query should be provided as a JSON object of type Metrics Request, which has these minimum requirements:
At least one valid entry in the Time Ranges field.
At least one valid entry in the Metrics field.
Here is a sample request with all top-level query fields expanded:
POST /api/sellside/metrics/data
Content-Type: application/sellside.metrics.data-v1+json
Accept: application/json
{
"timeRanges": [{
"period": "lastWeek"
}],
"aggregate": "daily",
"dimensions": ["am:date", "am:adID"],
"metrics": ["am:clicks", "am:impressions", "am:engagementCTR"],
"sorts":[{"field":"date","direction":"asc"}],
"filters": [{
"field": "am:categoryID",
"operator": "in",
"value": [1235]
},
{
"field": "am:regionID",
"operator": "in",
"value": [1,2,3,4]
}
],
"enrichment": [
"am:currentAdTitle",
"am:currentAdCategoryL1",
"am:currentAdStartDate",
"am:currentAdEndDate",
"am:currentAdVendorID",
"am:currentAdRegion",
"am:currentAdImage"
],
"limit": 5,
"offset": 2
}
Metrics Request¶
The data model of the request has the following structure:
{
"timeRanges": [<timeRange>, ...],
"aggregate": <string>,
"dimensions": [<string>, ...],
"metrics": [<string>, ...],
"sorts": [<sort>, ...],
"filters": [<filter>, ...],
"enrichment": [<string>, ...],
"limit": <integer>,
"offset": <integer>,
"searchPhrase": <string>
}
Parameter |
Description |
---|---|
|
Array of Time Ranges objects, separated by commas |
|
One of Time Aggregation string values |
|
Array of dimensions, separated by commas |
|
Array of metrics, separated by commas. At least one element is mandatory |
|
Array of Sort objects, separated by commas |
|
Array of Filters objects, separated by commas |
|
Array of ad enrichment fields, separated by commas |
|
Number of elements in the response, per time range. By default there is no limit |
|
Index of first row of the requested data (per time range), beginning with 0 |
|
String to match against an ad title |
Response¶
The response body of the API request is a JSON object of Metrics Response type. Here is a sample response for the sample request above.
{
"data": [{
"rows": [
{
"dimensions": ["2018-01-10 00:00:00", "4444"],
"metrics": [11, 22, 0.634],
"enrichment": [
"Some title of ad #4444",
"Category L1 description",
"2016-02-10 10:15:15",
"",
"fsd23432",
"City of Toronto",
"https://mp.images.icas.io/api/v1/a6519ad0/images/cd/cd41d66f-ff99-4abc-8ea8-ef2131c92b8e?rule=r-726x726"
]
},
{
"dimensions": ["2018-01-11 00:00:00", "5555"],
"metrics": [9, 20, 0.244],
"enrichment": [
"Some title of ad #5555",
"Category L1 description",
"2016-05-11 09:10:15",
"2016-07-11 06:10:10",
"123425d",
"Canada",
"https://mp.images.icas.io/api/v1/a6519ad0/images/66/6628f902-6c59-4c71-bf37-8d127a53e277?rule=r-726x726"
]
},
{
"dimensions": ["2018-01-12 00:00:00", "4444"],
"metrics": [34, 67, 0.252],
"enrichment": [
"Some title of ad #4444",
"Category L1 description",
"2016-02-10 10:15:15",
"",
"fsd23432",
"City of Toronto",
"https://mp.images.icas.io/api/v1/a6519ad0/images/fb/fba866a4-ff7b-4134-bb58-c12cfa02649e?rule=r-726x726"
]
},
{
"dimensions": ["2018-01-13 00:00:00", "5555"],
"metrics": [55, 61, 0.312],
"enrichment": [
"Some title of ad #5555",
"Category L1 description",
"2016-05-11 09:10:15",
"2016-07-11 06:10:10",
"123425d",
"Canada",
"https://mp.images.icas.io/api/v1/a6519ad0/images/d7/d7d25c7b-4494-491c-980a-7f6cdde14c21?rule=r-726x726"
]
},
{
"dimensions": ["2018-01-14 00:00:00", "5555"],
"metrics": [43, 76, 0.543]
"enrichment": [
"Some title of ad #5555",
"Category L1 description",
"2016-05-11 09:10:15",
"2016-07-11 06:10:10",
"123425d",
"Canada",
"https://mp.images.icas.io/api/v1/a6519ad0/images/f1/f16052a4-c08a-480a-855e-cbc4cd3a8e59?rule=r-726x726",
]
}
],
"count": 5
}
]
Metrics Response¶
The data model of the response has the following structure:
{
"data": [
{
"rows": [
{
"dimensions": [<string>, ... ],
"metrics": [ <number>, ...]
"enrichment": [<string>, ...]
}
, ...],
"count": <integer>
}
]
}
Parameter |
Description |
---|---|
|
Array of |
|
Array of dimension values for this row, in string format |
|
Array of metric values for this row, in number format |
|
Array of enrichment values for this row, in string format. Valid only if |
|
Actual number of rows returned |
The data
field contains an array of objects, one for each of the requested Time Ranges. It is important to remember that the order in which the metrics
, dimensions
, and enrichment
fields are requested is the same order in which they are listed in the response. The order of the objects in the rows array is not guaranteed to be deterministic unless explicit Sorting <Sorts> is used.
Examples¶
To understand the concept of dimensions and metrics, some examples of request and response are provided below, gradually increasing in complexity. In addition, a “tabular” view of the response is provided; in our experience it makes it easier to grasp these concepts.
Example 1:¶
Get all clicks and impressions for category 1234
for the previous week:
POST /api/sellside/metrics/data
Content-Type: application/sellside.metrics.data-v1+json
Accept: application/json
{
"timeRanges": [{
"period": "lastWeek"
}],
"dimensions": [],
"metrics": ["am:clicks", "am:impressions"],
"filters": [{
"field": "am:categoryID",
"operator": "in",
"value": [1234]
}]
}
{
"data": [{
"rows": [{
"dimensions": [],
"metrics": [1483, 36623] // 1483 clicks, 36623 impressions
}],
"count": 1
}]
}
am:clicks |
am:impressions |
---|---|
1483 |
36623 |
Example 2:¶
Get all clicks and impressions for categories 1234
and 5678
for the previous week, but split performance metrics per category:
POST /api/sellside/metrics/data
Content-Type: application/sellside.metrics.data-v1+json
Accept: application/json
{
"timeRanges": [{
"period": "lastWeek"
}],
"dimensions": ["am:categoryID"],
"metrics": ["am:clicks", "am:impressions"],
"filters": [{
"field": "am:categoryID",
"operator": "in",
"value": [1234, 5678]
}]
}
{
"data": [{
"rows": [{
"dimensions": ["1234"],
"metrics": [200, 400] // 200 clicks, 400 impressions for category "1234"
},
{
"dimensions": ["5678"],
"metrics": [300, 400]
}],
"count": 2
}]
}
am:categoryID |
am:clicks |
am:impressions |
---|---|---|
1234 |
200 |
400 |
5678 |
300 |
400 |
Example 3:¶
Get all clicks and impressions for categories 1234
and 5678
for the previous week, but split performance metrics per day and category. In addition, sort by date in ascending direction:
POST /api/sellside/metrics/data
Content-Type: application/sellside.metrics.data-v1+json
Accept: application/json
{
"timeRanges": [{
"period": "lastWeek"
}],
"dimensions": ["am:date", "am:categoryID"],
"metrics": ["am:clicks", "am:impressions"],
"filters": [{
"field": "am:categoryID",
"operator": "in",
"value": [1234, 5678]
}],
"sorts":[
{
"field":"am:date",
"direction":"asc"
}],
}
{
"data": [{
"rows": [{
"dimensions": ["2018-12-08 00:00:00", "1234"],
"metrics": [11, 12]
},
{
"dimensions": ["2018-12-08 00:00:00", "5678"],
"metrics": [9, 20]
},
{
"dimensions": ["2018-12-09 00:00:00", "1234"],
"metrics": [34, 67]
},
{
"dimensions": ["2018-12-09 00:00:00", "5678"],
"metrics": [19, 20]
},
...
{
"dimensions": ["2018-12-14 00:00:00", "1234"],
"metrics": [12, 90]
},
{
"dimensions": ["2018-12-14 00:00:00", "5678"],
"metrics": [43, 76]
}],
"count": 54
}]
}
am:date |
am:categoryID |
am:clicks |
am:impressions |
---|---|---|---|
2018-12-08 00:00:00 |
1234 |
11 |
12 |
2018-12-08 00:00:00 |
5678 |
9 |
20 |
2018-12-09 00:00:00 |
1234 |
34 |
67 |
2018-12-09 00:00:00 |
5678 |
19 |
20 |
… |
|||
2018-12-14 00:00:00 |
1234 |
12 |
90 |
2018-12-14 00:00:00 |
5678 |
43 |
76 |
Example 4:¶
Get all clicks, and average CPC for categories 1234
and 5678
for the previous week, but split performance metrics per ad ID. In addition, enrich the response rows with current ad title and vendorID. Limit to 3 results:
POST /api/sellside/metrics/data
Content-Type: application/sellside.metrics.data-v1+json
Accept: application/json
{
"timeRanges": [{
"period": "lastWeek"
}],
"dimensions": ["am:adID"],
"metrics": ["am:clicks", "am:avgCPC"],
"filters": [{
"field": "am:categoryID",
"operator": "in",
"value": [1234, 5678]
}],
"enrichment":["am:currentAdTitle", "am:currentAdVendorID"]
"limit": 3
}
{
"data": [{
"rows": [{
"dimensions": ["11111"],
"metrics": [11, 4.5],
"enrichment": [
"Ad title #11111",
"vendor11111"
]
},
{
"dimensions": ["33333"],
"metrics": [9, 3.0],
"enrichment": [
"Ad title #33333",
"vendor33333"
]
},
{
"dimensions": ["22222"],
"metrics": [34, 2.3],
"enrichment": [
"Ad title #33333",
"vendor33333"
]
}],
"count": 3
}]
}
am:adID |
am:clicks |
am:avgCPC |
am:currentAdTitle |
am:currentAdVendorID |
---|---|---|---|---|
11111 |
11 |
4.5 |
Ad title #11111 |
vendor11111 |
33333 |
9 |
3.0 |
Ad title #33333 |
vendor33333 |
22222 |
34 |
2.3 |
Ad title #22222 |
vendor22222 |
Example 5:¶
Get all clicks, and average spent micros for categories 1234
and 5678
for the previous week, but split performance metrics per ad ID. In addition, enrich the response rows with current ad title and vendorID. Limit to 3 results:
POST /api/sellside/metrics/data
Content-Type: application/sellside.metrics.data-v2+json
Accept: application/json
{
"timeRanges": [{
"period": "lastWeek"
}],
"dimensions": ["am:adID"],
"metrics": ["am:clicks", "am:avgSpentMicros"],
"filters": [{
"field": "am:categoryID",
"operator": "in",
"value": [1234, 5678]
}],
"enrichment":["am:currentAdTitle", "am:currentAdVendorID"]
"limit": 3
}
{
"data": [{
"rows": [{
"dimensions": ["11111"],
"metrics": [11, 45000.0],
"enrichment": [
"Ad title #11111",
"vendor11111"
]
},
{
"dimensions": ["33333"],
"metrics": [9, 3.0],
"enrichment": [
"Ad title #33333",
"vendor33333"
]
},
{
"dimensions": ["22222"],
"metrics": [34, 2.3],
"enrichment": [
"Ad title #33333",
"vendor33333"
]
}],
"count": 3
}]
}
am:adID |
am:clicks |
am:avgSpentMicros |
am:currentAdTitle |
am:currentAdVendorID |
---|---|---|---|---|
11111 |
11 |
45000.0 |
Ad title #11111 |
vendor11111 |
33333 |
9 |
30000.0 |
Ad title #33333 |
vendor33333 |
22222 |
34 |
23000.0 |
Ad title #22222 |
vendor22222 |
Final remarks:¶
In the SQL note, the enrichment fields can be seen as a left outer join operation.
The reporting numbers may slightly differ (±0.005%) from the final billing values, due to the nature of the system where we store the reporting data.
The API does not allow to filter on the current status of ads, which means the reporting numbers apply for all ads, including those that have been deleted in the meantime. Depending on API clients feedback, we might revisit the API and add support for such filtering in the future.
Errors¶
Each error contains a code
and text
attributes providing a numeric error code and a simple English error message. An error may contain a field
attribute describing the field where the error occurred and an additonal arg
attribute further specifying the error.
Field |
Code |
Message |
Description |
---|---|---|---|
entire response object |
1000 |
internal error |
Failed to execute query |
entire request object |
1005 |
invalid json |
Could not parse request data |
|
2000 |
missing argument |
The field ‘aggregate’ was missing |
|
2000 |
missing argument |
The field ‘metrics’ was missing |
any non-allowed field |
2001 |
invalid argument |
The value of field ‘dimensions:[am:wrongDimension]’ was invalid |