Changelog 1.0
The changes in each 1.0 release of @tomtom-org/maps-sdk, newest first. The detailed changelog on GitHub has the technical details of each release, and the release notes the status of each version. To move from a 0.x release, follow Upgrading to 1.0.
1.0.0-rc.7
Released October 29, 2026. Its documentation is archived on GitHub.
Improvements and fixes
- services: a call that adds its own
apiKeyto a request for the configured proxy sends the proxy’s session cookie with it, sotrafficAreaAnalyticswith a Move Portal key works from a page on a site other than the proxy’s. A call that changescommonBaseURLdecides on its own merged config
1.0.0-rc.6
Released October 26, 2026. Its documentation is archived on GitHub.
Breaking changes
-
map: The attribution shows the TomTom and OpenStreetMap credits as logos, each keeping its credit’s link, with any other credit after them as text.
attributiontakesposition(the corner) andpaddingto place the logos. It only places them: no value turns them off or swaps them for plain text- The logos are black with a white outline on every style, light and dark
- A soft, blurred backdrop sits behind the logos so they stand out from map labels. It follows the style’s theme across
setStyle.backdrop: falseremoves it, and the logos stay - Your own
creditsfollow the logos - Breaking: CSS or layout code aimed at
.maplibregl-ctrl-attribno longer finds the attribution: place the logos clear of your layout withpositionandpadding
-
core, services, map: a refused API key reads the same on the map as on a service call, so
PrivatePreviewAccess, which both errors now carry, is imported from@tomtom-org/maps-sdk/core, not@tomtom-org/maps-sdk/services- core:
APIErrorDetailsdeclaresapiErrorCodeandprivatePreviewAccessonce, for one function to read a service call’s error and the map’s alike - map:
TomTomMapErrorimplements it, asSDKServiceErrordoes - map: a style, tile, sprite or glyph refused with a JSON body names the API’s own code in
apiErrorCode,'InvalidReferer'when the key’s domain restriction refused the page and'Forbidden'when the API isn’t enabled for the key, and adds the API’s own message tomessage - map: the message of a failed style, tile, sprite or glyph request shows the API key in its URL as
key=…, so the message is safe to log - map: a plugin’s data that fails to load, such as the Landmarks 3D tiles, reaches
addErrorHandleras aTomTomMapErrorunder the plugin’s source, coded by status like the map’s own tiles
- core:
Improvements and fixes
-
map:
BaseMapModulelights up the style’s own 3D buildings:buildings3D.hoverandbuildings3D.clickset the colour a hovered or clicked building turns towards, andsetBuildingColorsgives the buildings you pick by id a colour of their own- A building reacts while a
BaseMapModulehandler reaches thebuildings3Dgroup, and stays as drawn while you leave both colours unset - A building the map data splits into parts lights up and takes its colour whole, by the id of any of its parts
getBuildingIdAtnames the building standing at a position, to highlight buildings you know by place- Features of the base map, the POIs and the traffic tiles now carry their
eventStateas a feature state, for your ownstyling.layerspaint to read - The 3D buildings’
fill-extrusion-coloris now an expression around the style’s colour on every map, sogetPaintPropertyand an exported style return that expression; the style’s own colour is its output at intensity 0 - The four settings are knobs of
baseMapKnobCatalogue,buildings3D.{hover,click}.{color,intensity}
- A building reacts while a
-
map:
getMapLightreads where the map’s light comes from, as a compass direction and an altitude, so a layer of your own can light its surfaces from the same direction as the 3D buildings- With neither
view.light.directionnorview.light.altitudeset, the light knobs leave MapLibre’s position unset, so a colour, intensity or alignment on its own, and a clean style switch, leavegetMapLightundefinedinstead of writing the 210°/60° default
- With neither
-
services: an unknown POI category logs its id, not the name the service sent
-
core: geometry helpers handle routes, boxes and cells across the antimeridian, and a new stop slots into a round trip where it belongs
- core:
bboxFromGeoJSONgives the narrowest box around shapes on both sides of the antimeridian, andundefinedfor a geometry missing its coordinates - core: route positions, owned polygons and hexagon cells wrap past ±180° instead of jumping across the map
- core: departure, arrival, waypoint, border and tollgate instructions carry no lanes
- core:
findBestWaypointInsertionIndexandwithInsertedWaypointsslot a new stop on a round trip between the right passes of its origin and destination - core:
calculateProgressAtRoutePoint,getRouteProgressBetweenandgetRouteProgressForSectionreturnundefinedfor a path index that is no whole number, where they returnedNaNvalues - core:
formatDurationrounds a half minute up, andformatDistanceandformatDurationkeep the global units for an option leftundefined - core: bundlers drop
TomTomConfigfrom an app that never reads it - core: a junction’s instruction keeps its lanes where a waypoint instruction shares its path point
- core:
-
map:
setLanguagealso translates style labels that read their name inside an expression, such as POIs, states, peaks and ferries- map: a sourceless map error is
STYLE_LOAD_FAILEDonly while a style loads, andINTERNALotherwise - map: colour knobs refuse colour forms MapLibre can’t paint, instead of drawing nothing
- map:
CustomGeoJSONModule.applyConfigreplaces a layer whose type changes instead of throwing - map: a failed or superseded style switch finishes cleanly, and a switch to the same style resets knobs and raw edits
- map: route summary bubbles stay above their route on a rotated map, hidden sections stay hidden, and section icons follow their size knob
- map: places keep another module’s config properties, draw a mapped category icon, and rebuild once per knob batch
- map: traffic incident icons keep their visibility across config changes, opacities clamp to 0–1, and area analytics grids take regions across the antimeridian
- map:
setLanguagerelabels only the map style’s own labels, so module and app layers keep the text they were given - map:
calculateFittingBBoxexpands latitudes in Web Mercator, asfitBoundsframes them, so its south and north move - map: a custom
icon.defaultimage repositions the place labels, a hoveredbase-mapplace draws once, and a clickedpin-clusteredmicro dot stays drawn - map:
invertFeatureshades a polygon’s holes, a MultiPolygon’s title sits on its outer ring, and an expressionfill.colorfalls through tocolor - map: shown-features handlers keep firing after one of them unsubscribes
- map: custom images load from an SVG file’s URL, from SVG markup with text past Latin-1 and from another origin that allows CORS
- map: each
where()scope over one source keeps its own hover and cursor,offalso removes the handlers on a source a config change dropped, and an unsubscribe removes only the registration it came from - map: routes, places, area analytics and traffic filters reload only the sources a change reaches
- map: a clean switch to the style already loaded removes the traffic flow and incident filters, as it does the POI ones
- map: the map look reads a page background the browser reports in
oklch()as painted - map: POI and place category icon offsets apply where the style’s own icon offset is a zoom ramp
- map: a sourceless map error is
-
services: a
geoBiaswith both a point and a bounding box fails validation asINVALID_REQUEST, and error statuses survive bodies the SDK can’t read- services: search results map their fields, opening hours and polygon boxes as the service sends them, and keep area-scoped brands
- services: an XML error over HTTP/2 names its status, and an unread error body is freed
- services: a zero
Retry-Afterstill backs off before the next try - services: suggestions pick their concept independently of
limit - services: traffic area analytics checks its date rules before the request, rejecting a call that breaks them as
INVALID_REQUEST - services: an along-route search whose filters hold only keys it doesn’t declare fails validation, as one with no filter does
- services: a route leaves out
vehicleRestrictedwhen it has none, as it does every other section type, andsectionTypes: ['lanes']withoutguidancerequests no sections - services:
geometryDatasends a footprint that several places share once, and gives it the first place’s properties, where the last place’s won - services: an
INVALID_REQUESTmessage lists its issues without theIssues:JSON, which stays in the error’sissues - services: fuzzy search drops a query intent it doesn’t know, and reverse geocoding an area type it doesn’t know, rather than returning
undefined - services:
trafficIncidentDetailssends a polygon cut at 180° as one box across the antimeridian, not one around the world - services: a cached
getPOICategoriescall rejects an insecure base URL, as an uncached one does
1.0.0-rc.5
Released October 22, 2026. Its documentation is archived on GitHub.
Breaking changes
-
core:
formatDurationreturns astringfor anynumber, so you can pass its result where astringis required with no fallback- Breaking: core:
0gives"0 min"and any other duration under 30 seconds gives"< 1 min", in your minute units, where it returnedundefined. Onlyundefinedstill returnsundefined, so whereundefinedhid a label for no delay or no wait, test the seconds before you format them - map:
RoutingModulestill leaves out a traffic delay, a jam delay, a stop’s wait and a duration difference that round to no minutes, and a summary bubble on a route under 30 seconds reads"< 1 min"
- Breaking: core:
Improvements and fixes
-
map:
calculatePaddedBBox,calculatePaddedCenterandcalculateFittingBBoxcut an element short of the map’s full width and height from the side that leaves the most of the map visible, so a toolbar inset from the map edges leaves the area below it visible rather than none- map: this changes the result for any such element whose closest map edge is not that side, whether it floats, sits in a corner or touches one edge. A 600 × 150 px panel against the left edge of a 1280 × 720 px map cuts from the top, and a short panel in the top-right corner cuts from the top rather than the right
- map: an element spanning the map’s full width or height cuts as before. If two sides leave the same area, the side nearest a map edge wins
-
map: waypoint labels win over the route’s section icons, and the section focus ring outlines the route instead of crossing it
- A tunnel, closed-to-vehicles, ferry, toll-road or traffic icon under a stop’s name gives way to it, as it does to the pin, rather than pushing the name aside.
setSectionFocusdraws its ring under the route’s own lines, so on a road that doubles back, or where focused sections meet end to end, the route covers the ring rather than the ring crossing it.
-
services:
geocodeanddiscoverPlacestake a bare query string, the same as{ query }, asgeocodeOneanddiscoverOnePlacealready do- services:
discoverPlaces('coffee')runs a fuzzy search and is typed as one
- services:
1.0.0-rc.4
Released October 21, 2026. Its documentation is archived on GitHub.
Breaking changes
-
core, services: a route or leg summary’s
trafficDelayInSecondsandtrafficLengthInMetersare optional, present only when the routing service sends them, rather than0when it leaves them out- core:
trafficDelayInSecondsis the delay of the traffic events alongtrafficLengthInMeters. For the gap to free-flow, useMath.max(0, liveTrafficIncidentsTravelTimeInSeconds - noTrafficTravelTimeInSeconds), withcomputeTravelTimeFor: 'all'
- core:
-
core: the bbox utilities read and return a box crossing the antimeridian as
west > east, as RFC 7946 and the services do, so fitting the map to results around Fiji frames Fiji rather than the whole world- Breaking: core:
bboxFromCoordsArray, andbboxFromGeoJSONon points, return the box across the antimeridian when it is narrower than the one from the lowest to the highest longitude. A tie, or input spanning -180 to 180, keeps the latter, so every country in the world still gives[-180, …, 180] - Breaking: core:
bboxFromGeoJSONreads a line or ring along its edges, which don’t wrap, so a ring past 180 gives the box across the antimeridian and one from -100 to 100 stays[-100, …, 100] - Breaking: core:
bboxFromBBoxes, andbboxFromGeoJSONon several features or parts, return the narrowest box containing every input, so merging a box across the antimeridian with another keeps both - Breaking: core:
polygonFromBBoxdraws a box across the antimeridian with its east edge ateast + 360, around the box rather than the rest of the world, andbboxFromGeoJSONreads that ring back as the same box - map:
TomTomMap.getBBoxwith padding returns a view across the antimeridian aswest > east, and a view wider than 180° whole - services:
geometrySearchranks a polygon across the antimeridian by its own width when it keeps the largest 50
- Breaking: core:
-
core:
Languageholds every language the map labels carry, somap.setLanguage('hi-IN')labels the map in Hindi, and the services send each API a code it takes- Breaking: core:
Languageandlanguagesgainca-ES,et-EE,eu-ES,gl-ES,he-IL,hi-IN,hr-HR,ja-JP,kk-KZ,lv-LV,ro-RO,sr-RSanduk-UA, so aRecord<Language, …>of your own needs an entry for each - map: the map labels in each of them, and the traffic incident descriptions in Catalan, Estonian, Hebrew, Japanese, Latvian and Romanian
- services: a behaviour change.
zh-Hansgoes out aszh-CNandzh-Hantaszh-TW, so every service but traffic incidents, which lack Simplified Chinese, answers in that script, where it picked the script by place and answered Singapore in English. Search, geocoding, suggestions and POI categories take both, where they answered each with a 400 - services: search, geocoding and suggestions answer
hi-INandja-JPin local names, and POI categories in English. All four answeren-CAin British English andes-MXin Latin American Spanish, where they answered each with a 400. POI categories takengtandngt-Latntoo - services:
trafficIncidentDetailstakes everyLanguage, answering in the nearest language the incident tiles have, or in English, where it answered one it lacks, such asen-AUorpt-BR, with a 406
- Breaking: core:
-
core:
main-when-availableuses a place’s first untyped entry point when none is typed'main', so a reverse geocoded place routes to the road-snapped point the service returns rather than to the queried point- Breaking: core:
getPosition(place, { useEntryPoint: 'main-when-available' })returns that entry point’s position. A place whose entry points are all'minor'keeps its own position - Breaking: services:
calculateRoutewithuseEntryPoints: 'main-when-available'sends such a stop at that entry point - Breaking: map:
RoutingModulewithwaypoints.entryPoints: 'main-when-available'draws such a waypoint at that entry point
- Breaking: core:
-
map:
styling.layers.queryselects style layers by exact id, derives a paint or layout value from the one beneath it, and narrows a layer’s filter with one more clause, all kept across style switches;POIsModulehides or shows single POIs by id, which makesfilters.categoriesoptional- map:
LayerQuerytakesids, the exact style layer ids to select - map:
setPaintandsetLayouttake a function(valueUnder, layerId) => valuefor any property, worked out from the style’s own value, or the one a knob set, and again whenever that value changes - map:
addFilterClauseandremoveFilterClauseadd a clause to a layer’s filter,and-ed with the style’s own and with the filters other modules add, instead of replacing it assetFilterdoes - map:
POIsModule’sfilters.idstakes aValuesFilterof POI ids, besidefilters.categories - Breaking: map:
POIsModuleConfig’sfilters.categoriesis optional, sofilterscan holdidsalone. Code readingconfig.filters.categoriesmust handleundefined
- map:
-
map: drag features on every module and scope with the new
dragstart,draganddragendevents, such as a route’s waypoints, its lines or a place’s pin- map: a drag handler makes its features draggable with the mouse or one finger. They show the new
cursorOnDraggablecursor,'grab'by default, the map doesn’t pan under the drag, and the release fires noclick - map:
RoutingModulereports the drag onevents.waypointsandevents.mainLinesand plans nothing, so you callcalculateRouteandshowRouteswith the moved or inserted stop, or let the route dragging plugin do it - Breaking: map:
EventTypealso holds the three drag types, so aswitchor aRecordover it needs them. Event states keep to the click and hover types, asEventStateandSetEventStateOptions.statenow say on their own
- map: a drag handler makes its features draggable with the mouse or one finger. They show the new
-
map:
SectionLinePattern, deprecated in 1.0.0-rc.3, is removed. UseLinePattern, the same type, which geometries and reachable range borders share too -
map:
TomTomMaptakes atransformRequestthat holds or rewrites each map request after the SDK’s own, and may return a promise, so an app can wait for its proxy session or point tiles at its own cache- map:
transformRequest, typedMapRequestTransform, gets the request the SDK built, with its URL, headers and credentials, and stays in place throughsetLanguageandsetGeopoliticalView - Breaking: map: the map no longer awaits
globalThis.__DEMOS_PROXY_ENSURE_SESSION__before its requests. An app that set it passes the same function astransformRequestinstead:transformRequest: async (request) => { await ensureSession(); return request; }
- map:
-
map: when the map’s style fails to load, a module’s
create()orget()rejects with the style’sTomTomMapError, the one the error handlers get, so anawaiton it lands in yourcatchinstead of waiting forever- Breaking: map: after a style load fails, a module call that waits for the map, such as
showRoutesorshow, rejects with that error too, until asetStyleloads a style. Once one loads, create again only the modules whosecreate()orget()rejected: the others restore themselves - map: a style, tile, sprite or glyph request that gets no response, offline or blocked, reaches the error handlers as
NETWORK_NOT_AVAILABLE, which can be retried, instead ofSTYLE_LOAD_FAILEDorINTERNAL
- Breaking: map: after a style load fails, a module call that waits for the map, such as
-
services:
calculateRoutereturns the curves of each route assections.curveand the winding stretches they make up assections.curvyStretchwhen itssectionTypesnames them, so you can keep a motion-sick passenger off winding roads or send a motorcyclist down them- Breaking: core:
SectionType,sectionTypes,inputSectionTypesandinputSectionTypesWithGuidanceinclude'curve'and'curvyStretch'. ARecord<SectionType, …>needs an entry for each - Breaking: services:
InputSectionTypeincludes them too - Breaking: map:
DrawnSectionType,GeneratedSectionType,drawnSectionTypesandgeneratedSectionTypesinclude them, so aRecord<DrawnSectionType, …>needs an entry for each.SectionKnobNameincludes'kerb', so aRecord<SectionKnobName, …>needs one for it - core: each curve has its
headingChangeInDegrees, positive to the right, itsradiusInMeterswhere it turns tightest, itslengthInMetersand acurvinessScore, its arc weighted by how tight it is as roadcurvature.com scores roads, aseverityfrom 0 to 1, how much a driver slows down for it from the speed limit on the road into it, weighing its radius, how far it turns and whether it’s a turn at a junction, and on a route with guidance themaneuverof a junction instruction on it. An instruction that keeps to the road, such as “Turn left to stay on the SS38” at a hairpin, names none - core: each curvy stretch groups three or more curves within 500 m of each other, ended by a curve with a maneuver, with its
curveCount,hairpinCount(its hairpins, curves turning 140° or more on a radius of 40 m or less, which the newisHairpintells),lengthInMeters,minRadiusInMetersandcurvinessScore, its curves’ scores added up - core:
getCurveSectionsandgetCurvyStretchSectionsfind them with thresholds of your own. A curve’sseverityreads the route’sspeedLimitsections, so ask for them along with the curves - services:
calculateRoutetakes those thresholds ascurveDetection, aCurveDetectionOptionswith the turn, radius and straight that make a curve and the curve count and gap that make a curvy stretch - core: the new
withCurveSectionsfinds a route’s curves and curvy stretches again with other thresholds, keeping its other sections, so you can tune them on routes you already have, with no new request - core:
compareRoutesandgetSectionsWithinweighcurveandcurvyStretchwhen you pass notypes, on routes that carry them - services: the SDK finds
curveandcurvyStretchin the route’s geometry, only when asectionTypeslist names them, so acalculateRoutewithoutsectionTypesdoes no more work than before.inputSectionTypesandinputSectionTypesWithGuidancename them, so a list built from those finds them too. It never sends them to the routing API - core: the new
defaultSectionTypesnames the sections acalculateRoutewithoutsectionTypesreturns, sosectionTypes: [...defaultSectionTypes, 'curve', 'curvyStretch']keeps them all and adds the curves - map: the routing module draws
curveandcurvyStretchas bands when you switch them on withsections.curve: { visible: true }, at the width of every other section band. The curves draw rose, a colour no traffic delay takes, deeper the higher theirseverity, above the stretch they make up, which draws the same rose fainter - map: from zoom 12, a curve of 60 m radius or less carries a kerb, short stripes of a tint of its colour, nearly white on a light map and nearly black on a dark one. The new
sections.curve.kerb.colorknob sets the stripes’ colour, andsections.curve.kerb.visible: falsedraws one plain line.layers.sections.curvetakes the kerb asrouteSectionCurveKerb
- Breaking: core:
-
map: the
maplibre-glpeer dependency moves up to^6.15.0- Breaking: services: the
zodpeer dependency moves up to^4.6.7. - services:
geometryDatareports ageometrieslist over 20 as one issue on that field, not as a union mismatch.
- Breaking: services: the
-
services: along-route results from
discoverPlaces({ route })carry their detour as typedAlongRoutePlaceProps,detourTimeInSecondsanddetourDistanceInMeters, so you read them without a cast- Breaking: services: the untyped
properties.detourTime,detourDistanceanddetourOffsetare nowdetourTimeInSeconds,detourDistanceInMetersanddetourOffsetInMeters. Either detour can be negative, when the route through the place is faster or shorter than the original - services:
detourOffsetInMeterscomes with results sorted by'detourOffset'
- Breaking: services: the untyped
-
services:
geocodeOneanddiscoverOnePlacereject with anSDKErrorcodedNOT_FOUNDwhen nothing matches, naming the'Geocode'or'FuzzySearch'service, so you can branch onerror.codeas for any other failed call- The message is unchanged. A
catchthat filters oninstanceof SDKErrornow receives a miss too, where it used to get a plainError.
- The message is unchanged. A
-
services: request validation rejects a parameter the service doesn’t know, and names it, so a misplaced key such as a top-level
poiCategoriesfails withINVALID_REQUESTinstead of being dropped silently- Breaking: services: an unknown parameter rejects with an
unrecognized_keysissue, and one the service takes inside an object parameter points there:poiCategories is not a parameter of AlongRouteSearch. Did you mean filters.poiCategories?. The check reads only the parameters you pass, not the global configuration, and a parameter set toundefinedcounts as absent.validateRequest: falseskips it - Breaking: services: an along-route
discoverPlaceswith neither aquerynor a filter other thanindexesrejects in validation, rather than with the API’s400 "The requested route cannot be calculated" - services:
calculateRoutevalidatesuseEntryPoints,extendedRouteRepresentationsandguidance
- Breaking: services: an unknown parameter rejects with an
-
services: a request a service can’t build, such as a geometry type geometry search doesn’t take sent with
validateRequest: false, rejects with anSDKErrorcodedINVALID_REQUESTinstead of a plainError, so you can branch onerror.codeas for any other failed call- What the request builder threw is on
cause, and the message is unchanged. - If the parameters passed validation and the request still can’t be built, the code is
INTERNAL.
- What the request builder threw is on
-
services: a rate-limited (
429) call backs off 447 ms before its first retry by default instead of retrying at once, and each wait is drawn between half and all of the backoff, so clients rate-limited together don’t retry together -
services:
whentakes alocalDateTime, a wall-clock time such as'2026-10-19T08:15:00'that the routing API reads in the origin’s time zone, so you can route at 08:15 in Tokyo from a browser anywhere without a UTC offset- With
arriveBy,calculateRoutereads alocalDateTimein the time zone of the route’s final destination.calculateReachableRangetakes it withdepartAt - The format is
YYYY-MM-DDTHH:mm:ss, typed asLocalDateTime. Request validation rejects a time without seconds, with an offset or aZ, a date that doesn’t exist, and awhenwith both or neither ofdateandlocalDateTime - Breaking:
DepartArriveParamsis a union of{ date }and{ localDateTime }, so code readingwhen.dateoff it getsDate | undefined. Narrow it first, for example withExtract<DepartArriveParams, { date: Date }>. Passing{ option, date }is unchanged
- With
New features
- map: add a MapLibre custom layer with
map.addCustomLayer, which keeps it in its place through style switches and lets its objects take clicks and hoversbeforeLayerConfigplaces it as on a module. The new'lowest3D'anchor,mapStyleLayerIDs.lowest3D, puts a 3D layer under the style’s 3D buildings, otherwise under the POIs, and module layers placed beforelowestLabelstay below it, even the ones added later. Module layers at'poi'or'top'stay above it, also where it falls back to the POIs or the top- An id the map already has throws, until that layer’s
remove() - After every
setStyle, before the modules restore, the layer goes back to its place, added again if the switch dropped it, and the module layers go back over or under it as they were.remove()takes it off for good - A
hitTestreturns the objects under the pointer, topmost first. They join the map’s user events in layer order, so the layer’sevents, priority, the hover cursor and the event states work as on a module’s features, withsetStateto draw the states
- map: line up a custom layer’s three.js or WebGL scene with the map, in metres around a place, with
localFrameMatrix- It turns
defaultProjectionData.mainMatrixinto aFloat64Array, composed in double precision, which a three.js camera or a WebGL uniform takes centerLatitudescales heights at the map centre’s latitude, as MapLibre scales its 3D buildings and terrain, andunits: 'mercatorMeters'takes geometry authored in EPSG:3857 metres
- It turns
Improvements and fixes
-
map: the style’s 3D buildings have softened corners, rounded over the last metre of their walls, and the new
buildings3D.roundedCornerDistanceMetersknob ofStylingFoundationsModulesets how far the rounding reaches- map:
0gives the sharp corners back, and a few metres rounds the buildings. A style that sets its ownfill-extrusion-rounded-corner-distancekeeps it
- map:
-
core:
aggregateIntoCellsgroups your points into hexagons, squares or your own polygons, such as districts, and gives each cell the median, mean, count, sum, min or max of a value, as GeoJSON polygons any map module draws- core: each point’s grid cell comes from its coordinates, so large data sets stay fast, and the cells across the antimeridian stay side by side.
minCountleaves out the cells with too few points, andgridOriginkeeps the cells in place while your points change - map:
TrafficAreaAnalyticsModulefinds each tile’s hexagon or square from its coordinates on the same cell grid, instead of testing it against every cell, and draws the same cells as before
- core: each point’s grid cell comes from its coordinates, so large data sets stay fast, and the cells across the antimeridian stay side by side.
-
core:
servesGeopoliticalView(view, api)tells whether the SDK sends a geopolitical view to an API, so you can label a result with the view its request carried- core:
GeopoliticalViewAPInames the APIs it answers for:'mapTiles','search','placeDetails','reverseGeocoding'and'geocoding' - map, services: the map’s tiles and every search, place details, reverse geocoding and geocoding request decide which view to send from it, so your label and the request always agree
- core:
-
core, services, map: exported classes keep their names in the minified bundles, so
SDKError.nameis'SDKError',TomTomConfig.nameis'TomTomConfig'andRoutingModule.nameis'RoutingModule' -
map: Add your own credits to the map’s attribution with
attribution: { credits }onTomTomMap. They show next to TomTom’s and stay across style switches. -
map:
setMapColorspaints city parks and sport grounds withparkon every standard style, wherestreetDarkand the mono styles gave themartificial’s colour- map: with
parkleft unset, the parks keep the style’s own colour whateverartificialis set to
- map: with
-
map:
TrafficIncidentDetailsModulefades every incident outside the focus set with the newhighlight.unfocusedOpacityFactor, so the incidents you focus are the ones that stand out- map: it fades their lines, icons and delay text while a focus is set, multiplies
line.opacity, leaves a hovered or clicked incident at full strength and survives a style change. It’s1by default, which leaves them as they are, and thehighlight.unfocusedOpacityFactorknob sets it by id
- map: it fades their lines, icons and delay text while a focus is set, multiplies
-
map: the map language labels the map in
zh-Hant,zh-Hans,ko-Latn-KR,ru-Latn-RU,ngt-Latnandnb-NOtoo, where those showed the local name or the wrong script -
map: with a proxy
commonBaseURL, the map sends credentials and TomTom headers only to URLs on the proxy’s own origin and under its path, not to a host or path that only starts with the same text -
core, services, map: the
licensefield readsSEE LICENSE IN LICENSE.txt, the form npm and license scanners recognise, so they point to the package’s ownLICENSE.txtinstead of reporting an unknown license -
services:
getSearchSuggestionsvalidates its own parameters before sending either request, so an invalidfilters.boundingBoxrejects under that name rather thangeoBias, and an invalid call costs no request -
services: geometry search sends a closed polygon ring of 50 vertices whole and samples a longer one to 50 evenly spaced vertices, where a ring just over a multiple of 50 sent as few as 26
-
services:
createLatestRequest({ supersede: 'on-answer' })shows each answer of requests that start faster than they answer, such as a route re-planned during a drag, and never an older answer after a newer one -
services: along-route
discoverPlacesrejects amaxDetourTimeSecondsabove3600, the service’s maximum, in request validation rather than after a round trip
1.0.0-rc.3
Released October 19, 2026. Its documentation is archived on GitHub.
Breaking changes
-
core: ten plain POI sub-categories have codes of their own, such as
SCHOOL_GENERIC, so a search can ask for plain schools without childcare or driving schools- Breaking: core: a place in one of them reads as its own code rather than its parent’s. Where you match
SCHOOL,THEATER,SPORTS_CENTER,MARINA,WEIGH_STATION,OPEN_CAR_PARKING_AREA,COLLEGE_OR_UNIVERSITY,CAR_WASH,AMUSEMENT_PARKorTRAFFIC_CONTROL_DEPARTMENTinpoi.categories, match its_GENERICcode too - Breaking: core: a
Record<POICategory, …>needs an entry for each of the ten codes - services: a
poiCategoryQueryorresolvePOICategoriesword that names a plain sub-category best, such as'rto'or'open car parking area', resolves to its_GENERICcode, which searches that sub-category alone rather than its parent and the parent’s other sub-categories - services: a word no longer spends one of its three codes on a sub-category of another code it already has, so
'medical'and'care'also findEMERGENCY_MEDICAL_SERVICE - map: a place with one of the new codes takes its parent’s base-map icon, pin and
categoryIconsentry
- Breaking: core: a place in one of them reads as its own code rather than its parent’s. Where you match
-
map: a route’s border crossings stand in a bubble above the route, the summary bubble’s shape with its tail on the border, instead of a plaque on the route line;
countryCrossings.alignmentis removed with its knob and theCountryCrossingAlignmenttype, and crossings no longer carry abearing- The default bubble takes the selected summary bubble’s default colours, so it follows the light or dark style,
setMapColors()and thecolors.labelandcolors.labelHaloknobs: white on a light style, dark grey on a dark one, the map’s label halo lightened under a theme.countryCrossings.colorandcountryCrossings.label.colorstill override either. - A crossing hides where a waypoint pin, a summary bubble, another symbol drawn above it or a crossing close by would cover it, and shows again once there’s room.
- Migration: drop
alignmentfromcountryCrossings. A bubble stays level with the screen.
- The default bubble takes the selected summary bubble’s default colours, so it follows the light or dark style,
-
map: the types of place events, traffic features and waypoint ids match what the map hands your code
- Breaking: map: under
pin-clustered, a cluster no longer reaches theevents.placeshandlers, which are typedPlace, nor takes their hover and click states. The module-wideeventsreceive it, withcluster: true,cluster_idandpoint_countin its properties - Breaking: map:
roadSubcategoryis optional onTrafficIncidentsModuleFeature, and absent offstreetandserviceroads, as onTrafficFlowModuleFeature - Breaking: map: a
TrafficFlowModuleFeature’s geometry is aLineStringor aMultiLineString, so checkgeometry.typebefore you read its coordinates - Breaking: map: a waypoint keeps the id you give it, a number included, so
WaypointDisplayProps.idisstring | number
- Breaking: map: under
-
core:
getDistinctSectionsfinds the stretches each route has to itself, andcalculateRoutereturns them assections.distinctwhenever it returns two or more routes.getImportantRoadsnames the main roads a route takes, by road number- Breaking: core:
SectionTypeandsectionTypesinclude'distinct', which a request’ssectionTypescan’t ask for: the SDK adds it. ARecord<SectionType, …>needs an entry for it - Breaking: services:
InputSectionTypeis only the types a request can ask for, soleganddistinctno longer compile insectionTypes; type a list asInputSectionTypesrather thanSectionType[].InputSectionTypesis read-only, so build a list whole rather thanpushonto one.inputSectionTypes,inputSectionTypesWithGuidanceandsectionTypesare read-only lists of their exact types - core: each distinct section runs from where its route leaves the others to where it rejoins them, with its
lengthInMeters, andminLengthInMetersleaves out the short ones - core:
getSectionOverlapgives the stretch two sections of one route share, whatever their types, as aRouteSpan - core:
getSectionsWithinlists a route’s sections of every type within spans of it, such as the ferries, tolls and traffic on its distinct sections, with each section’s share there to prorate a jam’s delay - core:
compareRoutestells what a route adds and avoids against a reference route, such as the selected alternative, or the routecostModel: { traffic: 'historical' }gives, to say which jams and closures the live route avoids - core:
getImportantRoadsgroups a route’simportantRoadStretchsections road by road, each with itsname, its length and its stretches to ring withsetSectionFocus;within: sections.distinctnames what sets a route apart - map: summary bubbles sit on their route’s longest distinct section, read from
sections.distinctwhen every route carries it, so a route crossing another at a junction keeps its whole stretch for the bubble
- Breaking: core:
-
map: a route you select with a click takes the selected style alone, and a feature an
events.where()predicate rejects stays inert, so narrowing a click to the alternatives keeps the selected route from reacting to the pointer- Breaking: map: an
events.where()predicate decides on the top-most feature under the pointer. One it rejects keeps the map cursor and takes no hover or click highlight, and the handler doesn’t run, even with a matching feature beneath - map:
selectRouteclears theclickstate of the route lines and summary bubbles, so a route you select with a click no longer stays highlighted - map: a long hover comes on the feature under the pointer when it comes due, so a still pointer no longer long-hovers a route as it was before a click selected it, which drew its wider outline
- Breaking: map: an
New features
-
services: an instruction’s
pathPointIndexis the route point at its maneuver, rather than the first point a few metres short of it, so it usually falls inside thelanessection leading to the maneuver- Breaking: a
lanessection’spropertiesreadIS_MANEUVER, as documented, where they passed the API’sisManeuverthrough. Match'IS_MANEUVER'instead.
- Breaking: a
-
services: Breaking: the service types say what each call returns and takes, from reverse geocoding and geometry data to the errors, and a call can set its own
retry- services: Breaking:
reverseGeocoderesolves aReverseGeocodingResponse, aPlaceor, where nothing matches, the queried point withoutproperties; checkingpropertiesnarrows it to aPlace - services: Breaking:
geometryDatagiven aPlacescollection types each polygon’s properties asPlaceGeometryProps, its place’s properties plusplaceCoordinates, and gives a polygon that matches no placenullproperties; aPlace[]or geometry IDs return plainPolygonFeatures - services: a service call’s
retryoverrides the global one field by field, andretry: undefinedturns retrying off for that call - services: Breaking: a service call no longer takes
displayUnits, which no service reads - services: Breaking:
calculateReachableRangesrejects a404, a5xxor an error without a status, as it does a401,403or429, and skips only the other4xx, such as the400MAP_MATCHING_FAILUREof an origin off the road network - services: Breaking:
SDKError.serviceis aServiceName, the union of the services’ names, and reachable ranges report'ReachableRange', not'Reachable Range' - services: Breaking: the wire-format types
PoiCategoriesResponseAPI,PoiCategoryAPI,PlaceDetailsResponseAPIandPlaceDetailsResultAPIare no longer exported - services: Breaking:
minFuzzyLevelandmaxFuzzyLeveltake aFuzzyLevel, the whole numbers1to4 - core: Breaking: a route traffic section’s
tecis optional, and absent when the service sends no TEC codes
- services: Breaking:
Improvements and fixes
-
core:
languagesis a runtime export, and the distance formatter, bounding-box and route helpers handle their edge cases- core:
formatDistancerounds below 10 m to one decimal, rounds a negative distance to the same magnitude as its positive, rounds feet and yards once rather than twice, and takesundefined - core:
bboxCentercentres a box that crosses the antimeridian, andbboxFromGeoJSONreads the 2D edges of a 3Dbbox - core:
getProgressAtNearestRoutePointreturnsundefinedon a route under two coordinates, rather than throwing - core:
getCoordinateAtRouteProgressreturnsundefinedpast an end whose progress entry lacks the value, rather than0 - core:
findBestWaypointInsertionIndicesandwithInsertedWaypointsprepend on a route under two coordinates - core:
getRouteProgressForSectionandgetSectionBBoxtake anyRouteSpan, such as the onegetSectionOverlapreturns - core:
TomTomConfig.instance.reset()restores the retry defaults, even after a caller editedget().retry
- core:
-
core:
getInstructionLanes(route, instruction)finds thelanessection leading to an instruction’s maneuver, so a directions panel can show the lanes to take under each step -
map: images without a DOM, base-map places under offset POI icons and a module’s
events.off()handle their edge cases- map: a module given an SVG image where there is no DOM, as in a server render or a Node.js test, adds no image rather than throwing a
TypeError - map: a
base-mapplace keeps the style’s icon offset whenPOIsModuleoffsets its owncategoryIconsentry for the same category, rather than drawing its sprite that many pixels away - map:
events.off('shown-features')stops compiling on a module with noshowmethod, which never emits that event, asevents.on('shown-features', …)already did
- map: a module given an SVG image where there is no DOM, as in a server render or a Node.js test, adds no image rather than throwing a
-
map: geometries and reachable ranges can blend
fill.palettefrom its first colour to its last, fade the bands away from the origin, and dash or dot their borders- map:
fill.paletteMode: 'ramp'shades the features, or the bands, evenly from the palette’s first colour to its last, blended in OKLCH.'cycle', the default, takes the colours in turn as before - map:
ReachableRangesModule’sfill.outermostOpacityFactormultiplies the outermost band’s fill opacity, and steps the bands between evenly from the innermost one. A lone range takes the factor - map:
line.pattern('solid','dashed'or'dotted') breaks up the borders ofGeometriesModuleandReachableRangesModule, scaled with the border width - map: the new settings are knobs of
geometriesKnobCatalogueandreachableRangesKnobCatalogue - map:
LinePatternnow types every line pattern;SectionLinePatternis deprecated in its favour
- map:
-
map: light the 3D buildings with the
view.lightknobs ofStylingFoundationsModule, kept across style switchesview.light.direction,view.light.altitude,view.light.alignment,view.light.colorandview.light.intensityset MapLibre’s light. A part you leave unset takes the style’s own light, otherwise MapLibre’s defaultstylingFoundationsKnobKindsgainsnumber, the kind of the direction, altitude and intensityexportStyle()carries the light the knobs set- Once a light knob has been set, a clean
setStyle(…, { resetState: true })draws the new style’s light, rather than keeping the one the knobs had set
-
map: road shields, POI icons and road patterns no longer go missing when the map’s own sprite loads more slowly than the place pins’ sprite
-
map: modules keep their state across style switches, routes draw with a traffic halo, and events, images and knobs handle their edge cases
- map:
RoutingModuledraws its routes whensections.traffic.styleis'halo', at creation, after a style switch and when switched at runtime - map:
routeIndexon route sections, summary bubbles and border crossings is the route’s position among the shown routes, soselectRouteand clicks work when only some routes are shown - map:
selectRoutewaits for the module before reading the shown routes, so ashowRoutesit follows unawaited keeps its routes; a newshowRoutesstarts its summary bubbles with no click state - map: route jam labels follow
displayUnits.time, and a speed limit that changes at a border takes the country the route enters - map: speed-limit signs anchor to their own instance’s layers, and go to the top on a style without their usual anchor
- map:
PlacesModulerestores what it showed synchronously on a style switch, repaints its default pin when created with no config, and no longer firesshown-featuresfor the restore - map: a place category icon with no image resolves to the sprite’s own id, a
poiCategoryicon mapping draws thecategoryIconsentry for the category it returns, andlayers.*.layoutoverrides win over the computed text and icon offsets - map:
POIsModulekeeps its category icons after asetStyleto the style already loaded, andFOOD_DRINKS_GROUP,HEALTH_GROUPandENTERTAINMENT_GROUPno longer pull in delicatessens, welfare organisations and clubs - map: a centre title keeps its own hover and click state rather than its polygon’s, and two identical reachable ranges no longer shade the inverted style
- map: raw layer edits stay on top of every module’s knobs, a preset switch fires
config-changeonce per module, and an unknown preset id such as'toString'throws the documented error - map: event handlers survive a style switch that leaves their scope with no layers, hover detects a feature with id 0 and the same id in two sources, and a handler that unsubscribes mid-dispatch no longer skips the next one
- map: a slow image load no longer overwrites a newer image or re-adds a removed one, and
addOrUpdateImageleaves a caller’sonloadalone - map: a
setStylecalled before the first style load finishes on the style it asked for, or on the first style when its own fails to load - map:
TrafficAreaAnalyticsModulemoves its hover outlines and highlights with their cells on abeforeLayerConfigchange, and its heatmap stays valid when every tile has the same value - map: an incident with an average speed of 0 km/h keeps it, and the jam delay label rounds to whole minutes first, with a marker sized for the rounded label
- map:
CustomGeoJSONModulegives a feature with no id one no other feature holds, keeps a layer hidden that its spec sets tovisibility: 'none', re-adds an image whose options change, and no longer firesshown-featureson a style switch - map: a retry after the first style fails to load loads it, and a
setGeopoliticalVieworsetLanguagecalled mid-switch applies once the map is ready without undoing a later call - map: a display-units change keeps the hover and click states of route jams and speed-limit signs,
showWaypointsdraws with a config applied while it waited, a waypoint Feature withproperties: nullno longer throws, and speed-limit signs show mph in Jersey, Guernsey, the Isle of Man, the US territories, seven British Overseas Territories, eight Caribbean states and Samoa - map: a dotted ferry or tunnel line draws its dots, and a named routing layer override placed under another routing layer, by its bare name or its full id, lands there rather than on top
- map:
PlacesModulekeeps entry point and connection event states across a style switch, a cluster rebuild and a config change, and a custom icon’s label offset accounts for itspixelRatioand an SVG’s drawn size, an SVG with only a width or a height taking the other from its viewBox - map:
POIsModuleno longer turns on micro markers the style hides,styling.layersvisibility edits no longer show a layer a module hides, a style sky that draws nothing no longer hides the theme sky while one with colours but no atmosphere counts as shown, and base-map group knobs apply in the order given - map: an events scope you hold registers on the current sources after a style switch, clicking the empty map clears a click state set before one, an
on()unsubscribe removes only its own registration, and a hovered place redrawn as selected doesn’t firehovertwice - map: a layer added in the same config change follows the layer it is pinned under when that layer moves
- map: geometries with their own ids keep them, and their event states, after a config change
- map: area analytics cells stop at
maxMeters, their hover outlines and highlights follow the metric filter, and an emptycolorStopsfalls back to the palette;TrafficIncidentDetailsModule.show()keeps the layers itslayersconfig hides; an incident delay or report count of 0 is kept - map:
calculateFittingBBoxclamps latitudes to the Web Mercator range and handles a box across the antimeridian, andcalculatePaddedBBoxcovers a rotated map and cuts a panel touching one edge from its closest edge - map: a module’s
applyConfigandresetConfigreach the event handlers already registered, so a new hover cursor or grace period applies, and a click on a cluster whose id matches a shown feature’s hands the handler the cluster - map:
TrafficFlowModule,TrafficIncidentsModuleandTerrainModuleshow and hide their layers alongsidestyling.layersedits, so an edit no longer shows traffic or a hillshade the module hides, andBaseMapModuleno longer misrecords anall-exceptvisibility for a layer group the style has no layers for - map: a section’s halo no longer vanishes under the route outline when the section sets a narrower
widthFactororwidthPreset, and settingcountryCrossings.visible: truewhile they are shown keeps a clicked crossing’s state - map: a
setStylecall a newer one supersedes resolves even when its style fails to load, as documented - map: area analytics extrusion highlights follow an extrusion height that ramps with zoom
- map:
POIsModuleSerializableConfigis exported, andstylingFoundationsKnobIdsisreadonlylike the other modules’ knob id lists, so code that mutates it stops compiling - map:
PlaceLayerNameleaves out'additional', which names no layer, andRouteLayersConfig.sectionsnames only the layers each type draws:speedLimitits sign layer, the other generated types their line and icon layers - map:
PlacesModule.updateDataand a show after a config change drop the category, icon and extra properties the previous config added, and a custom module’s layers that reference each other stack in dependency order at creation, onapplyConfigand after a style switch - map:
CustomGeoJSONLayerSpectakes only the six layer types a GeoJSON source draws (circle, line, fill, fill-extrusion, symbol and heatmap) - map: a route module with only some
displayUnitsof its own follows a global unit-system change for the rest - map: a POIs event handler no longer receives base-map features, nor a base-map handler POI ones, and a
recently-hoveredstate clears after its handler unsubscribes - map: area analytics fall back to the defaults for each fill and line field left
undefined, an inverted display cuts every region out of the mask, andsetHeight(undefined)clears the extrusion height - map: a jam with a delay of 0 shows no “1 min” marker, and a whole-hour jam delay gets the small sprite
- map:
setLayouttakesvisibilityas'visible'or'none'only, since a visibility expression was drawn as always visible, andgetStyleInput()is typed as neverundefined - map: routes relabel on the next config change after a global display-units change, a style switch in between included, and a layer override’s
reset()after a style switch restores the new style’s value, or after asetStyleto the style already loaded the value it replaced - map: an
off()followed by a style switch no longer leaves a hover, click or recently-hovered state stuck on a source - map: a place config change gives back the place’s own value of a property an
extraFeaturePropsentry replaced, and a clickedmicrodot underpin-clusteredkeeps its state across a config change and a style switch - map:
CustomGeoJSONModule.applyConfigthrows a clear error before changing anything when the config names other sources orsourceIDs than the module was created with, where it used to apply half of it - map: area analytics hover and click highlights stay off the cells a layer filter hides
- map:
-
core, services, map: the package now installs on Node.js 22 with any package manager
- The
enginesfield asks for Node.js 22 or newer instead of 24, and no longer names a pnpm version, so npm and pnpm stop warning about it on Node.js 22 andengine-strictinstalls succeed
- The
-
map: Fade a route, the traffic overlays, the incidents you show and your place icons, each with one opacity setting
RoutingModuleopacityfades the route lines and their outlines, selected and deselected; sections keepsections.<type>.opacityTrafficFlowModuleandTrafficIncidentsModuleopacityFactormultiply the style’s own line opacity, its zoom ramp kept; the incident icons stay opaqueTrafficIncidentDetailsModuleline.opacityfades the incident lines; the markers and the highlight outline stay opaquePlacesModuleicon.opacityfades the icons of every marker type, the cluster pin included; a selected place stays opaque- Each is a knob in its module’s catalogue
-
services:
calculateReachableRangerejects an arrival time with a message that shows thewhenshape to use instead,when: { option: 'departAt', date } -
map: Choose what a route’s summary bubble says, its colour, typeface and the zooms it shows at, or write your own text per route
summaryBubbles.fieldslistsduration,distanceandtrafficDelayin the order shown; a bubble with nothing to say isn’t drawn, so['trafficDelay']shows bubbles on delayed routes alonesummaryBubbles.minZoom,maxZoom,colorandlabel(color,size,opacity,typeface,customTypeface) are knobs inroutingKnobCatalogue, all butcustomTypefacesummaryBubbles.label.titletakes a function of the route’s summary, or a MapLibre expression, and writes its text in place of the fields- The bubbles now follow the map: a theme’s
labelHaloandlabelcolours once one sets them, else dark bubbles and light text on a dark style
-
map: Summary bubbles keep clear of each other, show on the routes you choose and give each alternative’s time against the selected route
- Each bubble sits on a stretch of road its route has to itself, so routes sharing a motorway no longer hide each other’s bubble, and it stays put when another route is selected
summaryBubbles.routesshows the bubbles onallroutes, theselectedone alone or itsalternatives- The
durationDifferencefield writes each other route’s time against the selected one, such as+6 min, andselectRoutere-times the bubbles
-
services: validation catches the inputs that used to crash or reach the API, and routing, search suggestions and the shared pipeline handle their edge cases
- services: validation rejects, as
INVALID_REQUEST, what used to throw a plainErroror come back as a 400: an empty Polygon or a Point ingeometrySearch, an impossible date such as'2024-02-30'intrafficAreaAnalytics, more than 100 incident ids, a non-integer fuzzy level or aminFuzzyLevelabovemaxFuzzyLevel, a routing avoid area with no bounding box, a one-point path, a non-integermaxAlternatives, an along-route search route under two positions, a zero reachable-range budget, a non-integer or out-of-rangelimitorheading, and an undefinedcommonBaseURL - services: validation also rejects an empty array as a route location, a stop’s
candidateEntryPointsoff the globe orpreferredEntryPointIndexpast them, an emptygeometrySearchgeometry list or ring,daysbeside anendDateintrafficAreaAnalytics, and a bare bbox of other than four numbers; it now accepts a GeometryCollection where a bounding box is read, bare or inside a Feature or FeatureCollection, and the documentedweightKG: 0 - services: validation checks GeoJSON input against its type: a route waypoint’s position, every position of a path, an along-route search route or a polygon ring, and a
geometrySearchCircle centre must be on the globe, a bounding box can’t be an empty array or collection, a path given as a Feature must hold a LineString, a stop’spauseDurationSecondscan’t be negative and itslegCostModeltakes only known route types and avoid values, a geometry’s coordinates must match itstype, and a GeoJSONbboxmust hold 4 or 6 numbers;extendedPostalCodesFor,mapcodes,openingHours,timeZone,relatedPoisandfilters.indexesreject values outside their types - services: a validation error from a union schema lists what each branch rejected
- services:
onAPIResponsereceives the API’s response body, as its type says, rather than the fetch envelope, and fires once per call - services: proxy-credentials mode is decided per call, so a call with its own
apiKeyno longer sendscredentials: 'include'under a global proxy setup - services: an error response labelled JSON whose body doesn’t parse still rejects with its status
- services:
calculateRoutekeeps the leg point indices right after a one-coordinate first leg, gives a road-shield section with no references[], no longer lets an origin’scandidateEntryPointsoverrideuseEntryPoints, maps TEC cause codes 16, 22 and 23 to'other'as the TPEG2-TEC table defines them, and gives each instruction with no road info an object of its own - services:
trafficAreaAnalyticsno longer throws aRangeErrorover a region with hundreds of thousands of tiles, andcalculateReachableRangesstops listening to the batch’s abort signal once each call settles - services:
getSearchSuggestionsshows a brand asked for alongside address-type kinds - services:
getSearchSuggestionsno longer offers a category refinement whoserefine()fails for a category id the SDK doesn’t know, and leaves out autocomplete segments of a type the SDK doesn’t know - services:
getPOICategoriesandresolvePOICategoriesvalidate their parameters and reject withSDKAbortErroron an aborted signal even when the cache or the known codes answer the call - services:
SDKServiceError.statusisreadonly, like the other error fields - services:
geocodekeeps ingeographyTypeonly the types core’sgeographyTypeslists, and rejectsextendedPostalCodesFor: ['POI']asINVALID_REQUEST - services: a blank
poiCategoryQueryrejects rather than searching with no category filter - services:
calculateReachableRangesno longer needsAbortSignal.any, which React Native lacks, and the search cursor no longer needsatobandbtoa - services: a search or geocode result at distance 0 keeps its
distance, Kosovo’sXKmaps toXKX, andgetPOICategorieshands out a copy of its cache - services:
VehicleModelandVehicleDimensionsare exported - core:
TomTomConfig.instance.putdropsundefinedretry fields rather than storing them over the defaults
- services: validation rejects, as
-
core, services, map: an app now bundles only the SDK code its imports use, so most single imports come out far smaller
- core: importing one helper, such as
generateId, bundles under 1 KB minified instead of about 30 KB with lodash - services:
geocodebundles about 14 KB minified instead of 68 KB, andcalculateRoute32 KB instead of 86 KB, with lodash - map:
TomTomMapbundles about 44 KB minified on top of MapLibre instead of 123 KB, with lodash - core, services, map: the package declares
sideEffects: false, so bundlers drop the modules an app doesn’t import
- core: importing one helper, such as
-
map: a route’s speed limit signs draw from zoom 12.5 by default instead of 11, two and a half zooms after the tunnel and closed-road signs, so they no longer crowd the overview of a route;
sections.speedLimit.sign.minZoomstill sets it, in steps of half a zoom inroutingKnobCatalogue
1.0.0-rc.2
Released October 9, 2026. Its documentation is archived on GitHub.
Breaking changes
- map: a knob id is the path of its setting in the configuration on every module, and
setKnobssets several knobs in one checked change- map:
setKnobs(module, catalogue, values)checks every value against its knob, then applies them all in one change and oneconfig-change. If it refuses one value, it sets none.KnobValues<CONFIG, ID>types the values by id - map:
StylingFoundationsModuleConfignests each setting along its id, as every other module does:{ labels: { sizeFactor: 1.2 } }instead of{ 'labels.sizeFactor': 1.2 }.setKnob,setKnobs,getKnob,resetKnobandMapPresetSettingskeep the ids - map:
StylingFoundationsModule’supdateConfigmerges one level deep, as on every module, soupdateConfig({ colors: { water } })replaces the colours set before. Set a single colour withsetKnob. ItsapplyConfigandupdateConfigno longer check values at run time, as on every module.setKnobandsetKnobsdo - map: a
KnobTargetimplements_setKnobValues(values)instead of_setKnobValue(id, value), and a subclass ofAbstractMapModuleinherits it. For a plugin’s own target,knobValueIn,configWithKnobsandconfigWithoutKnobimplement the hooks
- map:
Improvements and fixes
-
map:
TrafficAreaAnalyticsModulemetric filters no longer make MapLibre validate the whole style on each change -
map: a traffic flow section at a standstill reports
absoluteSpeed: 0fromTrafficFlowModule.getRenderedFeatures()and its events, instead of leaving itundefined -
map: The map fills its container from the first frame on pages whose scrollbars take up layout space, as on Windows
- If the page didn’t import the MapLibre CSS, the canvas could stay about one scrollbar width short on the right and bottom until the window was resized
-
map: a knob or config change on a data-owned module writes only the layer properties whose value changes, so a value set on its layers with
mapLibreMapstays until a change sets that property- map: changing a
GeometriesModule’sline.colorkeeps a fill opacity or label size set on its layers, and the same holds for routes, places, reachable ranges, custom GeoJSON, traffic incident details and area analytics
- map: changing a
-
map: Set every label on the map in one typeface, from the style’s serif and italic faces or your own font files, and give the labels of a route, places or geometries one of their own
- The
labels.typefaceknob ofStylingFoundationsModuletakessans,sans-italic,seriforserif-italic(mapTypefaces), each label keeping its weight labels.customTypefacetakes your own font file URLs per weight (CustomTypeface), which the map downloads itself; characters outside their range are drawn in the style’s Noto face- The labels of routes, places, geometries, reachable ranges and incident details follow the map’s typeface unless their module sets its own
- Each module’s label settings take the same
typeface(a knob:label.typeface,waypoints.label.typeface,lineLabel.typeface) andcustomTypeface, for those labels alone - The waypoint, geometry and reachable-range
fontknobs have no default, sogetKnobreturnsundefineduntil you set one. Unset, those labels are inNoto-Boldset in their typeface exportStyle()returns labels set in font files in the style’s own Noto faces, since only the SDK can draw those files
- The
-
map:
RoutingModule,PlacesModule,CustomGeoJSONModuleandTrafficIncidentDetailsModulekeep their events andsourceAndLayerIDsin step with the layers a later config change adds or removes- A removed layer, such as a section icon, an
additionallayer, a custom source’s layer or the incident highlight halo, used to stop hover and click for every module on the map. An added layer got no events and was missing fromsourceAndLayerIDs
- A removed layer, such as a section icon, an
-
map:
POIsModule’sfilters.categoriesnarrows the micro markers too, so the dots of filtered-out categories no longer show from zoom 15.5, nor come back fromgetRenderedFeatures() -
map:
RoutingModule.setSectionFocusrings any section or leg of the shown routes, so your UI can point at the stretch it describes- The ring outlines the route clear of its hovered outline and section halos rather than covering them, black on a light style and white on a dark one, as the traffic incident highlight does
highlight.section.outline.colorandhighlight.section.outline.widthFactorrestyle it, as config or as routing knobsgetShown().sectionFocusholds the focused sections, andshowRoutesclears them
-
map: the
maplibre-glpeer dependency moves up to^6.13.0 -
map: a route’s speed limit signs draw from zoom 11 by default, one zoom after the tunnel and closed-road signs, so they no longer crowd the overview of a route;
sections.speedLimit.sign.minZoomstill sets it -
map: a
TerrainModulechange that leaves the 3D surface as it was, such as a hillshade knob, no longer makes MapLibre rebuild the terrain
1.0.0-rc.1
Released October 6, 2026. Its documentation is archived on GitHub.
Improvements and fixes
npm install @tomtom-org/maps-sdkinstalls the 1.0.0 release candidate, with no@rcneeded, and the npm page shows its README
1.0.0-rc.0
Released October 6, 2026. Its documentation is archived on GitHub.
Breaking changes
-
core, services, map: 1.0.0, the first stable release of the SDK. The Upgrading to 1.0 from a 0.x release guide lists every change to apply from a 0.x release.
-
core, services, map: the error codes take the TomTom Navigation SDK’s names:
API_KEY_REJECTEDisINVALID_CREDENTIALS,SERVICE_UNAVAILABLEisLIVE_SERVICE_NOT_AVAILABLE,NETWORK_ERRORisNETWORK_NOT_AVAILABLEandUNEXPECTEDisINTERNAL- Breaking: core, services, map: a
403isINSUFFICIENT_PERMISSIONS, a valid key not allowed the request, andINVALID_CREDENTIALSis a401only, a key the API does not know - services, map:
SDKError.canRetryandTomTomMapError.canRetryaretrueforRATE_LIMITED,LIVE_SERVICE_NOT_AVAILABLEandNETWORK_NOT_AVAILABLE, the failures that clear on their own - services: a
403keeps the API’s message, andSDKServiceError.apiErrorCodeholds the API’s own code:'Forbidden'when the API is not enabled for the key,'InvalidReferer'when its domain restriction refused the page - services:
calculateReachableRangeandcalculateReachableRanges, in Private Preview, name the access a key lacks, and link the Private Preview terms, in the message; the access is also inSDKServiceError.privatePreviewAccess,{ product, requestAccessURL } - map: a style, tile, sprite or glyph answered
403reaches the error handlers asINSUFFICIENT_PERMISSIONS
- Breaking: core, services, map: a
-
map: the sky, space, incident delay and hillshade knobs are named as every other knob is: a part’s settings sit under it, and no name repeats its parent
- map:
StylingFoundationsModuleknob idsview.sky,view.skyColor,view.horizonColorandview.spaceColorareview.sky.visible,view.sky.color,view.sky.horizonColorandview.space.color, instyleColorKnobIds,getStyleColorand map presets too - map:
TrafficIncidentsModulefilters: { delays: { mustHaveDelay, minDelayMinutes } }isfilters: { delays: { required, minMinutes } }, and the knob ids follow - map:
TerrainModulehillshade: { lightDirection, exaggeration, shadowColor, highlightColor, accentColor }ishillshade: { light: { direction }, intensity, colors: { shaded, lit, steep } }, and the knob ids follow, instyleColorKnobIdsandgetStyleColortoo;exaggerationis now only the raised surface’s vertical scale
- map:
-
map:
PlacesKnoband the traffic knob types list only the kinds their catalogues hold, so aswitchover theirkinddrops the cases no entry reachesPlacesKnobno longer includestextTrafficFlowKnob,TrafficIncidentsKnob,TrafficIncidentDetailsKnobandTrafficAreaAnalyticsKnobno longer includeimage
-
map: the last config properties and knob ids off the shared vocabulary follow it: a size preset is a
*Preset, a fill style sits underfill, and a unit is named once- map:
GeometriesModuleandReachableRangesModuletakefill: { style }instead offillStyle, andTrafficAreaAnalyticsModuleregionPolygon: { fill: { style } }instead ofregionPolygon.fillStyle; a feature’sproperties.fillStylestays - map:
RoutingModulewidth,sections.<type>.widthandwaypoints.sizearewidthPreset,sections.<type>.widthPresetandwaypoints.sizePreset - map:
PlacesModulecluster.sourcetakesradius,maxZoom,minPointsandpropertiesinstead of MapLibre’sclusterRadius,clusterMaxZoom,clusterMinPointsandclusterProperties, typed byPlacesClusterSourceConfig - map:
PlacesModulelabel.offsetislabel.distance, since anoffsetis an[x, y]displacement on every module - map:
TrafficAreaAnalyticsModuleheight.maxHeightMetersandheight.minHeightMetersareheight.maxMetersandheight.minMeters, insetHeighttoo - map: each renamed property’s knob id follows it
- map:
-
map: the map loads TomTom standard styles only, so a custom style URL or style JSON no longer loads
StyleInputno longer takes{ type: 'custom', url }or{ type: 'custom', json }, andCustomStyleandCustomStyleSourceare no longer exportedlightDarkThemeis gone with them:map.styleLightDarkThemefollows from the standard style ID- Restyle a standard style at runtime with
StylingFoundationsModuleandsetMapColorsinstead
-
core, services, map: the SDK no longer offers real-time EV charging availability, nor routes and reachable ranges planned on a vehicle consumption model; search results keep their static EV station data
- services:
evChargingStationsAvailability,getPlacesWithEVAvailability,getPlaceWithEVAvailabilityandhasChargingAvailabilityare removed - services: long-distance EV routing is removed:
vehicle.preferences,chargingStopsStrategyandchargingStopsStrategies - services:
vehicletakesmodel.dimensions.weightKG,state.headingandrestrictionsonly:engineType,model.engine,model.variantIdand the charge and fuel state are removed, with the electric, combustion and generic vehicle types - core: the reachable-range budgets
remainingChargePCT,spentChargePCTandspentFuelLitersare removed; a budget istimeMinutesordistanceKM - core: route and leg summaries lose their battery, charge and fuel fields and
chargingInformationAtEndOfLeg, withChargingStop - core:
ChargingPark.availability,ChargingPoint.statusanddataSources.chargingAvailabilityare removed;StaticChargingPointbecomesChargingPoint, andChargingStationtakes no type parameter - map:
PlacesModulelosesevAvailability,categoryIconsentries loseavailabilityLevel, andRoutingModuleloseschargingStops, with their knobs, events and shown data
The Upgrading to 1.0 from a 0.x release guide lists every removed name.
- services:
-
map: each standard style ID is the Orbis style it loads, in camelCase
- map:
standardLight,standardDark,drivingLight,drivingDarkandsatellitearestreetLight,streetDark,streetLightDriving,streetDarkDrivingandstreetSatellite;monoLightandmonoDarkstay
- map:
Improvements and fixes
-
map: the
maplibre-glpeer dependency moves up to^6.12.0 -
core, services, map: the package ships without source maps, so a stack trace through the SDK points into its minified bundles, which keep their function names
- An app’s own source maps still lead a trace to the SDK’s frames (
map/dist/map.es.js:1:84523); share such a trace in a report and TomTom maps it back to the source
- An app’s own source maps still lead a trace to the SDK’s frames (
-
map:
TerrainModulesets the hillshade light’s height and what its direction turns with, and themultidirectionalmethod fans its four lights around the light’s direction- map:
hillshade.light.altitude, in degrees above the horizon, andhillshade.light.alignment,viewportormap(hillshadeLightAlignments), in the config and asterrainKnobCatalogueknobs - map: with
method: 'multidirectional',hillshade.light.directionis the centre of four lights spread over 135°
- map:
-
map:
TrafficIncidentsModulecan show planned incidents, and its incident descriptions follow the map languagetimeValidity: ['present', 'future']brings scheduled roadworks and closures in next to the incidents under way, also as thetimeValidityknobdescriptionis in the map language, or the nearest one the traffic service has (pt-PTforpt-BR), else English;map.setLanguagereloads the incident tiles when that changes- core:
trafficIncidentTimeValiditieslists everyTrafficIncidentTimeValidity,presentfirst