This is the documentation of version 0.64.0. Go to the latest version, 1.0.0-rc.5.

Traffic area analytics

Request Access

Important note Traffic Area Analytics is unavailable on a Freemium or Pay As You Grow (PAYG) basis. Click the Request Access button above to contact our Sales team.

trafficAreaAnalytics runs a historical traffic report for a polygon or multi-polygon region: give it the region, a date range or a list of dates, and the metrics you want, and one call returns the aggregates, their time series and per-tile values — no polling.

Introduction

Core concepts

A report is described by:

Basic usage

Traffic Area Analytics is a TomTom Move Portal product, so it takes a Move Portal API key, not the Maps API key the rest of the SDK uses. Keep your Maps key in TomTomConfig and pass the Move Portal key per call (per-call overrides):

import { TomTomConfig } from '@tomtom-org/maps-sdk/core';
import { trafficAreaAnalytics } from '@tomtom-org/maps-sdk/services';

TomTomConfig.instance.put({ apiKey: 'YOUR_API_KEY' }); // Maps API key, for everything else

const result = await trafficAreaAnalytics({
    apiKey: 'YOUR_MOVE_PORTAL_KEY', // this service only
    startDate: '2024-08-06',        // YYYY-MM-DD string or Date
    endDate: '2024-08-12',          // optional: defaults to three days ago
    metrics: ['speed', 'congestionLevel'],
    functionalRoadClasses: ['MOTORWAY', 'MAJOR_ROAD', 'OTHER_MAJOR_ROAD', 'SECONDARY_ROAD'],
    hours: [5, 6, 7, 15, 16],       // UTC: Amsterdam's rush hours in summer time (UTC+2)
    geometry: {
        type: 'Polygon',
        coordinates: [
            [[4.896128, 52.382402], [4.875701, 52.368459], [4.923611, 52.36341], [4.896128, 52.382402]],
        ],
    },
});

const region = result.features[0];
console.log(region.properties.baseData.speed);           // km/h
console.log(region.properties.baseData.congestionLevel); // %

A 401 or 403 on this service usually means the call went out with your Maps API key.

Available metrics

areaAnalyticsMetricKeys lists them:

metrics value Description Unit
'speed' Average speed on the road network km/h
'freeFlowSpeed' Average speed under uncongested conditions km/h
'congestionLevel' Increase in travel time above free flow %
'travelTime' Average travel time per 10 km minutes
'networkLength' Total length of the road segments with data metres

Parameters

Date selection

Give either startDate, with an optional endDate, or days. Both take Date objects or 'YYYY-MM-DD' strings, read as UTC calendar days.

Continuous range (startDate / endDate)

// The last week with data: endDate defaults to three days ago
const startDate = new Date();
startDate.setUTCDate(startDate.getUTCDate() - 9);
const lastWeek = await trafficAreaAnalytics({ startDate, /* ... */ });

const firstWeekOfAugust = await trafficAreaAnalytics({ startDate: '2024-08-01', endDate: '2024-08-07', /* ... */ });

Specific dates (days)

Each of days is two days ago or earlier.

// Every Monday of August 2024
const result = await trafficAreaAnalytics({
    days: ['2024-08-05', '2024-08-12', '2024-08-19', '2024-08-26'],
    metrics: ['speed', 'congestionLevel'],
    functionalRoadClasses: 'all',
    hours: [7, 8, 9, 17, 18],
    geometry: { /* ... */ },
});

Functional road classes

The functionalRoadClasses parameter selects the road classes, or 'all'. The importable functionalRoadClasses catalogue lists them, most important first:

Value Description
'MOTORWAY' Motorways, freeways, and major roads
'MAJOR_ROAD' Major roads, less important than motorways
'OTHER_MAJOR_ROAD' Other major roads connecting neighbouring regions
'SECONDARY_ROAD' Secondary roads linking parts of the same region
'LOCAL_CONNECTING_ROAD' Local roads providing settlement access
'LOCAL_ROAD_HIGH_IMPORTANCE' Local roads of high importance within a settlement
'LOCAL_ROAD' Local roads within settlement sections
'LOCAL_ROAD_MINOR_IMPORTANCE' Local roads of minor importance (dead-ends, alleys)
'OTHER_ROAD' Other roads (paths, cycle routes, pedestrian infrastructure)

Region geometry

geometry takes one GeoJSON Polygon or MultiPolygon, in [longitude, latitude] order, each ring closed (its first and last positions equal):

const geometry = {
    type: 'MultiPolygon',
    coordinates: [
        [[[4.89, 52.37], [4.91, 52.37], [4.91, 52.39], [4.89, 52.39], [4.89, 52.37]]],
        [[[4.95, 52.40], [4.97, 52.40], [4.97, 52.42], [4.95, 52.42], [4.95, 52.40]]],
    ],
};

A city's boundary comes from geocodeOne and geometryData:

import { geocodeOne, geometryData, trafficAreaAnalytics } from '@tomtom-org/maps-sdk/services';

const place = await geocodeOne('Amsterdam, Netherlands');
const boundaries = await geometryData({ geometries: [place] });

const result = await trafficAreaAnalytics({
    startDate: '2024-08-06',
    endDate: '2024-08-12',
    metrics: ['speed', 'congestionLevel'],
    functionalRoadClasses: 'all',
    hours: [7, 8, 9, 17, 18],
    geometry: boundaries.features[0].geometry,
});

name optionally names the report; the SDK names one when you don't.

Response structure

The result is a TrafficAreaAnalytics FeatureCollection with one feature, the submitted region.

Top-level properties

const { startDate, endDate, metrics, frcs, ranges } = result.properties;

Feature properties

const region = result.features[0];
const { baseData, timedData, tiledData, anomalies } = region.properties;

Base data

baseData aggregates each requested metric over the whole period; the metrics not requested are absent:

const { speed, freeFlowSpeed, congestionLevel, travelTime, networkLength } = region.properties.baseData;

Timed data

timedData breaks the metrics down per granularity. Each has its own entry type, with the metric fields of baseData and its time identifiers always set:

Granularity Entry type Time identifiers
yearly AreaAnalyticsYearlyEntry year
monthly AreaAnalyticsMonthlyEntry year, month (1–12)
weekly AreaAnalyticsWeeklyEntry year, week (ISO 8601, from Monday)
daily AreaAnalyticsDailyEntry date (midnight UTC)
hourly AreaAnalyticsHourlyEntry date, hour (0–23)
average AreaAnalyticsAverageEntry day (1 = Monday to 7 = Sunday), hour (0–23)
const { daily, hourly, average } = region.properties.timedData;

daily?.forEach((entry) => {
    console.log(entry.date.toISOString().slice(0, 10), entry.speed, entry.congestionLevel);
});

// hourly spans every day of the range, so read the day with the hour
hourly?.forEach((entry) => {
    console.log(`${entry.date.toISOString().slice(0, 10)} ${entry.hour}:00: ${entry.speed} km/h`);
});

average?.forEach((entry) => {
    console.log(`Day ${entry.day}, ${entry.hour}:00: ${entry.congestionLevel}%`);
});

Tiled data

tiledData holds per-tile values, when the response has them: each tile's tileCentre ([longitude, latitude]) and the requested metrics, networkLength being the road length within that tile.

region.properties.tiledData?.tiles.forEach((tile) => {
    const [lon, lat] = tile.tileCentre;
    console.log(`Tile at [${lon}, ${lat}]: congestion=${tile.congestionLevel}%`);
});

The Traffic Area Analytics Module draws them: pass it the whole response.

Anomalies

anomalies maps a metric to its anomalies: runs of UTC hours, each labelled with the public holidays it overlaps. It is currently always empty: the service detects anomalies only over 35 days or more, beyond a request's 31-day limit.

const speedAnomalies = region.properties.anomalies?.speed ?? [];
speedAnomalies.forEach((anomaly) => {
    console.log(anomaly.startDate, anomaly.endDate, anomaly.labels);
});

Error handling

A failed call rejects with an SDKServiceError, carrying the HTTP status and the service; a request breaking the date rules rejects before it is sent (Error handling).

API reference

Related guides and examples

Related examples

Related guides