You are using a browser that is no longer supported. Please use the latest version of Google Chrome, Mozilla Firefox, Apple Safari, or Microsoft Edge. For more information please see the System Requirements.
Skip To ContentArcGIS for DevelopersSign In Dashboard

Note: Support for 3D on mobile devices may vary, view the system requirements for more information.

This sample demonstrates how use an Arcade expression in a PopupTemplate to summarize points from one layer that intersect a polygon in a different layer.

The map in this sample contains two layers: a polygon layer representing block groups in San Diego and a point layer representing the locations of crimes. Each crime has a desc_ field describing the type of crime committed. It also has a is_night field containing either a 1 (crime committed at night) or a 0 (crime committed during the day). This app uses a single Arcade expression to do the following each time the user clicks a feature and opens the popup:

  1. Query the of crimes that intersect a selected polygon.
  2. Group those intersecting points by crime type and return the total count and average is_night value within each category.
  3. Sort the groups in descending order by count.

These three steps are reflected in the expression below.

<script type="text/arcgis-arcade" id="crimes-arcade">
  // 1. Query the number of crimes that intersect a selected polygon
  var crimes = Intersects(
    FeatureSetByName($map,"San Diego crimes", ["desc_", "is_night"])

  // 2. Group the intersecting points by crime type and return the total count
  // and average `is_night` value within each category of crimes
  var stats = GroupBy(crimes, ["desc_"],
    [ { name: "total", expression: "1", statistic: "count" },
      { name: "night_avg", expression: "is_night", statistic: "avg" }

  // 3. Sort the crime types in descending order by count.
  var topCrimes = Top(OrderBy(Filter(stats, "desc_ <> ''"), "total desc"), 3);

  var output = "";
  if(Count(topCrimes) == 0){
    return "No crimes committed in this area";
  var num = 0;
  // Format the results for display
  for(var item in topCrimes){
    var num_crimes =;
    var crimeType = item["desc_"];

    // The isNight field has values of either 1 or 0.
    // If the average value (night_avg) is high, then most crimes
    // occurred at night. If the average is low, then
    // the crimes typically occurred during daytime hours.

    var timeOfDay = When(
      item.night_avg >= 0.6, "at night",
      item.night_avg <= 0.4, " during the daytime hours",
    " at both night and day");

    // Display crime type with count using template literals
    output += `${num}. ${crimeType}
      -- Total offenses: ${Text(num_crimes, "#,###")}
      -- Most crimes were reported ${timeOfDay}

  return output;

The Arcade documentation for GroupBy() contains additional information for how to query multiple statistics (e.g. sum, min, max, average, standard deviation, variance) in Arcade with a single function call.

After authoring the Arcade expression, you can reference it in JavaScript as a string value and set it to the expression property of the expressionInfos in the layer's popupTemplate.

const arcadeScript = document.getElementById("crimes-arcade").text;

const blockGroups = new FeatureLayer({
        title: "U.S. Census Block Groups",
        portalItem: {
          id: "181b322639d44fcba6e37d8b82910daf"
        popupTemplate: {
          title: "Tract: {Tract}, Block Group: {BLKGRP}",
          content: "Top 3 crimes: <br\><br\>" +
          expressionInfos: [{
            // the name is used to reference the expression value in the template
            name: "top-crimes",
            title: "Top crimes",
            // the Arcade expression stored as text
            expression: arcadeScript

See the Popup profile of the Arcade expressions guide and the Reference Arcade expressions in PopupTemplate sample for more information about writing Arcade expressions for popups.

Sample search results