Skip to page contentSkip to chat
ServiceNow support
    • Community
      Ask questions, give advice, and connect with fellow ServiceNow professionals.
      Developer
      Build, test, and deploy applications
      Documentation
      Find detailed information about ServiceNow products, apps, features, and releases.
      Impact
      Accelerate ROI and amplify your expertise.
      Learning
      Build skills with instructor-led and online training.
      Partner
      Grow your business with promotions, news, and marketing tools
      ServiceNow
      Learn about ServiceNow products & solutions.
      Store
      Download certified apps and integrations that complement ServiceNow.
      Support
      Manage your instances, access self-help, and get technical support.
How to identify a slow widget on a page - Support and Troubleshooting
  • >
  • Knowledge Base
  • >
  • Support and Troubleshooting (Knowledge Base)
  • >
  • How to identify a slow widget on a page
KB0744521

How to identify a slow widget on a page


27773 Views Last updated : May 5, 2023 public Copy Permalink English (Original)
  • English (Original)
  • Japanese
KB Summary by Now Assist

Issue

This article will help you determine exactly which widget on a service portal page is slow in a very concrete and easy way. 

Procedure

  1. Copy this script:
    (async () => {
      let threshold = 1000; // only show load times for widgets higher than this value (in milliseconds)
      var wa = $("div [widget='widget']").css("border", "1px solid red").css("padding-top", "20px").css("position", "relative")
      let widgetTable = [];
      let wmk = [];
      for (var i = 0; i < wa.length; i++) {
        let widgetEntry = {};
        $0 = wa[i]
        let scope = $($0).scope();
        try{
          var widget = scope.widget;
        } catch(e){
          console.error(e);
          continue;
        }
        var timing = 0;
        let elem = $("<div style='position: absolute; top: 1px; left: 1px'><a target='_blank' href='/$sp.do?id=widget_editor&sys_id=" + widget.sys_id + "'> " + widget.name + "</a>&nbsp;&nbsp;</div>");
        var printScope = $("<a href='javascript:void(0);'>Print scope </a>").on('click', function() {
          console.info(scope);
        });
        elem.append(printScope);
        widgetEntry.name = widget.name;
        widgetEntry.rectangle = widget.rectangle_id || 'undefined';
        widgetEntry.sys_id = widget.sys_id;
        let id = scope.widget.rectangle_id + "_" + scope.$id
    
        // if this is not a nested widget, go ahead and refresh it.
        if (!scope.$parent || !scope.$parent.widget) {
          var widget_name = widget.name;
          var t0 = performance.now();
          await scope.server.refresh();
          var t1 = performance.now();
          timing = "<div style='float:right;color:red;' id='" + id + "'> Load Time: " + parseInt(t1 - t0) + " ms.</div>";
          widgetEntry.load_time_ms = parseInt(t1 - t0) || 0;
          elem.append(timing);
        }
        // add a button to refresh manually.
        var loadTime = $("<button style='border-radius: 50%;'> ⟳ </button>").on('click', function() {
          var widget_name = scope.widget.name;
          let id = scope.widget.rectangle_id + "_" + scope.$id
          var t0 = performance.now();
          scope.server.refresh().then(() => {
            var t1 = performance.now();
            timing = "<div style='float:right;color:red;' id='" + id + "'> Load Time: " + parseInt(t1 - t0) + " ms.</div>";
            widgetEntry.load_time_ms = parseInt(t1 - t0) || 0;
            if ($('#' + id)) {
              $('#' + id).remove();
            }
    
            elem.append(timing);
            console.log("Call to " + widget_name + " took " + (t1 - t0) + " ms.");
          });
        });
    
        elem.append(loadTime);
        $($0).append(elem);
        widgetTable.push(widgetEntry);
      }
      widgetTable.sort((a, b) => (a.load_time_ms > b.load_time_ms) ? 1 : -1);
      var slow = widgetTable.filter((e, i, w) => {
        return e.load_time_ms >= threshold;
      });
    
      let mkdn = `|Name|sys_id|rectangle_id|Load Time Ms|
    |:---:|:---:|:---:|:---:|
    ${slow.map((widgetEntry, i, widgetTable) => {
    return `|${widgetEntry.name}|${widgetEntry.sys_id}|${widgetEntry.rectangle}|${widgetEntry.load_time_ms}|`;
    }).join("\n")}`;
      var doCopy = function() {
        var el = document.createElement('textarea');
        el.value = mkdn;
        el.setAttribute('readonly', '');
        el.style = {
          position: 'absolute',
          left: '-9999px'
        };
        document.body.appendChild(el);
        el.select();
        document.execCommand('copy');
        document.body.removeChild(el);
      }
      var elem = `<div style="float: right;
    z-index: 1;
    position: relative;
    left: -50%; /* or right 50% */
    text-align: left;
    padding:10px">
    <h2>${(slow.length > 0)?"Slow Widgets:" : "No Slow Widgets Found!"}</h2>
    <table style="padding:3px; display:${(slow.length > 0)?"table":"none"}">
    <tr><td style="padding:3px;" >Name</td><td style="padding:3px;">sys_id</td><td style="padding:3px;">rectangle id</td><td style="padding:3px;">load time ms</td></tr>
    ${slow.map((widgetEntry, i, widgetTable) => {
    return `<tr><td style="padding:3px;">${widgetEntry.name}</td><td style="padding:3px;">${widgetEntry.sys_id}</td><td style="padding:3px;">${widgetEntry.rectangle}</td><td style="padding:3px;">${widgetEntry.load_time_ms}</td></tr>`;
    }).join(" ")}
    </table>
    <button onClick=${doCopy()} style="display:${(slow.length > 0)?"table":"none"}">Copy Markdown</button>
    </div>`;
      $('body').append(elem);
    })();
    
  2. Open the portal page which is slow.
  3. After the page loads open the javascript console (command + option + j), then paste the above script and press enter. 
    • By default, this script will output any widgets which take 1 second or more to load. This can be changed by changing the value of the threshold variable defined at the top of the script.
  4. Each widget on the page will refresh. A colored box will be displayed around each widget containing the time it took to load (in milliseconds).
  5. Additionally, a table will be shown at the bottom of the page to display the widgets which were either at or above the threshold time (in milliseconds) and in that table, you will see a button to copy the table as markdown to your clipboard automatically.

 

Related Links

Worth noting, this does not automatically refresh any embedded widgets as these are often dependent on parameters passed from the parent widget. These can be manually refreshed afterward if needed. In addition to the red outline on the widgets and a display of their load times, this will add the name of the widget, a button to print the scope of the widget (see what data is loaded), and a button that will refresh the widget and update the load time after the refresh finishes. The widget name will be a clickable link to open the widget in the widget editor.


The world works with ServiceNow.

Sign in for more! There's more content available only to authenticated users Sign in for more!
Did this KB article help you?
Did this KB article help you?

Attachments

Attachments

  • KB0744521-01.jpg

How would you rate your Now Support digital experience?

*

Very unsatisfied

Unsatisfied

Neutral

Satisfied

Very satisfied

Very unsatisfied

Unsatisfied

Neutral

Satisfied

Very satisfied

What can we improve? Please select all that apply.

What are we doing well? Please select all that apply.

Tell us more

*

Do you expect a response from this feedback?

  • Terms and conditions
  • Privacy statement
  • GDPR
  • Cookie policy
  • © 2025 ServiceNow. All rights reserved.