HOW TO

Extract and display metadata in ArcGIS Experience Builder using Python in ArcGIS Notebooks

Last Published: February 20, 2026

Summary

Metadata is data that describes an item. However, ArcGIS Experience Builder is unable to display metadata from a feature layer because its widgets are bound to attribute fields and statistics instead of item metadata. Therefore, Python scripting in ArcGIS Notebooks is required to enable metadata from a feature layer to be displayed in Experience Builder. Refer to ArcGIS Online: Use ArcGIS API for Python in a notebook for more information. In this article, a Python script demonstrates how to extract and display metadata in Experience Builder.

Procedure

This workflow extracts metadata (last edit date) using ArcGIS Notebooks and stores it in a hosted table for display in Experience Builder.

Prerequisites to successfully display metadata in Experience Builder:
• Select a feature layer in Experience Builder. This layer is read-only, and metadata is extracted from this layer.
• Create a hosted table in ArcGIS Online. This layer is used to store the updated metadata for display in Experience Builder.
  1. Log in to ArcGIS Online and click Notebooks > My notebooks > New notebook > Standard.
    Standard template type for Notebooks
  2. In the notebook, select Code from the drop-down list as the cell type.
    Code cell type in Notebooks
  3. In the first cell, paste the following code to authenticate the connection to the user's ArcGIS Online account and import Python libraries.
    # Defaults 
    from arcgis.gis import GIS
    from arcgis.features import FeatureLayer
    import requests
    from datetime import datetime
    import pytz
    
    gis = GIS("home")
    print("Logged in as:", gis.users.me.username)
    
Note:
After pasting the code, click Run this cell and advance The Run this cell and advance icon to execute the cell before proceeding to the next step. 
Note:
Click Insert a cell below (B) to add a cell below the current cell.
  1. In the second cell, paste the following code to define parameters for the feature layer and hosted table where the metadata fields are stored.
    SOURCE_LAYER_URL = "<feature layer URL>"
    DEST_TABLE_URL   = "<hosted table URL>/0" #hosted table URL-> make sure to paste the URL that ends with /0.
    DEST_OBJECTID    = 1
    FIELD_TEXT       = "last_updated_text" #field created in user own hosted table
    FIELD_DATE       = "last_updated_date" #field created in user own hosted table
    MYT              = "Asia/Kuala_Lumpur" #change this to user own location
    FORMAT           = "%Y-%m-%d %H:%M"
    print("✅ Parameters set.")
    
  1. In the third cell, paste the following code to extract the last updated timestamp from the third-party layer.
    import requests
    from datetime import datetime, timezone
    from zoneinfo import ZoneInfo  # Python 3.11+, no external dependency
    
    def request_json(url, params=None, timeout=30):
        p = {"f": "json", **(params or {})}
        r = requests.get(url, params=p, timeout=timeout)
        r.raise_for_status()
        j = r.json()
        if "error" in j:
            raise RuntimeError(f"REST error at {url}: {j['error']}")
        return j
    
    def get_last_updated_ms(layer_url: str) -> int:
        """Return epoch ms of last updated, preferring editingInfo.lastEditDate."""
        # 1) Try layer endpoint
        lyr = request_json(layer_url)
        ei = (lyr.get("editingInfo") or {})
        if isinstance(ei.get("lastEditDate"), (int, float)):
            return int(ei["lastEditDate"])
        # Try common direct keys
        for k in ("lastEditDate", "serviceUpdatedAt"):
            if isinstance(lyr.get(k), (int, float)):
                return int(lyr[k])
    
        # 2) Try service root (parent)
        parent_url = layer_url.rsplit("/", 1)[0]
        srv = request_json(parent_url)
        ei = (srv.get("editingInfo") or {})
        if isinstance(ei.get("lastEditDate"), (int, float)):
            return int(ei["lastEditDate"])
        if isinstance(srv.get("serviceUpdatedAt"), (int, float)):
            return int(srv["serviceUpdatedAt"])
    
        raise RuntimeError("Could not find last updated timestamp in layer or service root.")
    
    # Compute values
    ts_ms = get_last_updated_ms(SOURCE_LAYER_URL)              # <-- epoch ms (UTC)
    dt_utc = datetime.fromtimestamp(ts_ms/1000, tz=timezone.utc)
    dt_myt = dt_utc.astimezone(ZoneInfo(MYT))
    text_val = dt_myt.strftime(FORMAT) + " MYT"
    
    print("Last updated (text):", text_val)
    print("Last updated (UTC datetime):", dt_utc.isoformat())
    print("Last updated (MYT datetime):", dt_myt.isoformat())
    
  1. In the fourth cell, paste the following code to update the extracted timestamp in the hosted table.
    from arcgis.features import FeatureLayer
    import time
    
    dest_layer = FeatureLayer(DEST_TABLE_URL, gis=gis)
    
    # OPTIONAL: ensure fields exist (uncomment if needed)
    def ensure_field(layer: FeatureLayer, name: str, kind: str = "string"):
        fields = {f["name"].lower(): f for f in layer.properties.fields}
        if name.lower() in fields:
            return
        if kind.lower() == "date":
            new_field = {"name": name, "type": "esriFieldTypeDate", "alias": name, "nullable": True}
        else:
            new_field = {"name": name, "type": "esriFieldTypeString", "alias": name, "length": 255, "nullable": True}
        print(f"Creating field '{name}'...")
        res = layer.manager.add_to_definition({"fields": [new_field]})
        time.sleep(1.5)
        if isinstance(res, dict) and not res.get("success", True):
            raise RuntimeError(f"Failed to create field {name}: {res}")
    
    # Uncomment if you need schema creation
    # ensure_field(dest_layer, FIELD_TEXT, "string")
    # ensure_field(dest_layer, FIELD_DATE, "date")
    
    # Try to fetch the anchor record
    q = dest_layer.query(where=f"OBJECTID={int(DEST_OBJECTID)}", out_fields="*")
    if q.features:
        record = q.features[0]
        record.attributes[FIELD_TEXT] = text_val
        record.attributes[FIELD_DATE] = ts_ms           # <-- ArcGIS Date = epoch ms (UTC)
        res = dest_layer.edit_features(updates=[record])
    else:
        # Add one if missing (OBJECTID is usually auto-managed)
        new_feat = {"attributes": {FIELD_TEXT: text_val, FIELD_DATE: ts_ms}}
        res = dest_layer.edit_features(adds=[new_feat])
    
    print("✅ Record updated:", res)
    
  1. In cell 5, paste the following code to validate the workflow for Steps 5 through 7.
    rec = dest_layer.query(where=f"OBJECTID={int(DEST_OBJECTID)}", out_fields="*").features
    if rec:
        attrs = rec[0].attributes
        print(f"{FIELD_TEXT}: {attrs.get(FIELD_TEXT)}")
        print(f"{FIELD_DATE} (epoch ms UTC): {attrs.get(FIELD_DATE)}")
    else:
        print(f"No record found with OBJECTID={DEST_OBJECTID}. A new record may have been added with a different OBJECTID.")
    
  1. Click Save as and specify the file name. Click Save notebook.
  2. On the Content tab, click the web experience containing the feature layer, and click Edit.
  3. Add the hosted table to the web experience.
    1. Click the Data Data tab symbol tab and click Add data in the Data panel.
      Add data in the Data panel
    2. On the My content tab, select the hosted table and click Done. Ensure the hosted table is selected, indicated by a blue check mark in its top-right corner.
      Select the hosted table in the My content tab
    3. On the Data tab, ensure the hosted table is listed in the Data panel. In this example, it is sample_snap_retailers.
      The hosted table is added into the list in the Data panel
  1. Add and configure the Text widget.
    1. Click the Insert tab. In the Insert widget panel, on the New tab, under Page elements, drag and drop the Text widget onto the canvas.
      Select the Text widget from the Page elements in the Insert widget panel and drag and drop it onto the canvas
    2. In the configuration panel, on the Content tab, toggle Connect to data on and click Select data.
      Toggle Connect to data on and click Select data
    3. In the Select data panel, click Expand, then select the hosted table. In this example, sample_snap_retailers is selected.
      Click the feature layer after expanding the selected data in the Select data panel
    4. On the canvas, click the Text widget, and click Dynamic content Dynamic content symbol in the Text widget to open the Dynamic content pane.
    5. Click the Statistics tab.
    6. On the Statistics tab, for Data, ensure the correct feature layer is selected from the first drop-down menu. In this example, it is sample_snap_retailers.
    7. In the second drop-down menu, ensure Default is selected.
    8. For Operator, select MAX.
    9. For Field, select the metadata. In this example, it is Last Updated (UTC).
      Data field, Operator field, and Field value in the Statistics tab
    10. Click Insert.

The Text widget below shows the updated metadata information.

Metadata displayed in the Text widget

Article ID: 000039962

Software:
  • ArcGIS Online
  • ArcGIS API for Python
  • ArcGIS Experience Builder

Get support with AI

Resolve your issue quickly with the Esri Support AI Chatbot.

Start chatting now

Related Information

Discover more on this topic

Get help from ArcGIS experts

Contact technical support

Start chatting now

Go to download options