How to Add a Custom Image in the Icon Link Widget in ServiceNow’s Service Portal
- davidyang88
- Mar 21
- 11 min read
Updated: 11 hours ago

ServiceNow's Service Portal provides an Icon Link widget out-of-the-box for creating navigational links with icons. By default, this widget uses glyph icons (Font Awesome icons) and does not support custom images. In many cases, developers and ServiceNow administrators want to use company-specific icons or other custom graphics instead of the limited set of glyphs. This guide explains how to clone and customize the Icon Link widget to display uploaded images (stored in the Images [db_image] table) as icons. We maintain a technical focus, covering every step from preparation to implementation, and conclude with best practices and alternative solutions.
Overview
Adding custom images to the Icon Link widget is achievable by cloning the widget and enhancing its functionality. At a high level, the process involves:
Uploading the desired image into ServiceNow's Images (db_image) table.
Cloning the Icon Link widget to avoid altering the out-of-box version.
Modifying the widget's HTML template to include an <img> element that will show the custom image.
Updating the widget's server-side script to fetch the image from the database.
Defining new widget options (Option Schema) to allow selecting an image or switching between icon types.
Testing the changes in the Service Portal and applying best practices throughout.
By the end of this step-by-step guide, you will have a customized Icon Link widget that can display custom images (e.g. company logos or unique icons) in place of or in addition to the standard glyph icons.
Step-by-Step Guide
Step 1: Upload Your Custom Icon Image to the Images (db_image) Table
Before editing any widgets, ensure the custom icon graphic is available in your ServiceNow instance:
Prepare the image file you want to use as an icon (for example, a PNG or JPG of a logo or custom icon). Ideally, use a small, optimized image since it will be displayed as an icon.
In ServiceNow, navigate to System UI > Images (this module opens the Images [db_image] table). Alternatively, use the Filter Navigator and search for "Images".
Click New to create a new image record. In the form:
Provide a Name for the image. This will be used as the identifier (and later referenced in the widget code or options). For example, custom_icon.png.
Use the Image field to upload your image file (click the Add attachment paperclip icon and upload the file, then the Image field will reference the uploaded file).
(Optional) Fill other fields like Category or Application as needed. Save the record.
Verify that the image now appears in the list with the given name. Note: Images stored in this table can be served in Service Portal, and using the db_image table is preferable to storing images in a client-script or using external URLs, as it keeps the content self-contained.
Why this step? The Icon Link widget will retrieve the image from the db_image table by name or sys_id. ServiceNow stores these images as attachments under the hood, and by uploading here, we ensure the image is available for our widget to use.
Step 2: Clone the Out-of-Box Icon Link Widget
It is a best practice not to modify out-of-box (OOB) widgets directly, since your changes could be overwritten by future updates and will make upgrades more complex. Instead, clone the widget:
Navigate to Service Portal > Widgets or open the Widget Editor (for example, via any existing Icon Link widget instance in a page).
Find the widget named "Icon Link" (this is the OOB widget).
Click the Menu (⋮) icon for the widget record and choose Clone. Provide a new name for the cloned widget, for example, "Icon Link - Custom Image".
Open the cloned widget for editing. You should see its properties, including HTML Template, Server Script, Client Script (if any), CSS (if any), and Option Schema. Initially, these will mirror the original widget.
At this point, you have a separate copy of the Icon Link widget. Any changes you make next will not affect the original widget and can be packaged in an update set if needed.
Step 3: Modify the Widget's HTML Template to Add an Image Element
The HTML template controls what is rendered on the portal page for the widget. We will update it to support two modes: the original glyph icon mode and a new image mode. Specifically, we'll add an <img> tag that displays the custom image when the widget is configured to use one.
In the cloned widget record, click on the HTML Template field to edit it. You will see HTML markup similar to the original Icon Link widget.
Locate the section where the icon is rendered. In the default widget, this is typically structured with conditional blocks for different display templates (for example, a "Top Icon" or "Color Box" style). You might see an AngularJS ng-if tied to an option like options.link_template controlling whether to show a glyph icon.
Insert a new block of HTML for the custom image option. We can use a snippet like the following, which adds a new template option called "Image Icon":
In this code:
We added a new <a> block with ng-if="::(options.link_template == 'Image Icon')". This ensures that this block renders only when the widget's instance option link_template is set to "Image Icon".
Inside that block, an <img> tag is used to display the image. It binds to src="{{data.image}}", which will be provided by the server script (next step). We also included alt="Icon Image" (for accessibility) and some inline styles to ensure it displays nicely (centered and responsive via max-width).
We maintained the existing structure of a heading (<h4> for the title) and a description (<span> for the short description) so that the widget continues to show those details below the image. These use the same options.title and options.short_description provided by the widget's data.
The original glyph icon block is left unchanged (except we ensure it only shows when the template is not "Image Icon"). We used the condition || !options.link_template to treat the glyph icon as the default when the template option is not set.
Make sure to save the HTML template after making these changes. On the portal, if you toggle the widget's mode to "Image Icon", it will now render an <img> element in place of the Font Awesome <div> icon.
Step 4: Modify the Widget's Server Script to Retrieve the Image
Now that the template expects a data.image URL or path, we need to set that in the server script. The server script runs on the server side when the widget is instantiated, allowing us to look up the image and pass the needed info to the client (template).
In the widget editor, click on the Server Script field to edit the server-side logic. The default Icon Link server script likely populates data.href (the link target URL) and possibly handles the icon or other data.
We will add code to fetch the image from the Images (db_image) table. This can be done using a GlideRecord query for the image record. We will assume the widget will have an option to specify which image to use (for flexibility), rather than hard-coding an image name. For now, let's write the script assuming an option options.image will hold the sys_id of the selected image (we will define this option in the next step).
Below is an example server script with the necessary additions:
What this script does:
Uses $sp.getInstanceRecord() and $sp.getMenuHREF(gr) to get the link the widget should point to (this is default behavior for Icon Link – it figures out the URL if the widget is used in a menu context). It also sets data.target (e.g. self or blank) from the widget options.
Checks if options.image is provided (meaning an image has been selected for this instance). If so, it queries the db_image table for a record with sys_id == options.image.
If an image record is found, it sets data.image to the value of the Name field of that image (imgGR.getValue('name')). The Name typically includes the file extension (e.g. custom_icon.png). In ServiceNow's Service Portal, referencing the image by name is usually sufficient to retrieve it, because the platform knows how to serve images from the DB when referenced by name. Essentially, data.image will contain something like "custom_icon.png", and the <img> tag will source it.
Note: Another approach could be constructing a URL using the sys_id (for example, using sys_attachment.do or a Service Portal provided function). However, using the image name as we do here is straightforward and works since the image is stored in the system. Just ensure the name is unique to avoid confusion.
At this point, the widget has server logic to supply data.image when an image option is set. If no image is specified (e.g. the widget is set to use glyph mode or no image selected), data.image will remain undefined, and our template will simply not render an <img> tag (because of the ng-if conditions).
Step 5: Define the Widget Option Schema for Image Selection
To make our widget truly configurable, we need to provide instance options for the administrator to choose the icon type and the image. This is done through the Option Schema of the widget, which defines what options (fields) are available when someone instantiates the widget on a page.
In the widget editor, find the Option Schema section (in the Platform UI, there's usually an "Option schema" related list or a JSON definition area; in the Service Portal Widget Editor, there's an "Edit Option Schema" button in the menu).
We need to add (or modify) two options:
Link Template (link_template) – a choice that now includes our new option "Image Icon" in addition to the original choices.
Image (image) – a reference field that allows selecting an image from the Images table.
If the original Icon Link widget already had a link_template option with choices (like "Glyph Icon", "Color Box", etc.), edit that option to add "Image Icon" as another choice. If not, you can create it as a new choice field. Ensure the default remains "Glyph Icon" (or whatever the original default was) so existing behavior isn't altered unless specifically changed.
Next, add a new option for the image:
Display name: "Image" (or "Custom Image")
Name: image
Type: Reference
Reference Table: Images (this is the human-friendly name; in technical terms it’s the db_image table).
Optionally, you can provide a default or hint. Typically, default can be blank (meaning no image selected).
For example, in JSON format, the Option Schema might look like:
(The above is a simplified representation. ServiceNow's actual storage of the option schema might be an array of objects or similar structure. The key is that we include the new "Image" reference and the extended choices for "link_template.")
Save the option schema changes. Now, when you place this widget on a Service Portal page and open its instance options, you will see:
An option (dropdown) to select Icon Type (or whatever label you gave link_template), where you can choose "Glyph Icon" or "Image Icon" (and any other templates originally present like "Color Box").
If "Image Icon" is selected, you can then pick an image in the Image field (which opens a reference picker to the Images [db_image] table and shows the available images, including the one you uploaded in Step 1).
Step 6: Test the Customized Widget
With all configurations in place (HTML template, server script, and options), it's time to test:
Navigate to a Service Portal page (for example, a new test page) and add your cloned Icon Link - Custom Image widget to the page.
In the widget instance options panel, configure the widget:
Set the Title and Short Description as needed (same as you would for a normal Icon Link widget).
For Icon Type/Template (link_template), choose Image Icon.
In the Image option, use the reference picker to select the image you uploaded (e.g. custom_icon.png). If the reference is set up correctly, you should see the name of your image available.
Set the Link or other URL/target options as needed (depending on how the widget is meant to link to something).
Save the instance options and refresh the page (if it doesn't refresh automatically). You should now see your Icon Link widget displaying the uploaded image instead of a glyph icon. The title and description text should appear below the image, and clicking the image (or the whole widget area) should navigate to the configured URL.
Test both modes: Try switching the Icon Type back to "Glyph Icon", selecting one of the standard glyphs (Font Awesome icon name via the glyph option), and verify that still works. Then switch again to "Image Icon" to ensure your image returns. Also verify the link works (and opens in new tab or same window as per target option).
If the image does not display:
Double-check that data.image is being set. One simple debug step is to temporarily add console.log(data.image) in the server script (and use the browser console in the portal) or use the "Instance Options" > "Test" functionality to see data.
Ensure the image name in the db_image record is unique and that the options.image actually holds a sys_id (if the reference isn't working, options.image might be undefined).
If using a name instead of sys_id, you might adapt the server script to query by name field (e.g., imgGR.addQuery('name', 'your_image_name.png')). However, using the reference (sys_id) is cleaner for multiple instances.
Alternative Approach
The method above is the most direct approach to achieve custom images in the Icon Link widget while leveraging ServiceNow's framework. However, there are alternative methods and considerations:
Using CSS Background Images: In some cases, if all you need is to replace the icon visually and you don't require different images per widget instance, you could use CSS to set a background-image on the icon element. For example, you could add a CSS snippet to the page or widget that targets a specific Icon Link widget's container by ID or class and apply background-image: url('your_image_url') to it, hiding the original glyph. This approach can work for a one-off change (as suggested by some community members), but it is less flexible and maintainable than the widget option method. It also doesn't allow different images for different links without additional CSS for each, which quickly becomes unwieldy.
Creating a New Widget from Scratch: If the Icon Link widget is too limited or if you want more control, you could build a simple widget from scratch that displays an image and a link. Essentially, this means not using Icon Link at all, but rather a custom widget where the options might be the image and the URL. This can be faster if you don't need the additional features of Icon Link (like the color box style or the integrated link handling). However, you would be re-implementing some features that Icon Link already provides (like the logic for building the href to point to pages or external URLs).
Each alternative has trade-offs. The cloning method we detailed is advantageous because it retains all original functionality of Icon Link (link target handling, title/description display, etc.) and simply extends it, which is ideal for most situations. It also keeps the solution within the supported framework of ServiceNow (no hacks or unsupported tricks).
Best Practices and Recommendations
When implementing customizations like this, keep the following best practices in mind:
Do Not Edit OOB Widgets Directly: Always clone OOB widgets before modifying. This avoids impact on other areas of the system and preserves the original widget for reference. It also protects your customizations from being overwritten during upgrades.
Use Clear Naming Conventions: Name your cloned widget clearly (e.g., including "Custom" or your company prefix) to distinguish it from the original. This helps administrators identify custom components.
Leverage Instance Options (Option Schema): Rather than hardcoding values (like a specific image name or URL) in the widget, use instance options to make the widget reusable. In our solution, we added an Image option so each instance of the widget can use a different image. This makes the widget flexible and user-friendly for catalog managers or content admins who might configure portal pages.
Maintain Security and Accessibility: Images in the db_image table typically bypass normal ACLs so they can be visible on portals. Nonetheless, ensure that the images you use are meant to be public (or at least available to your user base). Also add alt text to images for accessibility, as shown in the HTML snippet.
Optimize Images: Since these images will load on portal pages, optimize them for web use (small file size, appropriate dimensions). High-resolution images can slow down page load times.
Test in a Sub-production Instance: As with any development, test your widget in a dev or test environment. Try different scenarios: no image selected, image selected, different browsers, etc., to ensure it works consistently.
Documentation: Document the existence of this custom widget in your internal developer docs or wiki. Future developers or admins should know that a cloned widget exists for custom icons, to avoid duplicating effort or confusing it with OOB functionality.
By following these practices, you'll create a robust solution that is easier to maintain over time.
Conclusion
In this article, we demonstrated how to transform ServiceNow's Icon Link widget to support custom images as icons. Starting with uploading an image to the platform and ending with a fully functional widget, we covered cloning the widget, updating its template and server script, and extending its option schema. The result is a more versatile Icon Link widget that can display any image you choose, enabling richer visuals on your Service Portal homepage or dashboards.
This enhancement is particularly useful for branding purposes (using company logos or product icons) and for situations where Font Awesome glyphs don't provide the desired imagery. By leveraging ServiceNow's built-in tables (like db_image) and keeping the customization within the platform's framework, we ensure the solution remains maintainable and upgrade-safe.
With the custom Icon Link widget in place, you can now create portal links with personalized icons, improving the user experience and visual appeal of your Service Portal. As ServiceNow and its community continue to evolve, keep an eye on new features—future versions might offer native support for custom images in widgets. Until then, the approach outlined here is a reliable way to achieve the functionality.