Possible to find out where feature layers are being used in web applications?

43816
54
Jump to solution
02-09-2022 08:12 AM
ZachRobinson_SantaClaraCounty
Emerging Contributor

I am wondering if it is possible to easily find out which web applications in our ArcGIS Online organization are using a specific feature layer.

For example, if I delete a layer from our organization, I want to make sure I know which web maps and applications the deletion will affect. This can be difficult and tedious to search manually when an organization has many web maps and applications. 

54 Replies
SarahWigley
Occasional Contributor

Many thanks for your quick reply. The format I used for the portal (in the original code) was this: 'https://xyz.maps.arcgis.com'. Is that correct? I tried with a / at the end, but that seemed to make no difference.  However, I shouldn't need to enter the portal url anywhere with your code, should I? I used your code within a new tool, and presumed it took the portal automatically from my ArcGIS Pro log-in?

0 Kudos
JustinMaysHMIS
Emerging Contributor

Hello Sarah,

Sorry for the late response. We are behind a firewall, and we connect to Enterprise server portals. When I run this script, I need to make sure my active portal (within ArcGIS Pro up at the top of the Pro window) is set to where I want to search. For our servers, the portal address looks something like this https://<server name>/arcgis/. Hope that helps.

If that does not help, I have been working on another tool that will search based on the service and looks at all web map/apps/experience builder locations where that service is being used. I do want to point out that sometimes when running scripts over and over again in Pro, it gets a little wonkey and you might need to restart Pro to clear everything out.

Good luck and let me know if you get it working.

Justin

0 Kudos
ErikAIversen
Occasional Contributor

Hi!

Made my own script that can search for "Web Maps", "Web Application", "Experience Builder", "Dashboard" or "All". 

1. Open notepad, pase the code below, choose "All files" save as your desired filename and location. Remember to add .py at the end of the filename

filename.png

2. Create a new toolbox in ArcGIS Pro and remember to add the parameters.

parameters.png

3. Link the toolbox to the code you saved in step 1.
script.png

import arcpy
from arcgis.gis import GIS
import time

# Connect to ArcGIS Pro portal session
gis = GIS("home")

# Parameters
find_id = arcpy.GetParameterAsText(0)
search_type = arcpy.GetParameterAsText(1)  # Web Map, Web Application, Dashboard, Experience Builder, All

start_time = time.time()

# Get feature service and its URL
content_item = gis.content.get(find_id)
if not content_item or not hasattr(content_item, "url") or not content_item.url:
    arcpy.AddError(" Could not retrieve a valid URL from the provided ID.")
    raise SystemExit

find_url = content_item.url
arcpy.AddMessage(f"🔍 Searching for usage of: {find_url}")

# 1. Pull all Web Maps and collect those referencing the feature service
all_webmaps = gis.content.search('', item_type='Web Map', max_items=1000)
map_ids = []

for wm in all_webmaps:
    try:
        if find_url in str(wm.get_data()):
            map_ids.append(wm.id)
            arcpy.AddMessage(f"✔️ Found referencing Web Map: {wm.title} ({wm.id})")
    except:
        continue

# 2. Load other content types conditionally
webmaps = all_webmaps if search_type in ('Web Map', 'All') else []
webapps = gis.content.search('', item_type='Application', max_items=1000) if search_type in ('Web Application', 'All') else []
dashboards = gis.content.search('', item_type='Dashboard', max_items=1000) if search_type in ('Dashboard', 'All') else []
webexp = gis.content.search('', item_type='Web Experience', max_items=1000) if search_type in ('Experience Builder', 'All') else []

# 3. Recursive matching function for nested itemId references
def references_map_id(item_data, map_ids):
    def search_dict(d):
        for key, value in d.items():
            if key == "itemId" and value in map_ids:
                return True
            elif isinstance(value, dict):
                if search_dict(value):
                    return True
            elif isinstance(value, list):
                for item in value:
                    if isinstance(item, dict) and search_dict(item):
                        return True
        return False
    return search_dict(item_data)

# 4. Results
web_map_list, app_list, dash_list, exp_list = [], [], [], []

# --- Web Maps ---
if search_type in ('Web Map', 'All'):
    for i, wm in enumerate(webmaps):
        arcpy.AddMessage(f":hourglass_not_done: Checking Web Map {i+1}/{len(webmaps)}: {wm.title}")
        try:
            data = str(wm.get_data())
            if find_url in data:
                web_map_list.append(wm)
        except:
            continue
    arcpy.AddMessage(f":package: Checked {len(webmaps)} web maps.")
    if web_map_list:
        arcpy.AddMessage(f" Found {len(web_map_list)} Web Map(s):")
        for item in web_map_list:
            arcpy.AddMessage(f"🔗 {item.title} ({item.id}) [{item.type}]")
    else:
        arcpy.AddMessage(" No Web Maps found.")

# --- Web Applications ---
if search_type in ('Web Application', 'All'):
    for i, wa in enumerate(webapps):
        arcpy.AddMessage(f":hourglass_not_done: Checking Web App {i+1}/{len(webapps)}: {wa.title}")
        try:
            data = str(wa.get_data())
            if find_url in data or any(mid in data for mid in map_ids):
                app_list.append(wa)
        except:
            continue
    arcpy.AddMessage(f":package: Checked {len(webapps)} web apps.")
    if app_list:
        arcpy.AddMessage(f" Found {len(app_list)} Web App(s):")
        for item in app_list:
            arcpy.AddMessage(f"🔗 {item.title} ({item.id}) [{item.type}]")
    else:
        arcpy.AddMessage(" No Web Applications found.")

# --- Dashboards ---
if search_type in ('Dashboard', 'All'):
    if dashboards:
        for i, db in enumerate(dashboards):
            arcpy.AddMessage(f":hourglass_not_done: Checking Dashboard {i+1}/{len(dashboards)}: {db.title}")
            try:
                raw = db.get_data()
                if references_map_id(raw, map_ids):
                    dash_list.append(db)
                    arcpy.AddMessage(f":collision: MATCH FOUND in Dashboard: {db.title}")
            except:
                arcpy.AddMessage(f":warning: Failed to parse Dashboard: {db.title}")
                continue
        arcpy.AddMessage(f":package: Checked {len(dashboards)} dashboards.")
        if dash_list:
            arcpy.AddMessage(f" Found {len(dash_list)} Dashboard(s):")
            for item in dash_list:
                arcpy.AddMessage(f"🔗 {item.title} ({item.id}) [{item.type}]")
        else:
            arcpy.AddMessage(" No Dashboards found.")

# --- Experience Builders ---
if search_type in ('Experience Builder', 'All'):
    if webexp:
        for i, we in enumerate(webexp):
            arcpy.AddMessage(f":hourglass_not_done: Checking Experience Builder {i+1}/{len(webexp)}: {we.title}")
            try:
                raw = we.get_data()
                if references_map_id(raw, map_ids):
                    exp_list.append(we)
                    arcpy.AddMessage(f":collision: MATCH FOUND in Experience Builder: {we.title}")
            except:
                arcpy.AddMessage(f":warning: Failed to parse Experience Builder: {we.title}")
                continue
        arcpy.AddMessage(f":package: Checked {len(webexp)} experience builders.")
        if exp_list:
            arcpy.AddMessage(f" Found {len(exp_list)} Experience Builder(s):")
            for item in exp_list:
                arcpy.AddMessage(f"🔗 {item.title} ({item.id}) [{item.type}]")
        else:
            arcpy.AddMessage(" No Experience Builders found.")

# --- Final Summary
arcpy.AddMessage("\n:bar_chart: ==== FINAL SUMMARY ====")
if search_type in ('Web Map', 'All'):
    arcpy.AddMessage(f"Web Maps         : {len(web_map_list)}")
if search_type in ('Web Application', 'All'):
    arcpy.AddMessage(f"Web Applications : {len(app_list)}")
if search_type in ('Dashboard', 'All'):
    arcpy.AddMessage(f"Dashboards       : {len(dash_list)}")
if search_type in ('Experience Builder', 'All'):
    arcpy.AddMessage(f"Experience Builds: {len(exp_list)}")

total = len(web_map_list) + len(app_list) + len(dash_list) + len(exp_list)
arcpy.AddMessage(f"\n🧮 TOTAL MATCHES : {total}")
arcpy.AddMessage(f":stopwatch:️ Runtime        : {round(time.time() - start_time, 2)} seconds")

 

Jesse_Albers
Emerging Contributor

@lxk1170 do you have any idea how to implement this with SAML authentication?

0 Kudos
JustinMaysHMIS
Emerging Contributor

See my code above this post. We use SAML and it works for me. Good luck!

0 Kudos