Suite Utils
Back to Blog
NetSuite TipsAug 14, 2026 • 6 min read

NetSuite Saved Search Role Access Checker Guide

A saved search that works as administrator returns nothing for a restricted role. Here is how to find which permission the role is missing.

Ethan James MarshalEthan James MarshalSenior SuiteScript Architect & Lead NetSuite Engineer
NetSuite Saved Search Role Access Checker Guide
On this page

The Problem: Saved Searches That Die by Role

You've built a saved search that works perfectly under your admin login. Then a user in a restricted role opens it, and either the search doesn't appear in their list, or it runs and returns zero rows, or it throws a "You do not have permission to view this search" error. The frustrating part is that NetSuite rarely tells you which permission is missing. It just fails.

NetSuite's built-in Show Permission Differences Between Roles tool compares two roles side by side. Go to Setup > Users/Roles > Show Role Differences to open that page. It helps you spot role-to-role gaps, but it doesn't tell you whether a specific saved search can actually run under a given role. The Audience subtab on the saved search controls who sees it in search lists, but it does nothing about whether the underlying record-type permissions let the search execute.

The real fix is to check two layers at once: the saved search's audience settings and the role's record-type permissions. That's exactly what a custom Suitelet can automate.

Before writing any code, understand the three independent gates a saved search must pass for a user to run it:

  1. Audience. Open the saved search and go to the Audience subtab. If the Public box is unchecked, the user must be listed as an audience member by name, role, department, subsidiary, or group. Administrators bypass this gate entirely.

  2. Record-type permission. The role needs at least Read level on the search's record type. A saved search on salesorder will not run for a role that lacks the Sales Order permission, even if that role appears in the audience.

  3. Search permission. The role needs the Perform Search permission, plus the record-specific search permission where one exists (for example, Employee Search for employee searches).

The gotcha here is that the audience subtab and the role permissions are configured in two different places, and nothing in the UI cross-references them. A saved search can be public, yet still fail for a role that lacks the record-type permission.

Building the Role Validator Suitelet

The community solution that surfaced for this exact problem is a Suitelet that takes a saved search internal ID and a role's XML definition, then reports which permissions are missing. You can roll your own in SuiteScript 2.1. The approach is straightforward:

  • Load the saved search record by internal ID.
  • Extract its search type (for example, vendorbill, itemfulfillment, salesorder).
  • Parse the role XML to check the relevant <permission> entries.
  • Compare and report gaps per role.

Here is a clean, copy-pasteable Suitelet skeleton that loads a saved search and reads its record type:

/**
 * @NApiVersion 2.1
 * @NScriptType Suitelet
 */
define(['N/record', 'N/ui/serverWidget', 'N/log'], (record, serverWidget, log) => {

    const onRequest = (context) => {
        const params = context.request.parameters;
        const searchId = params.searchid;

        if (!searchId) {
            const form = serverWidget.createForm({
                title: 'Saved Search Role Validator'
            });
            form.addField({
                id: 'custpage_searchid',
                type: serverWidget.FieldType.TEXT,
                label: 'Saved Search Internal ID'
            });
            form.addField({
                id: 'custpage_rolexml',
                type: serverWidget.FieldType.TEXTAREA,
                label: 'Role XML'
            });
            form.addSubmitButton({ label: 'Validate' });
            context.response.writePage(form);
            return;
        }

        const searchRec = record.load({
            type: record.Type.SAVED_SEARCH,
            id: searchId
        });

        const searchType = searchRec.getValue({ fieldId: 'searchtype' });
        log.debug({ title: 'Search Type', details: searchType });

        // Parse the role XML here, compare permissions,
        // and write the per-role report.
        context.response.write(`Search type: ${searchType}`);
    };

    return { onRequest };
});

The searchtype field on the saved search record returns the internal ID of the record type the search runs against. That value maps directly to the permission names you need to verify in the role XML. For example, itemfulfillment maps to the Item Fulfillment permission, and vendorbill maps to Vendor Bill.

Parsing the Role XML

NetSuite lets you download a role's definition as XML from Setup > Users/Roles > Manage Roles > Edit on a role, then Actions > Download XML. The XML contains a <permissions> block with entries like:

<permission>
    <name>ITEM_FULFILLMENT</name>
    <level>2</level>
</permission>

The <level> value is a number where 2 typically represents Read access. Your validator should check that the role's XML contains the permission name matching the saved search's searchtype, and that its level is at least the read threshold.

You can combine the XML exports from multiple roles into one file. The validator then iterates each <role> block, checks the permissions, and produces a per-role report. This is what saves you from clicking through 20 roles in the built-in comparison tool.

The Gotchas That Will Bite You

Permission names don't always match record type IDs. Most do, but custom record types use their script ID (for example, customrecord_my_thing) and some permissions have non-obvious names. Don't hardcode a mapping table unless you verify each one against your account.

Audience membership is separate from permissions. Your validator checks record-type access, but it won't catch a role that simply isn't listed on the Audience subtab. Handle that check separately, or include the audience fields in the comparison logic.

Suitelet governance is 1,000 units per execution. Loading one saved search record costs 10 units, and parsing XML in memory costs nothing extra. Even checking 20 roles in one run stays well under the limit. You don't need a scheduled script for this.

Administrators bypass every gate. If a search "works" under your login but fails for a regular user, the problem is almost always role permissions, not the search definition. That's the scenario this validator is built for.

When the Tool Isn't the Answer

A validator tells you what is missing, but it won't tell you whether the missing permission is intentional. Before you grant Item Fulfillment access to a role just to make a saved search run, ask whether that role should see fulfillment records at all. Sometimes the correct fix is to restrict the search's audience, not to widen the role. The tool helps you make that call with facts instead of guesswork.

If you're managing a large role matrix and need to audit which saved searches are exposed to which roles, a tool like this cuts the manual review from hours to minutes. Run the validator, fix the genuine gaps, and leave the intentional restrictions alone.

About the author

Put these ideas to work.

Suite Utils builds small NetSuite tools that fix the specific thing breaking your day. Each one runs as a native SuiteScript SuiteApp inside your account. No sales call, no onboarding.

Browse the Tools

Enjoyed this one?

Get NetSuite tips like this in your inbox. No spam. Practical guides only.

Keep reading