Stream NetSuite KPIs to TV via Firestick Without
NetSuite licenses are tied to named users with email addresses and roles.

On this page
You have a 55-inch screen mounted above the packing station. Right now it shows last week's open-order count because someone has to log in, navigate to the dashboard, and hit refresh every time the shift changes. Buying a full NetSuite seat for a display that only reads data is a hard sell to finance. The workaround most teams settle for, a shared "kiosk" login, breaks audit trails and still burns a license. There's a cleaner path: token-based authentication that presents as a service, not a user, paired with a $40 Firestick that anyone can plug into HDMI and Wi-Fi.
Why Token Auth Sidesteps the Seat Count
NetSuite licenses are tied to named users with email addresses and roles. When you authenticate via Token-Based Authentication (TBA), the request carries a consumer key, consumer secret, token ID, and token secret, no interactive user session, no role assignment to a human, no seat consumption. The integration runs under an Integration Record you create at Setup > Integration > Manage Integrations > New. Give it a name like "TV Dashboard Service," leave the default Token-Based Authentication checkbox enabled, and save. NetSuite generates the consumer key and secret once; copy them immediately.
Important: As of the 2027.1 release, NetSuite will no longer allow new TBA integrations for RESTlets, REST web services, or SOAP web services. Existing TBA integrations continue to work, but new development should use OAuth 2.0. For a read-only dashboard Suitelet deployed today, TBA still functions; plan a migration to OAuth 2.0 before the cutoff.
Next, create the token at Setup > Users/Roles > Access Tokens > New. Select the integration you just made, assign a User (this can be a dedicated "dashboard_service" employee record with no role and no login access), and save. The token ID and secret appear once, store them in your secrets manager. The employee record exists only to satisfy the token's required user reference; it never logs in and never counts against your seat total. Because no licensed role is attached, the integration does not consume a user seat.
Building the Data Endpoint NetSuite Can Serve
The Firestick browser can't run SuiteScript. It needs a lightweight HTTP endpoint that returns JSON. A Suitelet deployed as Available Without Login does this cleanly. In the Suitelet's get handler, execute a saved search using N/search, transform the result set to an array of objects, and return response.write(JSON.stringify({ kpis: data })). Set the script's Log Level to Error only, you don't need execution logs cluttering the system for a read-only dashboard.
/**
* @NApiVersion 2.1
* @NScriptType Suitelet
*/
define(['N/search'], (search) => {
function get(context) {
const savedSearchId = context.request.parameters.searchid || 'customsearch_tv_kpi_open_orders';
const resultSet = search.load({ id: savedSearchId }).run();
const kpis = [];
resultSet.each((result) => {
kpis.push({
label: result.getValue({ name: 'custcol_kpi_label' }),
value: result.getValue({ name: 'custcol_kpi_value' }),
trend: result.getValue({ name: 'custcol_kpi_trend' })
});
return true;
});
context.response.write(JSON.stringify({ kpis, generatedAt: new Date().toISOString() }));
}
return { get };
});Deploy the script at Customization > Scripting > Scripts > New, select the file, set Status to Released, check Available Without Login, and set Audience to All Roles. Note the External URL, it will look like https://<account>.app.netsuite.com/app/site/hosting/scriptlet.nl?script=1234&deploy=1&compid=<account>&h=<hash>. That URL is what the Firestick hits.
When referencing saved search columns, use the field ID (e.g., custcol_kpi_label), not the UI label. Field IDs are permanent; labels can change. You can verify field IDs by opening the saved search in the UI and checking the URL or using the System Notes feature to track changes to custom fields.
Firestick Setup in Under Ten Minutes
On the Firestick home screen, search for "Silk Browser" (Amazon's built-in browser) or install Firefox from the Appstore, both support full-screen kiosk mode. Open the browser, navigate to your Suitelet URL, and verify the JSON renders. Then enable kiosk mode:
- Silk: Menu (three lines) > Settings > Advanced > Kiosk Mode > enter the URL > Start
- Firefox: Install the "Kiosk Browser" add-on, set the homepage to your URL, and launch
Plug the Firestick into the TV's HDMI port, power it via USB or the included adapter, connect to Wi-Fi, and the dashboard loads on boot. No keyboard, no mouse, no IT ticket. If the TV loses power, the Firestick restarts and relaunches the browser automatically.
What Data Can Actually Drive This
The Suitelet can execute any saved search you expose via the searchid parameter. Common warehouse KPIs:
| Saved Search Type | Typical Fields | Refresh Cadence |
|---|---|---|
| Open Sales Orders | tranid, entity, total, shipdate | 2 min |
| Backorder Count | item, quantitybackordered, preferredstocklevel | 5 min |
| Shipping Queue | custbody_carrier, custbody_tracking, shipdate | 1 min |
| Inventory Aging | item, location, quantityonhand, lastpurchasedate | 15 min |
Create each saved search under Reports > Saved Searches > New, set Public so the Suitelet can read it, and note the Script ID (e.g., customsearch_tv_kpi_open_orders). The Suitelet example above expects three custom columns, custcol_kpi_label, custcol_kpi_value, custcol_kpi_trend, but you can reshape the JSON to match whatever front-end you build (a simple HTML/JS page hosted on NetSuite's File Cabinet works fine).
Scheduling, Governance, and the Refresh Trap
A Suitelet runs on every HTTP request. If ten TVs poll every 30 seconds, that's 1,200 executions per hour. NetSuite enforces concurrency and governance limits on Suitelets; heavy saved searches with large result sets or complex joins can spike governance usage. Keep each search under 500 rows; use Summary Type: Count or Group By where possible. Add a result limit in the saved search Results tab if you only need top-N.
For heavier aggregations (daily revenue, rolling 30-day trends), run a Scheduled SuiteScript (Map/Reduce or N/task) once per hour that writes pre-computed KPIs to a Custom Record (customrecord_tv_kpi_snapshot). The Suitelet then reads that single record, near-zero governance, instant response.
Edge Cases That Break the Display
- Token rotation, TBA tokens don't expire automatically, but your security policy may require rotation every 90 days. Automate the swap: a scheduled script generates a new token via
N/auth, updates the secret in your vault, and the Suitelet picks it up on next invocation. - Account ID changes, Sandbox refreshes alter the
compidin the external URL. Parameterize the base URL in your front-end config so you only update one variable post-refresh. - Network segmentation, Warehouse Wi-Fi often blocks outbound HTTPS to unfamiliar domains. Whitelist
*.app.netsuite.comand*.netsuite.comon the VLAN firewall. - Time zone drift, The Suitelet returns
generatedAtin UTC. Convert to the viewer's local zone in the front-end (new Date(data.generatedAt).toLocaleTimeString()) so the "as of 2:13 PM" label matches the wall clock.
What to Check Next
If you're already running SuiteAnalytics Workbook dashboards, you can reuse those KPI definitions, export the underlying saved search IDs from the Workbook JSON (Setup > Analytics > Workbooks > Export) and feed them to the same Suitelet. For teams that want a hosted front-end without maintaining HTML files, a lightweight middleware service can connect to your TBA credentials, pick up saved searches by script ID, and serve a ready-to-bookmark URL, no Suitelet coding required.


