Figure.tilemap/pygmt.datasets.tile_map: Set User-Agent to avoid blocked access to OSM tile server - #4816
Conversation
…g OSM tile policy
fa1927b to
0f25ab6
Compare
|
Ping @GenericMappingTools/pygmt-maintainers for reviewing this PR. Related but slightly off-topic: |
This seems to be a quite new issue: In PR #4809 merged on Sunday the tile maps gallery example looks good (https://pygmt-dev--4809.org.readthedocs.build/en/4809/gallery/maps/tilemaps.html), but in #4805 merged on Monday it fails and shows the reported issue (https://pygmt-dev--4805.org.readthedocs.build/en/4805/gallery/maps/tilemaps.html) . Looking at the wikipedia pages for openstreetmap there are quite recent updates, https://wiki.openstreetmap.org/w/index.php?title=Blocked_tiles&action=history and https://wiki.openstreetmap.org/w/index.php?title=Referer&action=history.
With the changes in this PR the tile maps gallery example seems to work again, including when building the documentation locally. I am wondering if our weekly Link-Checks on Sundays can catch this. Maybe we should add a note to the release checklist to manually check this gallery example shortly before making a new release.
I am afraid yes. This issue affects all PyGMT versions, i.e. using a lower version does not work as an (unelegant) workaround. Thus, the |
weiji14
left a comment
There was a problem hiding this comment.
Hmm, I've scanned through contextily's code/issues and found geopandas/contextily#75, and it seems they should have set a user-agent header of some sort already since 2019? Maybe the contextily- header is getting rate-limited 😅 so ok to set a custom PyGMT one, but I hope this doesn't get rate-limited too (if so, we'll know PyGMT's fig.tilemap is getting used a lot 😆).
Related but slightly off-topic:
Considering that the Figure.tilemap method is used in the PyGMT paper and it doesn't work now, I think we should make a new release, maybe v0.19.1?I am afraid yes. This issue affects all PyGMT versions, i.e. using a lower version does not work as an (unelegant) workaround. Thus, the
Figure.tilemapmethod is currently not working at all, and it's likely multiple users will face this issue (so far I see no reports on the forum). It's almost one and a half months until the end of September, which is the considered time range for the release of v0.20.0.
It's only not working for OpenStreetMap tiles, but should be ok for other tilemap providers. That said, yeah a v0.19.1 would probably be good in this case.
| "wait": wait, | ||
| "max_retries": max_retries, | ||
| "zoom_adjust": zoom_adjust, | ||
| "headers": headers, |
There was a problem hiding this comment.
Need to bump to contextily>=1.7 in pyproject.toml, ref geopandas/contextily#266 and https://github.com/geopandas/contextily/releases/tag/v1.7.0
There was a problem hiding this comment.
contextily 1.7 was released in November 2025, less than a year ago. It would be good if we could still support old versions.
It seems that we only need to pass the User-Agent header when using OSM (need to verify it). Perhaps we can continue supporting older versions of contextily in general, and require contextily>=1.7 only when OSM is used (i.e., checking if source is openstreetmap)?
Edit: Done in 0473d49.
There was a problem hiding this comment.
I think it's good to set the User-Agent header even if using a non-openstreetmap source, the changes look good to me.
Actually, a simple workaround is to use a different OSM tile server, e.g., the German one: |
That's interesting. Did not check this yesterday night; only looked at tiles beside OSM and these seem to work. |
This reverts commit 085c92c.
| # Please note, not all zoom levels are always available. | ||
| zoom=14, | ||
| # Use tiles from OpenStreetMap tile server | ||
| source="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", |
There was a problem hiding this comment.
No {s} according to https://operations.osmfoundation.org/policies/tiles/.
There was a problem hiding this comment.
Pull request overview
This PR updates PyGMT’s tilemap functionality to comply with OpenStreetMap tile usage policy by sending a User-Agent header with tile requests, and exposes a new headers parameter so callers can pass custom HTTP headers through to contextily.
Changes:
- Add a
headersparameter toFigure.tilemapandpygmt.datasets.load_tile_map, forwarding it tocontextily. - Set a default
User-Agentheader (PyGMT version + project URL) for tile requests when supported bycontextily. - Update the tilemaps gallery example and docstrings accordingly.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
pygmt/src/tilemap.py |
Adds headers parameter and documents header behavior for Figure.tilemap. |
pygmt/datasets/tile_map.py |
Implements headers passthrough and default User-Agent injection (version-gated on contextily). |
examples/gallery/maps/tilemaps.py |
Updates documentation example source URL and formatting in the gallery example. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| if headers is None: | ||
| headers = {"User-Agent": f"PyGMT/{_pygmt_version} (+https://www.pygmt.org)"} | ||
| contextily_kwargs["headers"] = headers |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
| HTTP headers to include with requests to the tile server. This can be useful | ||
| for authentication or to set a custom User-Agent. When supported by | ||
| ``contextily`` (>=1.7.0), PyGMT sets a default ``User-Agent`` header like | ||
| ``PyGMT/v0.19.0 (+https://www.pygmt.org)``. |
There was a problem hiding this comment.
Do we want to state v0.19.0 here, or can we just use PyGMT/vX.Y.Z (+https://...)?
weiji14
left a comment
There was a problem hiding this comment.
Thanks @seisman, looks reasonable to me, maybe get @yvonnefroehlich to have another quick look too before merging.
This workaround is a nice trick! |
Not sure why it worked before, but it turns out that now we need to set "User-Agent" when requesting tiles from the OSM tile server.
This PR sets the default User-Agent to something like
PyGMT/v0.19.0 (+https://www.pygmt.org)and allows custom headers.Reference:
Closes #4815.
Preview: