Digital Geography

24. April 2014

export your qgis project to a webmap with qgis2leaf

It was just a small idea but I haven’t slept much since it came to my mind to build a plugin fo QGIS. It should create a basic webmap from your current layers without coding and with popup functionality and changeable basemaps using leaflet. Meet my new daughter: qgis2leaf!

idea of qgis2leaf

When building a webmap with leaflet you probably start with a GIS to customize and change your geodata. We do this all the way: remove NaN points, change the projection and change position of features and much more. In the end we export the vector features to a geojson and after that we need to enhance the produced file a bit to give it a variable name. Then we write the leaflet webmap which more or less follows the same patterns:

<script src='data/places_few_1.js' ></script>
var map ='map', { zoomControl:true }).setView([0,0], 2);
function pop_line_feature(feature, layer) {
var popupContent = 'some text with relation maybe to the json data';
var line_featureJSON = new L.geoJson(line_feature,{
onEachFeature: pop_line_feature,
pointToLayer: function (feature, latlng) {
return L.marker(latlng);

As we are all human and we are doing failures and it consume pretty much time. And sometimes the only thing you would like to do is to share your qgis data with another one without sending/compressing dozens of shapefiles (remember the *.prj, *.dbf and all the other things). So here comes qgis2leaf.

qgis2leaf: what it does

qgis2leaf builds a webmap from all of your vector data in your current qgis project. It converts and saves them automatically in a folder structure as JSONs (reprojecting them to EPSG:4326 as well and to be exact: geoJSON), enhances them with a var XXX = and change file type to js. Then it creates the basic frame like basemap, popup content from the geoJSONs and the presentation of the layers in the map itself. The whole result is a folder structure with an index.html site which holds the webmap.

how to use qgis2leaf

First you need to install it. You might download it from github as it is still in review by the qgis team ATM (2014/04/24). You must unzip it to the plugin directory of QGIS which is “/home/yourusername/.qgis2/python/plugin/” on Linux and “C:\Users\{username}\.qgis2” on Windows machines. Enable the plugin using the dialog of QGIS (explanation on When you’re using the plugin you just need to define the dimension of the webmap html frame (1280×1024 is default), the basemap and the output folder name:

GUI of the new qgis2leaf plugin

The rest will be done by the plugin:

screenshot form the output webmap

what next

The next goals will be to enhance the initial view in leaflet regarding the input vector data, add a check box for the layer control and some more. If you find some feature useful: create an issue on github and let’s talk about. The big goal is to translate the style of the qgis canvas to a leaflet style… stay tuned and get involved: qgis2leaf on github

  • Great work! It seems to work quite smooth! Can’t wait for further updates!

  • This seems to be an interesting project.It would have been much better if you have uploaded the data as well as steps involved in this task so that even a beginner interested in learning web mapping can use this .Thank you

    • The test data is in the plugin folder under test_data. Best regards,


  • Pingback: qgis2leaf: Exporta un proyecto de QGIS a un visor web de Leaflet - MappingGIS()

  • Pingback: Aplicando estilos em camadas GeoJson em webmaps gerados pelo plugin qgis2leaf |

  • Pingback: Digital Geography()

  • Pingback: Digital Geography()

  • Pingback: Digital Geography()

  • Norrlandsson

    Awesome plugin!

    Is there any way to customize the basemap?

    • in the actual versions you can choose between several basemaps. or what do you mean exactly by “customize the basemap”?

      • Norrlandsson

        Thank you for the quick reply. I am working on a project which involves old maps and I was thinking if I can put one of them as background.

        • You can customize the basemap in the resulting index.html file by hand afterwards if you would like to use your own tileserver. We are working on an enhanced version of the plugin which will provide the functionality to add your own basemap provider. If you need support, give me a sign: ricckli @ skype

          • Norrlandsson

            Thank you for your disponibility ๐Ÿ™‚

  • Guest

    Nice plugin! But for me it doesn’t work at all ๐Ÿ™ Every time I export a map the index.html shows a completely blank page. Tested it with a single world-shapefile, but it nothing is shown. Would be great if someone could help me out ๐Ÿ™‚

    • Hi Stefan, I would love to help. can you provide your qgis version, the leaflet version and maybe a link to the dataset so i can try for my own?

      • Stefan


        leafle 0.7.3

        But – one dumb question: Shouldn’t it work with the src-links inside the html (as stand-a-lone), so I don’t have to work with my local leaflet version?

        • I was referring to your current qgis2leaf plugin version.
          looking at your data: the geometry of those country files is way to complex! you need to keep in mind when creating a webmap each vertex will be exported. furthermore your attribute tabel has colums with spaces. this works in QGIS but not in the leaflet webmap as we build the popup like : XXX. the space between “name” and “XXX” corrupts the index.html. you can use the table manager plugin in qgis to rename your tables.

          • Stefan

            Thanks for your fast reply! Will test it the next days ๐Ÿ™‚

  • Pingback: QGis Tutorial: webmap creation with QGis, QGis2leaf and MMQGIS | archaeoINaction()

  • Pingback: Top 5 QGIS Plugins | archaeoINaction()

  • Pingback: QGis Tutorial: webmap creation with QGis, QGis2leaf and GoogleSpreadsheet | archaeoINaction()

  • Dave

    Love this plugin, thanks for the work! My data spans a small area (300′ by 300′), is it possible to change the minimum zoom level? It would be very useful to be able to zoom to a small group of data points, the maps I’ve generated so far won’t allow me to zoom below the the extent of my data.

    • Hi Dave,

      thank you for your kind words. ATM we don’t set any fixed zoom levels. Each basemap style has its own max/min zooms. Can you provide some testdata on github? best regards,


  • I don’t think it’s useless as googlemaps is a commercial plugin and you need to export each layer as kml separately. Nevertheless the label function is an issue on github and we will prob. take care of it!

  • Jefferson

    Hello Ricardo, you are the creator of the application? Congratulations, great job !!!

    Ricardo, I have a couple of problems or doubts about the functions of the application, see if you can help me.

    1 – Is it possible to load the labels of vector layers?

    2 – I have two rasters with virtually the same properties: spatial resolution, format, EPSG, however one loaded, however the other presented the following error:

    Traceback (most recent call last):
    File “C:/Users/jefferson.faria/.qgis2/python/”, line 275, in export2leaf
    qgis2leaf_exec(self.outFileName, self.basemapName, self.basemapMeta, self.basemapAddress, self.width, self.height, self.extent, self.full_screen, self.layer_list, self.visible, self.opacity, self.encode2JSON,self.createcluster, self.webpage_name, self.webmap_head,self.webmap_subhead, self.legend,self.locate,self.address)
    File “C:/Users/jefferson.faria/.qgis2/python/”, line 451, in qgis2leaf_exec
    in_raster = str(i.dataProvider().dataSourceUri())
    UnicodeEncodeError: ‘ascii’ codec can’t encode character u’xe3′ in position 30: ordinal not in range(128)

    Versรฃo do Python:
    2.7.5 (default, May 15 2013, 22:44:16) [MSC v.1500 64 bit (AMD64)]

    Versรฃo do QGIS
    2.4.0-Chugiak Chugiak, 8fdd08a

    Caminho para o Python: [‘C:/PROGRA~1/QGISCH~1/apps/qgis/./python/plugins\processing’, ‘C:/PROGRA~1/QGISCH~1/apps/qgis/./python’, u’C:/Users/jefferson.faria/.qgis2/python’, u’C:/Users/jefferson.faria/.qgis2/python/plugins’, ‘C:/PROGRA~1/QGISCH~1/apps/qgis/./python/plugins’, ‘C:\PROGRA~1\QGISCH~1\bin\’, ‘C:\PROGRA~1\QGISCH~1\apps\Python27\DLLs’, ‘C:\PROGRA~1\QGISCH~1\apps\Python27\lib’, ‘C:\PROGRA~1\QGISCH~1\apps\Python27\lib\plat-win’, ‘C:\PROGRA~1\QGISCH~1\apps\Python27\lib\lib-tk’, ‘C:\PROGRA~1\QGISCH~1\bin’, ‘C:\PROGRA~1\QGISCH~1\apps\Python27’, ‘C:\PROGRA~1\QGISCH~1\apps\Python27\lib\site-packages’, ‘C:\PROGRA~1\QGISCH~1\apps\Python27\lib\site-packages\PIL’, ‘C:\PROGRA~1\QGISCH~1\apps\Python27\lib\site-packages\jinja2-2.7.2-py2.7.egg’, ‘C:\PROGRA~1\QGISCH~1\apps\Python27\lib\site-packages\markupsafe-0.23-py2.7-win-amd64.egg’, ‘C:\PROGRA~1\QGISCH~1\apps\Python27\lib\site-packages\pytz-2012j-py2.7.egg’, ‘C:\PROGRA~1\QGISCH~1\apps\Python27\lib\site-packages\win32’, ‘C:\PROGRA~1\QGISCH~1\apps\Python27\lib\site-packages\win32\lib’, ‘C:\PROGRA~1\QGISCH~1\apps\Python27\lib\site-packages\Pythonwin’, ‘C:\PROGRA~1\QGISCH~1\apps\Python27\lib\site-packages\Shapely-1.2.18-py2.7-win-amd64.egg’, ‘C:\PROGRA~1\QGISCH~1\apps\Python27\lib\site-packages\six-1.3.0-py2.7.egg’, ‘C:\PROGRA~1\QGISCH~1\apps\Python27\lib\site-packages\wx-2.8-msw-unicode’, ‘C:\PROGRA~1\QGISCH~1\apps\Python27\lib\site-packages\xlrd-0.9.2-py2.7.egg’, ‘C:\PROGRA~1\QGISCH~1\apps\Python27\lib\site-packages\xlwt-0.7.5-py2.7.egg’, ‘C:\Users\jefferson.faria\.qgis2\python\plugins\DigitizingTools\tools’, ‘C:\Users\jefferson.faria\.qgis2\python\plugins\MetaSearch\ext-libs’, ‘C:\Users\jefferson.faria\.qgis2\python\plugins\mmqgis/forms’, ‘/usr/share/qgis/python’, ‘C:\PROGRA~1\QGISCH~1\apps\qgis\python\plugins\fTools\tools’, ‘C:\Users\jefferson.faria\.qgis2\python\plugins\cadastre/forms’, ‘E:/Pessoal/Curso de Qgis’]

    • Hi Jefferson,

      Thank you very much for your comment. Exporting the labels is already an issue/addressed enhancement for the next versions of qgis2leaf. So we will work on it.
      Regarding your error: it looks like your faster may have a special character in its name so this why the export fails. Check the name also for spaces and please create a new issue on github And paste the name of failed to use.
      Best regards,

  • Elliott

    Hi Riccardo,

    First, thank you so much for putting this together. It’s incredibly useful.

    I’ve had issues since getting it to work since my first attempt, however. Can you help me troubleshoot, for example, why my data doesn’t load here and why this map loads zoomed all the way out? The first one loaded to the extent of the data.

    Exported qgis2leaf map:

    Thanks in advance for your help.


    • Hi Elliot,

      I just took a look at your webmap. normally, all the layers will be exported to wgs84 (EPSG:4326) . In yoiur webmap it seems so as well but the coordinates of your polygons are still messed up:
      “type”: “FeatureCollection”,
      “crs”: { “type”: “name”, “properties”: { “name”: “urn:ogc:def:crs:OGC:1.3:CRS84” } },
      “features”: [
      { “type”: “Feature”, “properties”: { “id_qgis2leaf”: 0, “color_qgis2leaf”: ‘#ff8000’, “transp_qgis2leaf”: 1.0, “transp_fill_qgis2leaf”: 1.0, “votdst”: “2200”, “NAME”: “SEA 32-2200”, “SUM_VOTERS”: 392.000000, “Shape_area”: 7348129.717390, “Shape_len”: 12221.943684, “MurrayV”: 153, “McGinnV”: 78, “MurrayP”: 0.662338, “McGinnP”: 0.337662 }, “geometry”: { “type”: “Polygon”, “coordinates”: [ [ [ 1260708.768279156647623, 266340.813181567180436 ], [ 1262092.657161191105843, 266300.575135603547096 ], [ 1262097.837925106287003, 264968.489873275160789 ], [ 1263077.489837184548378, 264941.986973524093628 ], [ 1263072.13715760409832, 264048.878851607441902 ], [ 1263135.015968859195709, 264035.001910850405693 ], [ 1263066.765121102333069, 263152.820932433009148 ], [ 1262634.098007440567017, 263384.618041023612022 ], [ 1262485.614052444696426, 263259.360089436173439 ], [ 1262220.727115020155907, 263170.461973264813423 ], [ 1261810.305035606026649, 263191.472101852297783 ], [ 1261188.755097612738609, 263382.311943277716637 ], [ 1260091.434129521250725, 263524.915988773107529 ], [ 1259621.402928458526731, 263783.857768463029061 ], [ 1259904.422000005841255, 263994.912000000476837 ], [ 1260297.651999995112419, 264583.452999994158745 ], [ 1260516.400999993085861, 265036.578999996185303 ], [ 1260735.150999993085861, 265695.43299999833107 ], [ 1260708.768279156647623, 266340.813181567180436 ] ] ] } },

      Those coordinates are non-EPSG4326 coordinates. Here are the coding lines from the plugin:
      exp_crs = QgsCoordinateReferenceSystem(4326, QgsCoordinateReferenceSystem.EpsgCrsId)

      if i.type() ==0:

      //which is true for vectors like polygons
      qgis.core.QgsVectorFileWriter.writeAsVectorFormat(i,dataStore + os.sep + ‘exp_’ + re.sub(‘[W_]+’, ”, + ‘.js’, ‘utf-8’, exp_crs, ‘GeoJson’)

      Can you provide the original dataset which you tried to export? It seems like it was not able to reproject. Which EPSG is used by the original datasets.

      • Elliott

        OK–dumb question; thanks for pointing this out. I think I can manage from here–I was able to project it properly and get it to work. Really appreciate this tool. Best,


    • ps: the map has this big extent as it tries to zoom to a latitude of 1262097 degrees ๐Ÿ˜‰

      • Elliott

        that is funny.

  • Thank you very much! This is very helpful. One question: Is there a possibility for the person viewing the map online to change the ortder of the layers ?

    • Hi @michielm:disqus ,
      thanks for your comment. you can “change” the layer order by disabling/enabling a layer again. if a layer is enable it will be placed on top i think. But we had some issues with this.

  • Nicodemus Nauwanga Amell

    Hello there.Any news with regard to labeling of vector files.
    Thank you.

    • we just embedded labe support in version 1.4. it’s not already in the repo, but you can try by using the github version

  • Mark Reimer


    I’m just curious if there is a way to set the maximum zoom a user can do when looking at a map. i.e. I don’t want the user to be able to zoom in further than 1:1000000


    • here you go: set the the minZoom and maxZoom in the index.html by hand:

      • Mark Reimer

        Thanks Riccardo! That worked. And for anyone else trying to figure out how to set the zooms, when you are viewing the map in your browser look at the “/index.html#6/” The “#6” is your zoom level. I didn’t want my map to zoom in further than 6 so my code looks like this:
        var map =‘map’, { zoomControl:true, maxZoom: 6 });

  • Habboub

    Many thanks, Riccardo.

  • zsolt

    Hello Ricardo,
    there is, or will be, possibel to group layers in some hierarcy? like A: A1, A2,… ; B: B1, B2,… etc, with radio buttons, or check ?
    other question: how many layers can be added in max. to leaflet?
    Thank you very much!

    • Hi @disqus_o3wn7slbP1:disqus ,

      thanks for your comment. ATM we have not implemented groups of layers. The maximum numbers of layers is unknown to me. Despite this discussion: keep in mind that your webmap should be easy to use and not so crowded by data. keep it simple when it comes to webmaps. and thats what the plugin is designed for… simple webmaps ๐Ÿ˜‰

      • zsolt

        Thank you for the answer, it is awesome indeed, simple fast, i like it!

  • Alexander Mikolyuk

    Hello RIcardo! Nice plugin!

    These comments do not find the answer to their questions.

    1) Is it possible to add a base map? (it is a shp file).

    2) Now you can display the signatures of objects without moving the cursor?

    Thank U

  • Bence

    Hello Ricardo!
    First of all I’d like to say thank you for this plugin!
    But i have the same problem like Jefferson (a comment 5 month ago), so i checked the file names and place names, but i still cant publish raster layers. When I tried to add vector layers from the same directory and same name it worked.
    Do you have any idea about this? Thank you!

    • Hi bence, we are not really sure what is causing the problem. Yet the process is quite easy: warp the image to be 4326. store it as jpg and add it to the webmap.
      Make sure your tiff has proper values in the range of 0-255…
      Nevertheless we already have an issue for the whole thing on github but no real time to deal with it… Sorry

      • Bence

        Thanks for your answer, im going to try out the advices!

      • Elizardo

        Hi Riccardo,
        I’m excited about this plug-in — thanks for you work on it.
        Like some of the others, I’m having trouble getting my raster to export with qgis2leaf. I’m trying to implement various suggestions I’ve found here and on the GitHub Issues list, but the advice about converting to jpg confuses me a little.

        My image is a GeoTiff. I georefectified it outside of QGIS, and then loaded it into my QGIS project. It’s projection is 4326.
        How do I load a jpg into leaf? Within QGIS, there’s no way to save a layer as a jpg. I know I’m missing something. Can you offer any advice?

        Thank you!

        • Hi Elizardo,

          thanks for your comment. Use the gdal tool “translate” in the processing toolbox to convert your geoTiff into a jpg.

          best regards,


          • Elizardo

            Thanks for the fast response!

            I was able to translate the layer to jpg, but it still doesn’t export correctly. The error message I’m getting is:

            Traceback (most recent call last):
            File “C:/Users/bettinge/.qgis2/python/”, line 297, in export2leaf
            qgis2leaf_exec(self.outFileName, self.basemapName, self.basemapMeta, self.basemapAddress, self.width, self.height, self.extent, self.full_screen, self.layer_list, self.visible, self.opacity, self.encode2JSON,self.createcluster, self.webpage_name, self.webmap_head,self.webmap_subhead, self.legend,self.locate,self.address, self.precision, self.labels, self.labelshover, self.matchCRS, self.selected)
            File “C:/Users/bettinge/.qgis2/python/”, line 581, in qgis2leaf_exec
            File “C:/PROGRA~1/QGISWI~1/apps/qgis/./python/”, line 71, in runalg
            alg = Processing.runAlgorithm(algOrName, None, *args)
            File “C:/PROGRA~1/QGISWI~1/apps/qgis/./python/”, line 270, in runAlgorithm
            if isinstance(algOrName, GeoAlgorithm):
            TypeError: isinstance() arg 2 must be a class, type, or tuple of classes and types

            Have you seen this one before?
            Many thanks in advance for your help.

  • Hi! with this plugin I make fantastic MAP …

  • Mark Reimer

    Hi Riccardo,

    I’m having issues with exporting (using Wien 2.8.1 and 64-bit machine) features, I’m not sure why or what the issue is though… I’ve played around with projections but nothing I do seems to solve this. My total dataset is 21,000 line segments (each 5 feet long), but I’ve tried doing a subset of this (200 line segments) and it also did not work. The javascript datafiles are all 1kb… I’ve used the plugin before and it has worked fine… any insights on similar issues with Wien, 64-bit, or exporting lines?


    • Mark Reimer

      Just an update, I’ve run now with QGIS 2.6 and 32-bit and it worked.

      • it works on my 64bit ubuntu like a charm. as well as on my windows 7 64bit with qgis 2.8.1 … maybe it’s a data problem?!
        But you are right. the plugin is not designed to work with joins as joins should be made permament if your map is finished… so save the layer as a shapefile and try it again.

        • Mark Reimer

          Thanks Riccardo, it was definitely the join, seems to work great now.

          The “selected layers only” feature still gives me problems and I’ve tested with a bunch of different data – found a work around though so I’m good to go.

          Thanks again, definitely love this plugin!

  • Ragnvald Larsen

    Thank you for a great plugin! Tried it today and after some tinkering around it worked fine. Would it be possible to keep a dynamic link to a http-based geojson-source? I guess it is a matter of just replacing the reference to the data catalog with a live source. But I am unfortunately quite a novice in using leaflet, but your plugin helps – bigtime!

  • Miukku

    Hello Ricardo,

    I wanted to learn to use this nice tool, so I downloaded data (ne_10m_airports.shp) from a nice tutorial site ( I guess the data should be ok as it is a tutorial page after all, but all I get is a following error message. What is wrong? Please, explain as simply as possible, thank you.

    Traceback (most recent call last):
    File “C:/Users/mnaukkar/.qgis2/python/”, line 297, in export2leaf
    qgis2leaf_exec(self.outFileName, self.basemapName, self.basemapMeta, self.basemapAddress, self.width, self.height, self.extent, self.full_screen, self.layer_list, self.visible, self.opacity, self.encode2JSON,self.createcluster, self.webpage_name, self.webmap_head,self.webmap_subhead, self.legend,self.locate,self.address, self.precision, self.labels, self.labelshover, self.matchCRS, self.selected)
    File “C:/Users/mnaukkar/.qgis2/python/”, line 290, in qgis2leaf_exec
    print ‘>> ‘ + crsProj4
    UnboundLocalError: local variable ‘crsProj4’ referenced before assignment

    Python versio:
    2.7.5 (default, May 15 2013, 22:44:16) [MSC v.1500 64 bit (AMD64)]

    QGIS versio:
    2.4.0-Chugiak Chugiak, 8fdd08a