How to Add Markers to a Map
- API or service
- Map Marker API + JavaScript map libraries
- Task
- Location coordinates → visible map markers
- Examples
- Difficulty
- Beginner
- Time
- 10 min
You have one or more locations and need to make them visible and interactive on a map. The Geoapify Map Marker API generates marker images that you can use with Leaflet, MapLibre GL, and OpenLayers. A marker object is convenient for a small number of locations because it is easy to create, move, and attach to a popup. A data layer is usually better when the map must render or filter many points.
Leaflet and MapLibre GL provide dedicated marker objects. In OpenLayers, a marker is normally a point feature in a vector layer. MapLibre can also render GeoJSON points as a WebGL layer, which avoids creating one HTML element for every location.
Map APIs generally use coordinates in [longitude, latitude] order. Leaflet marker methods are a common exception and accept [latitude, longitude].
The examples use this double-resolution marker:
https://api.geoapify.com/v2/icon/?type=awesome&color=%23ff005c&size=42&scaleFactor=2&apiKey=YOUR_API_KEY
Display the returned image at 32 × 47 CSS pixels. Its shadow occupies the bottom 5 pixels, so the geographic anchor is 5 pixels above the image bottom. Each library applies that offset differently. Use the Map Marker API Playground to choose another shape, color, icon, or text.
Add markers with Leaflet
Create a reusable L.icon from the Geoapify marker URL, then pass it to each L.marker. Leaflet expects marker coordinates in [latitude, longitude] order.
const markerIcon = L.icon({
iconUrl: "https://api.geoapify.com/v2/icon/?type=awesome&color=%23ff005c&size=42&scaleFactor=2&apiKey=YOUR_API_KEY",
iconSize: [32, 47],
// The location is 5 px above the bottom because the shadow extends below it.
iconAnchor: [16, 42]
});
const locations = [
{ name: "Brandenburg Gate", lat: 52.5163, lon: 13.3777 },
{ name: "Museum Island", lat: 52.5169, lon: 13.4010 }
];
for (const location of locations) {
L.marker([location.lat, location.lon], { icon: markerIcon })
.bindPopup(location.name)
.addTo(map);
}
iconSize displays the double-resolution API response at its intended CSS size. iconAnchor: [16, 42] places the horizontal center and the point above the 5-pixel shadow on the location.
Add markers with MapLibre GL
A MapLibre Marker is an HTML element positioned above the map canvas. Create an image element for the Geoapify marker and display the double-resolution response at 32 × 47 CSS pixels. Coordinates use [longitude, latitude] order.
const markerIconUrl = "https://api.geoapify.com/v2/icon/?type=awesome&color=%23ff005c&size=42&scaleFactor=2&apiKey=YOUR_API_KEY";
function createMarkerElement() {
const image = document.createElement("img");
image.src = markerIconUrl;
image.width = 32;
image.height = 47;
image.alt = "";
return image;
}
const locations = [
{ name: "Brandenburg Gate", coordinates: [13.3777, 52.5163] },
{ name: "Museum Island", coordinates: [13.4010, 52.5169] }
];
for (const location of locations) {
new maplibregl.Marker({
element: createMarkerElement(),
anchor: "bottom",
// Move the image down so the point above its 5 px shadow hits the location.
offset: [0, 5]
})
.setLngLat(location.coordinates)
.setPopup(new maplibregl.Popup().setText(location.name))
.addTo(map);
}
Because every marker is a DOM element, avoid creating thousands of them. The MapLibre layer example uses the same Geoapify marker image for a larger or frequently updated point collection.
Add markers with OpenLayers
Represent markers as point features in a vector source and use the Geoapify marker as their icon style. OpenLayers maps normally use Web Mercator, so convert geographic [longitude, latitude] coordinates with fromLonLat().
import Feature from "ol/Feature.js";
import Point from "ol/geom/Point.js";
import VectorLayer from "ol/layer/Vector.js";
import VectorSource from "ol/source/Vector.js";
import Icon from "ol/style/Icon.js";
import Style from "ol/style/Style.js";
import { fromLonLat } from "ol/proj.js";
const marker = new Feature({
name: "Brandenburg Gate",
geometry: new Point(fromLonLat([13.3777, 52.5163]))
});
marker.setStyle(new Style({
image: new Icon({
src: "https://api.geoapify.com/v2/icon/?type=awesome&color=%23ff005c&size=42&scaleFactor=2&apiKey=YOUR_API_KEY",
width: 32,
height: 47,
anchor: [0.5, 1],
// Negative Y moves the image down, placing the point above its shadow.
displacement: [0, -5]
})
}));
map.addLayer(new VectorLayer({
source: new VectorSource({ features: [marker] })
}));
The configured width and height display the double-resolution image at its intended CSS size. The 5-pixel downward displacement keeps the shadow below the geographic point. Keep data such as the location name on the feature so a click handler can populate a popup or side panel.
Render markers as a MapLibre GL layer
Use a GeoJSON source and a symbol layer when the points behave as data rather than separate HTML controls. This approach reuses one Geoapify marker image for the entire layer and supports efficient filtering and clustering.
const markerIconUrl = "https://api.geoapify.com/v2/icon/?type=awesome&color=%23ff005c&size=42&scaleFactor=2&apiKey=YOUR_API_KEY";
map.on("load", async () => {
const markerImage = await map.loadImage(markerIconUrl);
// scaleFactor=2 returns a double-resolution image. pixelRatio restores
// its intended 32 × 47 CSS-pixel size when MapLibre renders the symbol.
map.addImage("geoapify-marker", markerImage.data, { pixelRatio: 2 });
map.addSource("locations", {
type: "geojson",
data: {
type: "FeatureCollection",
features: [
{
type: "Feature",
properties: { name: "Brandenburg Gate" },
geometry: { type: "Point", coordinates: [13.3777, 52.5163] }
},
{
type: "Feature",
properties: { name: "Museum Island" },
geometry: { type: "Point", coordinates: [13.4010, 52.5169] }
}
]
}
});
map.addLayer({
id: "location-points",
type: "symbol",
source: "locations",
layout: {
"icon-image": "geoapify-marker",
"icon-anchor": "bottom",
// Move the image down so the point above its 5 px shadow is anchored.
"icon-offset": [0, 5],
"icon-allow-overlap": true
}
});
});
Use marker objects when every point needs its own HTML control. Use a symbol layer when many points share an image and need efficient filtering, visibility rules, or clustering.