I am in the process of adding a WMS map server to a map I wrote in JavaScript using the Mapbox GL JS library.

The map server is using the WMS from the FEMA National Flood Hazard Layer, and I would like to subset that data to a few specific Fields and overlay that onto my map..

I am using this Mapbox GL JS tutorial to add the WMS layer, I am running into two problems:

  1. I can't get the layer to display
  2. I can't subset the right fields I need to display

The code I am using...

    <!DOCTYPE html>
        <meta charset='utf-8' />
        <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
        <script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.44.1/mapbox-gl.js'></script>
        <script src='https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v2.2.0/mapbox-gl-geocoder.min.js'></script>
        <link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet">
        <link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.44.1/mapbox-gl.css' rel='stylesheet' />
        <link href="https://fonts.googleapis.com/css?family=Inconsolata" rel="stylesheet">
        <link rel='stylesheet' href='https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v2.2.0/mapbox-gl-geocoder.css' type='text/css' />
                body {
                  margin: 0;
                  padding: 0;
                #map {
                  position: absolute;
                  top: 0;
                  bottom: 0;
                  width: 100%;
                  height: 100%;
                #menu {
                  position: absolute;
                  background: rgba(64, 64, 64, 0.15);
                  padding: 5px;
                  font-family: 'Inconsolata';
                  font-size: 12px;
                .marker {
                  background-image: url('/maki_icons/icons/square-stroked-11.svg');
                  background-size: cover;
                  width: 12px;
                  height: 12px;
                  cursor: pointer;
                  padding: 0px;
                .mapboxgl-popup {
                  max-width: 200px;
                .mapboxgl-popup-content {
                  text-align: center;
                  font-family: 'Open Sans', sans-serif;
    <div id='map'></div>
    <div id='menu'>
        <input id='streets' type='radio' name='rtoggle' value='streets'>
        <label for='streets'>streets</label>
        <input id='light' type='radio' name='rtoggle' value='light'>
        <label for='light'>light</label>
        <input id='satellite' type='radio' name='rtoggle' value='satellite'>
        <label for='satellite'>satellite</label>
    mapboxgl.accessToken =

        //load map
          var map = new mapboxgl.Map({
            container: 'map',
            style: 'mapbox://styles/mapbox/streets-v10',
            center: [-96, 37.8],
            zoom: 3.5,

        //add second layer of data
            map.on('load', function() {

          //add the FEMA WMS layer
                'id': 'wms-test-layer',
                'type': 'raster',
                'source': {
                'type': 'raster',
                'tiles': [

          // Tile switcher
          var layerList = document.getElementById('menu');
          var inputs = layerList.getElementsByTagName('input');

          function switchLayer(layer) {
              var layerId = layer.target.id;
              map.setStyle('mapbox://styles/mapbox/' + layerId + '-v9');

          for (var i = 0; i < inputs.length; i++) {
              inputs[i].onclick = switchLayer;

1 Answer 1


In your addLayer function, the tiles option must be the URL to the raster tiles. https://hazards.fema.gov/gis/nfhl/rest/services/public/NFHL/MapServer/28 is the URL to the HTML page describing the ERSI MapServer service.

Although that service doesn't appear to support WMS it supports an /export which we can force to return raster tiles in the right format for Mapbox GL JS. So you should replace your tiles URL with this:


You can change that layers=28 to another layer number or I think use a comma separated value for multiple layers.

You might want to consider inserting this layer below the roads and label layers as well.

  • Sorry I missed that part about filtering by an attribute, I can't see how to do that, but it might be possible. I would have suggested using the WFS feed but it seems to only support GML which would require an additonal library to convert it to GeoJSON hazards.fema.gov/gis/nfhl/services/public/NFHL/MapServer/… Commented Mar 19, 2018 at 23:27
  • hey thats awesome, thanks very much! may I ask how or where you found out about the /export that was in the right format for Mapbox? I want to see if that bread crumb trail leads to learning how to filter out the necessary attributes. I'm not familiar with that syntax Commented Mar 21, 2018 at 3:29
  • 2
    If you go up a level to hazards.fema.gov/gis/nfhl/rest/services/public/NFHL/MapServer you'll see at the bottom it says "Supported Operations: Export Map Identify Find Return Updates". The first one Export map returns a raster, so if you click through you can see all your options. mapbox.com/mapbox-gl-js/style-spec#sources has a section on WMS layers showing how GL JS can substitute in a bbox for each tile request, together with a setting the right coordinate system, image size and layers param you can get a raster tile for GL JS from that ArcGIS service. Commented Mar 21, 2018 at 10:13
  • @AndrewHarvey, I couldn't get the code sample to run. Is there anything else that needs to done? I couldn't find any documentation from FEMA on how to use the webservice in general, or how to form the url endpoint you posted. Is there a more general term I could look up that would teach me how to interact with services like this one? Then I could apply that general knowledge to this FEMA service. Thanks.
    – alfonso
    Commented Jan 16, 2020 at 18:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.