Self-hosted service
AliFlux/MapTilesDownloader avatar
AliFlux/MapTilesDownloader

MapTilesDownloader: a local web app for pulling map tiles offline

A super easy to use map tiles downloader built using Python

552 stars149 forksPythonMIT

At a glance

What is it?
MapTilesDownloader is a small Python script with a browser based map interface for downloading tiles from Google, Bing, OpenStreetMap, ESRI and others, with parallel downloads, MBTiles and directory output, and a built-in stitcher that assembles the result into a GeoTIFF using libvips. It is MIT licensed, and the readme is unusually direct about the terms of service problem.
Who is it for?
Adopt MapTilesDownloader if you need tiles for offline use, for example for field work, an offline viewer or an archive of a region, and you are comfortable with the legal grey area that comes with it. Do not adopt it for anything commercial without reading the provider terms yourself, because the readme says so plainly and the Google endpoints are unofficial and may be rate-limited.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 176 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A script with a browser front end

MapTilesDownloader is described as a super easy to use GUI for downloading map tiles, and the implementation is a tiny Python based script with an easy to use web based map UI for selecting the area and previewing tiles.

That combination is the interesting design decision. A local server that serves a map interface to your own browser, rather than a desktop GUI toolkit or a command line tool, means you get pan, zoom and rectangle selection from a real slippy map with no extra dependencies, and the script itself stays small enough to read in an afternoon.

The whole thing runs with two commands:

sh
cd src
python server.py

Then you open a web browser and navigate to http://localhost:8080, and the output map tiles end up in the src/output/{timestamp}/ directory by default.

The timestamp in the path is a sensible default. Every run gets its own directory, so two downloads of different regions or different zoom levels do not collide, and a failed run does not leave a half-written set mixed in with the good one.

The requirements are Python 3.13 or newer and a modern web browser. There is a detail in the readme worth noting: the cgi module was removed in Python 3.13 and the repository has been updated to use the email module as a replacement, and Python versions older than 3.13 are not tested with the current code. That is the kind of statement that saves an afternoon, because a reader on Python 3.11 would otherwise assume something was broken rather than unsupported.

The dependencies are just two, and each does a specific job. Pillow handles tile scaling for 2x and Hi-Res output. pyvips handles tile stitching, with the readme describing it as memory-efficient image assembly.

The install note about libvips is the one practical gotcha. On Windows, pyvips with the binary extra bundles the required libvips DLLs automatically. On Linux and macOS you install libvips through the package manager, apt install libvips or brew install vips, before running pip.

Providers, and the honest column in the table

The provider table is short and has a Notes column that is more informative than the provider names.

Bing Maps comes in three flavours, road, satellite, and hybrid for satellite with labels. Google Maps comes in four, road, satellite, hybrid and terrain, and all four carry the same note: unofficial endpoint, may be rate-limited. OpenStreetMap is road, Open Cycle Maps is cycling, Carto Light is a minimal road map, and ESRI World Imagery is satellite.

The readme then gives a recommendation: for the highest quality satellite imagery, use ESRI World Imagery at zoom level 18 or 19. And the table describes it as best quality, up to zoom 19-20, free, no key required.

That recommendation is the useful part, because it is a recommendation about the outcome rather than about the provider. Someone who wants offline satellite imagery for a region will end up with Google if they pick the first satellite option they see, and the readme is steering them past that. The Google endpoints are unofficial, which means they are not a supported interface and they are rate-limited, which means a large download will be slow or throttled. ESRI needs no key and is not described as unofficial.

The feature list has a broader claim about providers still. It supports ANY tile provider as long as the URL has x, y, z or quad in it. That is a simple and generous rule, and it is what makes the tool more useful than the dropdown suggests, because the dropdown is a set of verified presets rather than the whole capability.

The base map uses OpenStreetMap, and the readme notes no API key is required for it, which is the default configuration and the one that involves the fewest questions.

Zoom levels and the arithmetic of tiles

The zoom level section is short and contains the number that decides how long your download takes. Each level up has four times more tiles than the previous.

That is exponential growth in the tile count, and the table of detail levels gives a sense of what each band is for. Zoom 1 to 5 is country or continent, 10 to 12 is city, 15 to 16 is street, which is the default, and 18 to 19 is building or maximum detail.

So a zoom 10 download is a manageable number of tiles and a zoom 18 download is four times that, then four times that again, then four times that again. The gap between a street-level view and a building-level view is two levels, which is a factor of sixteen in tiles.

The readme explains the two ways to set the range. Set Zoom from and Zoom to to the same value to download only that level, or set a range to download multiple levels at once, which it describes as useful for maps that need to work at different scales.

That multi-zoom case is the one that catches people, because it multiplies the arithmetic. If you select 10 through 19 you are asking for every level in between, and the total is dominated by the highest level. The readme's advice about zooming to 18 or 19 for imagery quality is therefore also advice about download size, and the two trade against each other.

The feature list also covers the things that make a bulk download practical rather than theoretical. Multi-threading downloads tiles in parallel. Ability to ignore tiles already downloaded, which matters enormously when you are resuming or extending an earlier selection. Select multiple zoom levels in one go. Specify any custom file name format. Supports downloading to file as well as mbtile format.

That last one is a real distinction. A directory of PNG tiles and an MBTiles file are the two standard ways of packaging tiles, and they serve different consumers. A directory of individual files is what the built-in stitcher consumes and what many offline viewers expect. An MBTiles file is a single SQLite database with the tiles inside, which is what most mobile and desktop map applications consume.

The stitcher, and why libvips rather than Pillow

The feature that distinguishes this from every other small tile downloader is the built-in tile stitcher, which assembles all downloaded tiles into a single GeoTIFF with one click.

The readme is precise about why libvips is used. Unlike Photoshop or Pillow, libvips processes images in strips rather than loading everything into RAM, so it handles multi-gigapixel outputs without running out of memory. That is the whole argument, and it is a good one. A zoom 19 download over a city produces a mosaic that is easily many gigapixels, and an assembler that loads the whole canvas into memory will fail on exactly the downloads that are most worth stitching.

The flow is five steps. Check Stitch tiles into image after download, which is visible above the Download button and only enabled for Directory output type. Start the download as normal. Once all tiles have downloaded, stitching begins automatically. Progress is shown in the log panel and the button shows STITCHING while it runs. The output is saved alongside the tile folders as stitched_z{zoom}.tif, one file per zoom level.

The output format is a tiled, deflate-compressed TIFF compatible with GIS tools such as QGIS, GDAL and ArcGIS, as well as image editors. Producing a separate file per zoom level for a zoom range is the right behaviour, because a single stitched image across multiple zooms would have no coherent scale.

The constraint is stated too. Stitching is only available when Output type is set to Directory, which is the default, because MBTiles and Repo formats store tiles internally and do not produce individual image files to stitch from. That is a logical limitation rather than an oversight, and it is a fair one, since a stitcher needs the individual tiles on disk.

The rest of the output story is small. Tiles are saved to src/output/{timestamp}/ in a {z}/{x}/{y}.png folder structure, which is the standard slippy map layout that most tooling understands, and both the output directory and the file name format can be customised under More Options in the UI.

Docker, the disclaimer, and the inconsistency in the build

There is a Docker route, and it is one command:

sh
docker run -v $PWD/output:/app/output/ -p 8080:8080 -it aliashraf/map-tiles-downloader

The volume mount is the important part, because it is what puts the downloaded tiles on your host filesystem rather than inside the container. The port mapping exposes 8080, and the readme says to open the browser and head over to http://localhost:8080, with the downloaded maps stored in the output directory.

The Dockerfile itself is minimal and worth reading. It starts from python:3.8, sets a working directory of /app, copies src/requirements.txt in, runs pip install -r requirements.txt, copies the src directory into /app, exposes 8080, and runs python server.py as its command.

That python:3.8 base line is in tension with the readme's requirement of Python 3.13 or newer, and the readme's own note about the cgi module removal in 3.13 makes the consequence concrete. On Python 3.8, the cgi module still exists but the code has been rewritten to use the email module instead, and the readme says versions older than 3.13 are not tested with the current code. The Docker image is therefore likely to run the server but is not on a tested configuration. It is the kind of inconsistency that only shows up when you build the image and wonder why the behaviour differs from running it locally.

The disclaimer section is the most unusually candid part of the readme. Downloading map tiles is subject to the terms and conditions of the tile provider, and some providers such as Google Maps have restrictions in place to avoid abuse, so you should understand their terms of service before downloading. The author's own recommendation is not to use Google, Bing and ESRI tiles in any commercial application without their consent.

That is worth taking seriously rather than as boilerplate. The distinction the readme draws between personal offline use and commercial use is real, and the Google endpoints being unofficial and rate-limited is an operational fact as well as a legal one.

The project is MIT licensed, copyright Ali Ashraf from 2020, and the readme points to aliashraf.net for release announcements. There are no GitHub releases published, and the last push was on 2026-04-30.

Editorial conclusion

Adopt MapTilesDownloader if you need tiles for offline use, for example for field work, an offline viewer or an archive of a region, and you are comfortable with the legal grey area that comes with it. Do not adopt it for anything commercial without reading the provider terms yourself, because the readme says so plainly and the Google endpoints are unofficial and may be rate-limited. Before you commit, read the disclaimer section, use ESRI World Imagery rather than Google if you need high quality imagery, and check the Dockerfile, because it still declares Python 3.8 while the readme says Python 3.13 or newer is required.

Frequently asked questions

How do I run MapTilesDownloader?

Run cd src and then python server.py, then open http://localhost:8080 in a web browser. It needs Python 3.13 or newer and a modern browser, with dependencies installed using pip install -r requirements.txt. Output goes to src/output/{timestamp}/ by default, and Docker is offered as an alternative.

Which map tile providers does MapTilesDownloader support?

The dropdown offers Bing Maps in road, satellite and hybrid flavours, Google Maps in road, satellite, hybrid and terrain flavours, OpenStreetMap, Open Cycle Maps, ESRI World Imagery and Carto Light. The readme notes the Google endpoints are unofficial and may be rate-limited, and recommends ESRI World Imagery at zoom 18 or 19 for the highest quality satellite imagery. Any provider whose URL contains x, y, z or quad is supported.

What are the dependencies for MapTilesDownloader?

Two. Pillow handles tile scaling for 2x and Hi-Res output, and pyvips handles tile stitching with memory-efficient image assembly. On Windows, pyvips with the binary extra bundles the libvips DLLs automatically, while on Linux and macOS you install libvips with apt install libvips or brew install vips before running pip.

What does the built-in tile stitcher produce?

A tiled, deflate-compressed TIFF saved alongside the tile folders as stitched_z{zoom}.tif, one file per zoom level, compatible with GIS tools such as QGIS, GDAL and ArcGIS. It uses libvips so that multi-gigapixel outputs are processed in strips rather than loaded into memory. Stitching only runs when Output type is Directory, since MBTiles and Repo formats store tiles internally.

Is using MapTilesDownloader allowed?

The readme says downloading map tiles is subject to the terms and conditions of the provider, that some providers such as Google Maps have restrictions in place to avoid abuse, and that you should understand their terms before downloading. The author's own recommendation is not to use Google, Bing and ESRI tiles in any commercial application without their consent.

Official sources

  1. AliFlux/MapTilesDownloader on GitHub
  2. Issues
  3. License: MIT
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/aliflux-maptilesdownloader.svg)](https://hysenlabs.com/projects/aliflux-maptilesdownloader)

Was this useful?