Vector Maps
Daily-updated vector map tiles - property, address, road, and environment layers. Works with Mapbox and MapLibre.
We provide advanced but simple to use vector maps with styles for displaying rich data about properties, addresses, roads and environment and many other things. You can use Mapbox or MapLibre GL JS to render the maps in both web and mobile apps.
Maps are updated daily and hot swapped.
Before Getting Started
The tile server only serves pages whose origin your team has registered. Register every origin that shows the maps: scheme, host and the port when it is not the default, without a path. While developing you can register your local origin too, e.g. http://localhost:5173.
curl -X POST "https://lens-api.tic.io/team/tiles/cors" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "domain": "https://maps.example.com" }'{
"teamCorsId": 42,
"domain": "https://maps.example.com",
"lastUpdatedAtUtc": "2026-10-07T12:00:00Z"
}The origin works right away. Registering the same origin twice answers 409, and a value with a path or query answers 400.
List the team’s origins, and remove one by its teamCorsId:
curl -H "x-api-key: YOUR_API_KEY" "https://lens-api.tic.io/team/tiles/cors"
curl -X DELETE -H "x-api-key: YOUR_API_KEY" "https://lens-api.tic.io/team/tiles/cors/42"Getting Started
This example shows how you get started with MapLibre GL JS in a webpage.
Include the JavaScript and CSS files in the head of your HTML file.
<script src='https://unpkg.com/maplibre-gl@latest/dist/maplibre-gl.js'></script>
<link href='https://unpkg.com/maplibre-gl@latest/dist/maplibre-gl.css' rel='stylesheet' />Include the following code in the body of your HTML file.
<div id='map' style='width: 800px; height: 800px;'></div>
<script>
var map = new maplibregl.Map({
container: "map",
style: "https://tiles2.tic.io/style/super-map-style2",
center: [19.8756, 63.5569], // starting position [lng, lat]
zoom: 4, // starting zoom
attributionControl: false
});
</script>Draw additional details
Property borders and buildings are by default included in the style but if you wish to draw areas and greater details about building numbers, usage type etc you
can download the property details from the property summary (GET https://lens-api.tic.io/properties/se/{uuid}/summary). It gives you additional
data and areas.
In the example below we are adding four(4) layers:
- Areas
- Building parts (already included in the default style)
- Building parts text (number)
- Areas text (number)
Result will look like the example below where the area is filled with light blue opacity and buildings are drawn in yellow adding the text number.
For simplicity we are using Lodash.
Include the JavaScript and CSS files in the head of your HTML file.
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
<script src='https://unpkg.com/maplibre-gl@latest/dist/maplibre-gl.js'></script>
<link href='https://unpkg.com/maplibre-gl@latest/dist/maplibre-gl.css' rel='stylesheet' /><div id='map' style='width: 800px; height: 800px;'></div>
<script>
// See above: in your server controller / backend, request
// https://lens-api.tic.io/properties/se/{uuid}/summary (replace uuid with the property id)
// with your API key in the x-api-key header, and pass the response to the page
const dataFromRequest = {};
// Then copy and paste the code below
const omraden = dataFromRequest.omraden;
const byggnader = dataFromRequest.byggnader;
var map = new maplibregl.Map({
container: "map",
style: "https://tiles2.tic.io/style/super-map-style2",
center: [19.8756, 63.5569], // starting position [lng, lat]
zoom: 4, // starting zoom
attributionControl: false
});
let bounds = [];
map.on('load', async () => {
const coordinates = [];
const geojsonOmraden = {
type: 'geojson',
data: {
"type": 'FeatureCollection',
"features": []
}
};
_.forEach(omraden, function(omrade) {
geojsonOmraden.data.features.push({
type: 'Feature',
properties: {
omradesnummer: omrade.omradesnummer
},
geometry: {
type: 'Polygon',
coordinates: omrade.omradeYta
}
});
_.forEach(omrade.omradeYta[0], i => coordinates.push(i));
});
map.addSource('omraden', geojsonOmraden);
map.addLayer({
'id': 'omraden',
'type': 'fill',
'source': 'omraden',
'paint': {
'fill-color': '#90E0EF',
'fill-opacity': 0.7
},
'filter': ['==', '$type', 'Polygon']
});
const geojsonByggnadsdelar = {
type: 'geojson',
data: {
"type": 'FeatureCollection',
"features": []
}
};
_.forEach(byggnader, function(byggnad) {
_.forEach(byggnad.delar, function(del) {
geojsonByggnadsdelar.data.features.push({
type: 'Feature',
properties: {
byggnadHusnummer: byggnad.byggnadHusnummer
},
geometry: {
type: 'Polygon',
coordinates: [del.byggnadsdelYta]
}
});
});
});
map.addSource('byggnadsdelar', geojsonByggnadsdelar);
map.addLayer({
'id': 'byggnadsdelar',
'type': 'fill',
'source': 'byggnadsdelar',
'paint': {
'fill-color': '#FDC86C',
'fill-opacity': 0.8,
'fill-outline-color': '#F9A107'
},
'filter': ['==', '$type', 'Polygon']
});
map.addLayer({
'id': 'byggnadsdelartext',
'type': 'symbol',
'source': 'byggnadsdelar',
"layout": {
"text-field": [
"concat",
"Husnr: ",
["get", "byggnadHusnummer"],
],
"text-font": ["Open Sans SemiBold"],
"text-size": {
"stops": [
[2, 10],
[4, 12],
[6, 12],
[12, 12],
[16, 16]
]
},
"visibility": "visible"
},
"paint": {
"text-color": "#000",
"text-halo-blur": 1,
"text-halo-color": "rgba(255, 255, 255, 1)",
"text-halo-width": 1
},
'filter': ['==', '$type', 'Polygon']
});
map.addLayer({
'id': 'omradesnummertext',
'type': 'symbol',
'source': 'omraden',
"layout": {
"text-field": [
"concat",
"Omrnr: ",
["get", "omradesnummer"],
],
"text-font": ["Open Sans SemiBold"],
"text-size": {
"stops": [
[2, 10],
[4, 12],
[6, 12],
[12, 12],
[16, 16]
]
},
"visibility": "visible"
},
"paint": {
"text-color": "#000",
"text-halo-blur": 1,
"text-halo-color": "rgba(255, 255, 255, 1)",
"text-halo-width": 1
},
'filter': ['==', '$type', 'Polygon']
});
const bounds = coordinates.reduce((bounds, coord) => {
return bounds.extend(coord);
}, new maplibregl.LngLatBounds(coordinates[0], coordinates[0]));
map.fitBounds(bounds, {
padding: 120,
duration: 0
});
});
</script>Custom Styles
You can copy the style that we provide and make your own adjustments. We recommend using Maputnik which is a visual editor for MapLibre and MapBox style specifiation. It allows you to make modifications to your style and save the json style sheet and host it yourself.
Each source object in the style reference our tileserver, tiles2.tic.io, which requires CORS. Therefore ensure you have registered your origin. Each URL consists of the following format which contains four(4) parts in the URL that should be replaced https://tiles2.tic.io/database.schema.table.column e.g database, schema, table and column.
You have access to the following databases. They are updated daily and the tile server serves cached tiles.
| Database | Description |
|---|---|
| lm_belagenhetsadress | Contains all information relating to an address |
| lm_fastighetsindelning | Contains all information relating to a property |
| lm_top1m | Contains topography 1:1M |
| lm_top10 | Contains topography 1:10 000 |
| naturalearth | Contains Natural Earth |
| ormeo | Contains extended databases such as the EBH which is a national database of contaminated areas |
Check next section for a full data dictionary.
Data Dictionary
Each databases consists of geometric tables and in total they are 248. Each table then contains a range of columns that can be used to be displayed on the map. For simplicity we are adding a full data dictionary in PDF (582 pages) that you can download and easier search in and pick the fields you want to display.
Download the data dictionary here
Adding a source layer is very simple in the style sheet and we have made an example below.
Let’s say you want to show railroads in the map (enabled by default in our stylesheet), you check the PDF-dictionary and find that there is a table called ralstrafik (English: rail roads) and the column geom contains the geometry of the railroads.
Just add a source object with the nickname “ralstrafik” and you are done:
"ralstrafik": {
"type": "vector",
"url": "https://tiles2.tic.io/lm_top10.table.public.ralstrafik.geom"
},This should be interpreted as
Database = lm_top10 Schema = public Table = ralstrafik Column = geom