I've two sublayers with interaction set as true and the proper columns added in the interactivity method. The featureClick listener is attached to the layer. On the one hand, popups are working on both sublayers independently when they are alone. But when both sublayers are present only the top-sublayer is triggering the featureClick event. How can I launch both popups from the two sublayers?

  • Can you try having an empty sublayer-0 and putting your data layers into 1 and 2. I've had this same issue before where the cartojs is expecting the actual map layer in the zero index, and not your data.
    – Jags
    Commented Feb 21, 2018 at 22:22
  • @jags can you suggest how to set an empty layer ?
    – amar
    Commented Mar 1, 2018 at 0:04

2 Answers 2


As Ramiroaznar, you can use the brand new CARTO.js v4 library to get interactivity in two layers and get your events in both of them.

You can check this gist. If you click on a city, you'll see in the console the country from one layer and the city from the other one.


If you can afford moving to CARTO.js, it's worth a try.

  • I don't see anything clickable (no cities). I do see countries, but nothing happens upon click. Nothing is written to the console log, except for the following: bl.ocks.org/:1 Uncaught (in promise) Error {message: "Unauthorized", origin: "windshaft", type: "auth", errorCode: "windshaft:auth:unknown-error", name: "CartoError", …} errorCode: "windshaft:auth:unknown-error" message: "Unauthorized" name: "CartoError" origin: "windshaft" originalError: i {_error: {…}, origin: "windshaft", type: "auth", subtype: "api-key-not-found", message: "Unauthorized", …} stack: "Error↵ at new ... Commented Jul 26, 2020 at 20:44

That's the expected behavior. Following the Detect feature flick and Add more layers example from CARTO.js v4 documentation, you can create an example similar to this one:

    <title>Feature click + 2 layers | CARTO.js v4</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700|Open+Sans:300,400,600" rel="stylesheet">
    <!-- Include Leaflet -->
    <script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
    <link href="https://unpkg.com/[email protected]/dist/leaflet.css" rel="stylesheet">
    <!-- Include CARTO.js -->
    <script src="https://cartodb-libs.global.ssl.fastly.net/carto.js/v4.0.0-beta.20/carto.min.js"></script>
      * {
        box-sizing: border-box;
      body, *{ margin: 0; padding: 0; }
      #map {
        position: absolute;
        height: 100%;
        width: 100%;
        z-index: 0;
    <div id="map"></div>
      const map = L.map('map').setView([30, 0], 3);

      L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_nolabels/{z}/{x}/{y}.png', {
        maxZoom: 18

      const client = new carto.Client({
        apiKey: 'YOUR_API_KEY',
        username: 'ramirocartodb'

      const citySource = new carto.source.Dataset(`
      const cityStyle = new carto.style.CartoCSS(`
        #layer {
          marker-width: 7;
          marker-fill: #EE4D5A;
          marker-line-color: #FFFFFF;
      const cityLayer = new carto.layer.Layer(citySource, cityStyle, {
        featureClickColumns: ['name', 'pop_max']

      const worldSource = new carto.source.Dataset(`
      const worldStyle = new carto.style.CartoCSS(`
        #layer {
          polygon-fill: #826DBA;
          polygon-opacity: 0.8;
          ::outline {
            line-width: 1;
            line-color: #FFFFFF;
            line-opacity: 0.8;
      const worldLayer = new carto.layer.Layer(worldSource, worldStyle, {
        featureClickColumns: ['name', 'pop2005']

      client.addLayers([worldLayer, cityLayer]);

      const cityPopup = L.popup({ closeButton: false });
      cityLayer.on('featureClicked', featureEvent => {
        let city = featureEvent.data.name;
        let pop_max = featureEvent.data.pop_max;
          <h3>${pop_max} inhab.</h3>

      const worldPopup = L.popup({ closeButton: false });
      worldLayer.on('featureClicked', featureEvent => {
        let country = featureEvent.data.name;
        let pop2005 = featureEvent.data.pop2005;
          <h3>${pop2005} inhab.</h3>


UPDATE: check @Ivan Malagon to see how it can be done. :-)

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.