Map attribution twice: my duplicate, not the provider's fault
Two stacked attribution lines on a tiny map turned out to be my own duplicate; the provider's TileJSON had been shipping attribution all along.
TL;DR
A duplicated map attribution wasn't a typo in the component; MapLibre pulls the string automatically from the provider's TileJSON. The fix was dropping the hand-typed customAttribution and setting compact: false so the credit stays visible. License strings belong in tile data, never retyped in app code.
Right after deploying the office locations page, I noticed something off. In the bottom right corner of that tiny map, two lines of text were stacked. © OpenMapTiles © OpenStreetMap contributors appeared twice in the same spot. It looked amateurish on a company landing page.
My first guess: that attribution string had to be typed into the component by hand, so one of the lines had to be my own leftover duplicate from when I first wrote the component. Just delete it, I thought. Safe, one line gone.
The tile provider was already shipping it
The guess was wrong. MapLibre collects attribution automatically from the tile source's TileJSON. The text OpenFreeMap © OpenMapTiles Data from OpenStreetMap had been sitting in the metadata of the OpenFreeMap planet endpoint all along [6]. I never needed to type it, and the provider says exactly that: with MapLibre the attribution is added automatically, you have nothing to do [5].
This makes sense once you think about it: license compliance lives in the data layer, not the UI layer. The control on screen just renders whatever the data declares. And the obligation is real. The ODbL requires credit and a license notice as soon as OSM data is used publicly [1]. If the attribution disappears from the map, the loser is not a vendor but the mapping community whose data we use for free.
customAttribution is additive, not a replacement
The mistake sat in office-map.tsx. The old code:
new maplibregl.AttributionControl({
compact: true,
customAttribution: "© OpenMapTiles © OpenStreetMap contributors"
})
Two mistakes in five lines. First, customAttribution: the MapLibre docs say this option shows in addition to any other attributions [3]. It is additive. My manual line did not override the built-in text, it stacked on top of it. The double credit for OpenMapTiles was unnecessary too: the TileJSON already acknowledges it, and if the official string ever changes, my hand-typed copy becomes a silently drifting leftover.
Second mistake: compact: true. That mode folds the attribution into a tiny icon you have to click. By default the control stays expanded no matter how wide the map is [4], and attributions from all sources get merged into one small line. The designers clearly thought about this case before I did.
compact: false and the rules of the game
The new code is short:
new maplibregl.AttributionControl({
compact: false
})
compact: false forces the attribution to stay open. The docs themselves say the compact mode is only for when the attribution genuinely cannot fit on the map [3]. This office map is wide enough; the text fits. Forcing compact means users need an extra click just to read a data copyright notice. That tiny icon is also easy to ignore: no word like "license" or "copyright" appears, just a symbol whose meaning not everyone knows.
The licensor's own rules are clear here. An interactive map may put the credit in a corner, and if it collapses, users must still be able to find the license info, for example through an info button on the map [2]. MapLibre's responsive default only folds temporarily while the map is being moved on narrow screens [3], it never deletes the notice.
This pattern is not exclusive to OpenFreeMap. Vector tile providers generally put attribution in their TileJSON, and that is exactly where it belongs: the license string is managed by the party that knows the data, not retyped in every component. If you self-host tiles, fill the attribution property of your own TileJSON properly, and every MapLibre client complies automatically, consistently across web, mobile, and tools like QGIS, with not a single license string typed in application code.
My position here is firm: attribution is a license obligation, not UI decoration. When the corner of the map feels crowded, what gets removed is your own duplicate, never the provider's legitimate notice. After this change the corner is clean, one line, and one bad habit died with it: typing license strings by hand.
Sources: [1] https://www.openstreetmap.org/copyright [2] https://osmfoundation.org/wiki/Licence/Attribution_Guidelines [3] https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/AttributionControlOptions [4] https://maplibre.org/maplibre-gl-js/docs/API/classes/AttributionControl [5] https://openfreemap.org [6] https://tiles.openfreemap.org/planet