Traffic sources and UTMs
Compare campaigns, sources and ads by views, retention, pitch and sales
Every parameter in the address of the page where the player was watched is recorded with the session, as long as it has a value: usually the UTMs (utm_source, utm_medium, utm_campaign, utm_term, utm_content), src and sck, but any other parameter too. Grouping the metrics by their values tells which source, campaign or ad brings the viewers who stay and buy.
You need the player's ID, the video's duration and the pitch time. GET /players/list returns all three.
See which parameters your traffic carries
POST /traffic_origin/valid_utms counts how many times each parameter was recorded for the player:
curl -X POST 'https://analytics.vturb.com/traffic_origin/valid_utms' \
-H "X-Api-Token: $VTURB_API_TOKEN" \
-H 'X-Api-Version: v1' \
-H 'User-Agent: my-integration/1.0' \
-H 'Content-Type: application/json' \
-d '{
"player_id": "64a5c8072e6fd10009828db2",
"start_date": "2026-09-01 00:00:00",
"end_date": "2026-09-07 23:59:59",
"timezone": "America/Sao_Paulo"
}'[
{ "utm_source": 1520 },
{ "utm_campaign": 1488 },
{ "utm_content": 960 },
{ "src": 312 }
]Each item holds one parameter and its count. start_date is required; end_date is optional.
Compare the values of one parameter
POST /traffic_origin/stats returns one row per value of the parameter in query_key:
curl -X POST 'https://analytics.vturb.com/traffic_origin/stats' \
-H "X-Api-Token: $VTURB_API_TOKEN" \
-H 'X-Api-Version: v1' \
-H 'User-Agent: my-integration/1.0' \
-H 'Content-Type: application/json' \
-d '{
"player_id": "64a5c8072e6fd10009828db2",
"start_date": "2026-09-01 00:00:00",
"end_date": "2026-09-07 23:59:59",
"timezone": "America/Sao_Paulo",
"query_key": "utm_source",
"video_duration": 2340,
"pitch_time": 1260
}'Leave query_key out to get every parameter at once, each row with its own query_key, or send query_keys, a list, to get only those parameters.
video_duration and pitch_time, in seconds, are not read from the player here: send them with the values from GET /players/list. video_duration is required; send pitch_time when the player has one, and leave it out when the list returns 0.
[
{
"query_key": "utm_source",
"grouped_field": "facebook",
"total_viewed_device_uniq": 840,
"total_started_device_uniq": 410,
"play_rate": 48.8,
"engagement_rate": 41,
"total_over_pitch": 140,
"total_under_pitch": 290,
"over_pitch_rate": 32.55,
"total_conversions": 22,
"overall_conversion_rate": 5.36,
"total_amount_brl": 437800
}
]grouped_field is the parameter's value. The fields have the names and formulas of the daily report, with these differences:
total_over_pitchandtotal_under_pitchcount only the sessions that pressed play, and a session that pressed play with no progress recorded counts under the pitch.- Sales and their amounts are selected by when the sale was registered, not by the time of the click.
engagement_rateis a whole number, andplay_ratenever goes above 100.
Follow them day by day
POST /traffic_origin/stats_by_day takes the same body with query_keys, a list, in place of query_key, and returns one row per day, parameter and value, each with its date_key. A day without traffic comes back as a row with an empty query_key and grouped_field, and zeros:
{
"player_id": "64a5c8072e6fd10009828db2",
"start_date": "2026-09-01 00:00:00",
"end_date": "2026-09-07 23:59:59",
"timezone": "America/Sao_Paulo",
"query_keys": ["utm_source", "utm_campaign"],
"video_duration": 2340,
"pitch_time": 1260
}Use it to see whether a campaign holds up over the week or fades after the first days.
Compare where each source leaves the video
POST /times/user_engagement_by_traffic_origin returns the retention data split by value. values lists the values to compare:
{
"player_id": "64a5c8072e6fd10009828db2",
"start_date": "2026-09-01 00:00:00",
"end_date": "2026-09-07 23:59:59",
"timezone": "America/Sao_Paulo",
"query_key": "utm_source",
"values": ["facebook", "google"]
}[
{ "group_key": "facebook", "group_values": [{ "timed": 0, "totalUsers": 120 }, { "timed": 5, "totalUsers": 31 }] },
{ "group_key": "google", "group_values": [{ "timed": 0, "totalUsers": 64 }, { "timed": 5, "totalUsers": 12 }] }
]As in the retention curve, each item counts the sessions that stopped at that second. Turn each group_values into a curve the same way, renaming totalUsers to total_users, and draw the sources on one chart: the one whose curve stays higher up to the pitch is bringing the viewers who watch.
Keep the parameters consistent
The values are grouped as they arrive in the address, once URL-decoded: black%20friday and black friday are one row, but Facebook and facebook are two. A session counts once per parameter, under the last value it carried. Standardize how your campaigns write their parameters, and the comparison works without cleaning the data afterwards.