The portal page took 7.2 seconds to first paint and the widget audit revealed three widgets each making four GlideAjax calls on render. The fix was not adding more compute — it was rewriting the widgets to populate server.data once instead of fanning out to call the same endpoints from the client. Service Portal widget patterns reward exactly the discipline that makes any frontend code fast: do less work, do it once, do it on the right side.
Widget Anatomy
A widget consists of HTML, CSS, a client script, a server script, and configurable options. The server script runs on the instance during page render and returns data via the data object. The client script (AngularJS) binds the returned data to the template. Keep the server script lean — the bigger it is, the slower the page load, because every widget on the page contributes to render time before the user sees anything.
// Server script: minimal, focused
(function() {
data.items = [];
var gr = new GlideRecord('sc_request');
gr.addQuery('opened_by', gs.getUserID());
gr.addQuery('active', true);
gr.setLimit(20);
gr.query();
while (gr.next()) {
data.items.push({
number: gr.number+'',
short_description: gr.short_description+''
});
}
})();
Data Calls: server.data vs GlideAjax
For page-load data, populate server.data in the server script. The platform serializes the data into the page on render — one round trip, no client-side waiting. For user-triggered calls (form submission, refresh button, dynamic loading), use GlideAjax to call a server endpoint asynchronously. Do not try to load everything on render via GlideAjax — it produces a render-then-wait UX that feels slow even when the underlying data is small.
Reuse Widgets
If a widget is called from three or more pages, it is reusable and should be a single widget instance with parameters. Parameterize via the widget options, document the options in the widget description so the next maintainer knows what to pass, and resist the urge to copy-paste a slightly-modified copy. One widget, multiple placements with different option values, beats four near-duplicate widgets that drift over time.
Responsive CSS Without Pain
Bootstrap 3 is the portal’s underlying framework. Use its grid and utility classes for layout — they are tested across breakpoints and survive upgrades. Custom CSS goes in the widget’s own CSS field, not instance-wide stylesheets that override Bootstrap unpredictably. Theme variables via the Service Portal branding editor; hardcoded color values fight the theme and break in dark mode and high-contrast accessibility modes.
Layout pattern (Bootstrap 3):
<div class="row">
<div class="col-md-8">main content</div>
<div class="col-md-4">sidebar</div>
</div>
Mobile collapses to single-column automatically.
Upgrade Safety
Out-of-box widgets get patched in family upgrades. Custom widgets do not — they sit on the version you wrote. When you override an OOB widget by cloning, document why in the clone’s description and diff against the latest OOB version after each family upgrade to absorb relevant fixes. Override-by-cloning silently accumulates bug fixes nobody backports; track the divergence intentionally.
Common Failure Modes
Widget that queries inside a loop on the server script — the N+1 GlideRecord anti-pattern lands here too; collect IDs and batch lookup. Widget that loads images directly from external URLs — fails offline, leaks the page load to a third party; mirror images via the platform’s image storage. Widget options renamed without updating placements — placements still reference the old option name and silently get undefined; document option changes as breaking when shared widgets revise.
What Changed in 2026
Next Experience and UI Builder are the strategic frontend path. Service Portal continues to receive bug fixes but new portal-style work increasingly targets UI Builder. Existing Service Portal investment remains supported; net-new portal projects should evaluate UI Builder first. The decision is not urgent; the direction is clear.
Cost Considerations
Render time on the portal is your customer experience. A 4-second portal that nobody uses is a worse business outcome than a 1.5-second portal with fewer features. Budget render time before adding widgets and audit periodically. Use the browser’s network tab to measure first paint and time-to-interactive on representative pages; numbers above 3 seconds need investigation, above 5 seconds need a redesign.
Implementation Sequence
Profile the existing portal first — identify the slowest pages and the widgets contributing most to render time. Optimize those widgets (server.data instead of GlideAjax, batch queries, lazy-load below-fold content). Add new widgets only after the existing ones meet the performance budget. New widgets that follow the patterns inherit the speed; widgets retrofitted from copy-paste of legacy ones inherit the problems.
What to do this week: pull the load times for your top three Service Portal pages from browser real-user metrics or synthetic monitoring; pages above 3 seconds are your optimization queue.