How to show a private Grafana dashboard on a TV without a login screen
Grafana kiosk mode hides the menus but does not sign in for you, so a wallboard eventually shows a login page. Here are the four supported ways to display a non-public Grafana dashboard on a TV or Raspberry Pi with no login, when to use each, the exact settings, and how to keep the screen alive afterwards.
Updated 2026-09-08 · 12 minute read · Applies to Grafana 9.1 to 12, Grafana Cloud and self-hosted.
Why a Grafana wallboard ends up on the login page
A dashboard you open in your own browser works because your browser holds a Grafana session cookie. A TV, a Raspberry Pi or any kiosk browser has no such session, and even if someone logs in once on the device, Grafana sessions expire (30 days by default, sooner in many installs) and the screen drops back to Welcome to Grafana. Adding ?kiosk to the URL changes what is drawn, not who is allowed to see it.
The fix is always the same idea: give the screen a way to view the dashboard that does not depend on a person's session. Grafana offers four, and they differ in where they work, what they support and how much they expose.
Choose a method
| Method | Works on | Who sets it up | Login prompts | Best for | Caveat |
|---|---|---|---|---|---|
| Shared dashboard link | Grafana Cloud, OSS and Enterprise 9.1+ | Editor on the dashboard | Never asks for a login | Most teams. Safest option, no server config. | No template variables; the link works for anyone who has it. |
| Anonymous viewer org | Self-hosted OSS and Enterprise | Server admin (grafana.ini) | Never | Dashboards with variables, on a private network. | Not available on Grafana Cloud; counts as active users on Enterprise. |
| JWT URL login | Self-hosted OSS and Enterprise | Server admin (grafana.ini) | Until the token expires (you choose) | Private dashboards on the public internet with variables and full features. | Token lives in the URL; HTTPS is mandatory. |
| Auth proxy | Self-hosted, behind your own reverse proxy | Server admin and proxy admin | Never for allow-listed screens | Office networks where the screens have fixed IPs. | Grafana must only be reachable through the proxy. |
Rule of thumb: on Grafana Cloud use a shared link. Self-hosting on a private network, use anonymous access with a dedicated org. Self-hosting on the internet with template variables, use JWT URL login.
Method 1: share the dashboard with a link (Grafana Cloud and self-hosted)
Grafana calls this externally shared dashboards (Grafana 11 and newer) or public dashboards (Grafana 9.1 to 10). It produces a read-only URL that runs the dashboard's stored queries for anyone who has the link, with no login. It is the safest option because the screen holds no credential at all, and it is the only option on Grafana Cloud.
- Make a copy for the wall. Open the dashboard, choose Save as copy, and name it, for example,
NOC wall. Shared links do not support template variables, so in the copy replace each variable with the fixed value the wall should show. Remove panels that use frontend data sources or library panels; they render empty on a shared link. - Share it. Click the Share dropdown at the top of the dashboard and choose Share externally. On Grafana 10 the same option is the Public dashboard tab of the Share dialog.
- Choose who can open it. Select Anyone with the link, tick the acknowledgement checkbox and click Accept. The Only specific people option emails one-time links that expire; it is meant for humans, not screens.
- Set the options. Leave Enable time range off so the wall cannot be changed by whoever finds the link, and turn Display annotations on only if the wall should show them.
- Copy the link. It looks like
https://grafana.example.com/public-dashboards/8f2c…. Append?kiosk&refresh=30sfor a clean, self-refreshing view. - Later: Pause access stops the link temporarily and keeps the URL; Revoke access kills it for good and you must share again.
Method 2: an anonymous viewer organisation (self-hosted)
Anonymous access lets unauthenticated visitors view one organisation with a role you choose. It supports everything a normal viewer sees, including template variables, playlists and links between dashboards. It is a server setting in grafana.ini, so it is not available on Grafana Cloud, and on Grafana Enterprise anonymous devices count towards licensed users (one user per three devices).
- Create a dedicated org. Administration → Organizations → New org, for example
Wall. Anonymous visitors will see this org only, so never enable anonymous access on the org that holds everything. - Move or import the wall dashboards into that org, along with read-only data source connections. Export as JSON from the main org and import into
Wall; point the data sources at read-only credentials. - Enable anonymous access in
grafana.ini(or the matchingGF_AUTH_ANONYMOUS_*environment variables in Docker) and restart Grafana:
[auth.anonymous]
enabled = true
org_name = Wall
org_role = Viewer
hide_version = true
# optional: cap how many anonymous devices may connect
device_limit = 20 - Build the URL with the org id of
Wall:https://grafana.example.com/d/abc123/noc?orgId=2&kiosk&refresh=30s. Open it in a private browser window to confirm no login is asked. - Restrict who can reach Grafana if it is on the internet: an allow-list on your reverse proxy or firewall for the office and the screens, or keep Grafana on the private network and let the screens sit on that network.
Wall org is visible to any device that can reach the Grafana URL. Put only wall content in that org, use read-only data source users, and prefer Method 1 if the instance is reachable from the internet.Method 3: JWT URL login (self-hosted, private dashboards with full features)
Grafana can authenticate a request from a signed JSON Web Token, and with url_login the token may be passed as the auth_token query parameter. That is designed for exactly this case: a kiosk that cannot set headers. The screen becomes a real, named Viewer user, so variables, annotations, playlists and permissions all work, and nobody else can open the dashboard without the token.
- Create a signing key pair on your workstation. Grafana verifies tokens with the public key; the private key never leaves your machine.
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out jwt-private.pem
openssl rsa -in jwt-private.pem -pubout -out jwt-public.pem - Install the public key on the Grafana host, for example
/etc/grafana/jwt-public.pem, readable by the Grafana user. - Enable JWT auth in
grafana.iniand restart Grafana. Users are created on first sight with thesubclaim as their login, andexpect_claimsrejects tokens minted for anything else.
[auth.jwt]
enabled = true
header_name = X-JWT-Assertion
url_login = true
username_claim = sub
email_claim = email
key_file = /etc/grafana/jwt-public.pem
auto_sign_up = true
expect_claims = {"iss": "wall-displays"}
# role for auto-created users; Viewer is the default in most installs
# auto_assign_org_role = Viewer (in the [users] section) - Mint a token for a dedicated user, with the expiry you want the screen to keep working. One year is common for a wallboard; shorter if the dashboard is sensitive. This uses PyJWT (
pip install pyjwt cryptography):
import jwt, time
claims = {
"sub": "wall-noc-1",
"email": "wall-noc-1@example.com",
"iss": "wall-displays",
"iat": int(time.time()),
"exp": int(time.time()) + 365 * 24 * 3600,
}
print(jwt.encode(claims, open("jwt-private.pem").read(), algorithm="RS256")) - Give the new user access. Open the URL once with the token so Grafana creates the user, then in Administration → Users confirm it is a Viewer in the right org and add it to a team that can see the wall dashboards. Set
hide_versionstyle hardening as you would for any viewer. - Build the URL:
https://grafana.example.com/d/abc123/noc?orgId=1&kiosk&refresh=30s&auth_token=eyJhbGciOi…. Test it in a private window.
Method 4: auth proxy behind your own reverse proxy (self-hosted, private network)
With auth proxy, Grafana trusts a header such as X-WEBAUTH-USER set by a reverse proxy in front of it. If your screens have fixed addresses on the office network, the proxy can inject a viewer username for requests from those addresses only, and everyone else still logs in normally. Nothing is stored on the screen and no link can leak.
- Enable the auth proxy in
grafana.ini;whitelistmust be the proxy's address so a spoofed header from anywhere else is ignored:
[auth.proxy]
enabled = true
header_name = X-WEBAUTH-USER
header_property = username
auto_sign_up = true
whitelist = 10.0.0.5
enable_login_token = false - Configure the proxy. In Caddy, for example, match the screens' addresses and set the header; every other client gets Grafana's normal login:
grafana.example.com {
@screens remote_ip 10.0.20.0/24
reverse_proxy @screens grafana:3000 {
header_up X-WEBAUTH-USER wall-viewer
}
reverse_proxy grafana:3000
} - Make sure Grafana is reachable only through the proxy (bind it to localhost or a private interface). If Grafana's own port is exposed, anyone can send the header themselves.
- Create the viewer by opening the dashboard once from a screen's address, then assign it read-only permissions on the wall folder.
Kiosk URL parameters worth knowing
Whichever method you chose, the URL you give the screen should describe exactly what to show. Grafana reads these query parameters:
| Parameter | What it does |
|---|---|
kiosk | Hides the navigation and side menu. Use it bare, not kiosk=1. Older versions also had kiosk=tv, which newer versions no longer support. |
_dash.hideTimePicker=true | Hides the time and refresh picker in kiosk mode (Grafana 11.3 and newer). |
_dash.hideVariables=true | Hides the variable and annotation controls at the top of the dashboard. |
_dash.hideLinks=true | Hides dashboard links. |
refresh=30s | Auto-refreshes panels at that interval. Values must be one of the intervals allowed in the dashboard settings. |
from=now-6h&to=now | Time range. Relative values keep the window rolling; epoch milliseconds pin it. |
timezone=America/Vancouver | Time zone for the axes, independent of the server. |
theme=dark | Force dark or light regardless of the viewing user's preference. |
orgId=1 | Organisation id. Required when the dashboard is not in the default org (the anonymous and JWT methods often use a dedicated org). |
var-instance=web-01 | Sets a template variable. Not available on shared dashboard links. |
A complete wall URL for a shared dashboard: https://grafana.example.com/public-dashboards/8f2c…?kiosk&refresh=1m&from=now-24h&to=now&theme=dark. Rotate several dashboards with a Grafana playlist (/playlists/play/<uid>?kiosk) or, more simply, with a DisplayOps slideshow.
Put it on the screen and keep it there
A Raspberry Pi with a browser will show the URL once. What breaks wallboards over the following weeks is everything after that: Chromium's memory growth, a power blip, an HDMI handshake, a rebooted switch, an expired token nobody noticed. DisplayOps is a managed player for exactly this job. The steps below assume a supported Raspberry Pi and a free DisplayOps account.
- Flash and pair. Write the DisplayOps image to a microSD card, plug the Pi into the TV and the network, and enter the pairing code shown on screen in the portal under Displays → Pair. Wi-Fi can be set at flash time or later from the portal.
- Add the dashboard as content. Content → New → Website, paste the wall URL from the method above, and set a page reload interval of six to twelve hours. Grafana's own
refresh=keeps the panels current; the reload is what clears browser memory and picks up dashboard edits. - Assign it. Open the display (or a group of displays) and choose the content. The screen switches within seconds and shows the same URL again after any reboot or power cut, even before the network is back.
- Schedule, if useful. Show the NOC board during the day and a calmer status page at night, or push an incident message to every screen with one click and return to the dashboards afterwards.
- Watch it. The portal shows a screenshot on request, when the screen last checked in, and when the player restarted. If the page ever drifts to a login screen because a token expired, you see the redirect in the display's activity and fix the URL in one place for every screen that uses it.
Three screens are free on the Personal plan, which is enough for most NOCs and offices to start. The Grafana wallboard use case covers rotating dashboards and incident overrides in more detail.
Troubleshooting
- The login page appears after a while. A JWT or a manually created session expired, or a shared link was paused or revoked. Check the method's expiry or status, then update the content item; every screen using it updates at once.
- Panels are empty on a shared link. The dashboard uses template variables, a frontend data source or library panels. Bake the values into a copy of the dashboard and share the copy.
- "Dashboard not found" with anonymous access or JWT. The URL is missing
orgIdfor the dedicated org, or the viewer user is in the wrong org. Open the URL in a private window and read the address bar after Grafana redirects. - The menu still shows. Use
kioskwith no value.kiosk=1is ignored andkiosk=tvwas removed in newer versions. - Time picker or variables still visible in kiosk mode. Add
_dash.hideTimePicker=trueand_dash.hideVariables=true(Grafana 11.3 and newer). - The browser grows until it crashes. Set a periodic page reload in the content item; DisplayOps also restarts a player that stops responding.
- Text is too small on the TV. Use a dashboard designed for the screen's resolution, or set the display's browser zoom in DisplayOps rather than editing every panel.
Security checklist
- One dedicated org, user or link per wall, never a person's own login.
- Read-only data source credentials for anything anonymous viewers can reach.
- HTTPS everywhere; tokens in URLs are only acceptable over TLS.
- Expiry dates written down: JWT tokens and shared links should be reviewed when someone leaves the team.
- Grafana behind a proxy or firewall allow-list when it is on the internet, with the auth proxy's
whitelistset. - Content URLs kept in DisplayOps, not on sticky notes; the portal masks nothing on screen because the browser never shows the address bar.
Grafana on a TV: questions we get
Does Grafana kiosk mode log in by itself?
No. Kiosk mode only hides the menus. If the dashboard needs a session, the screen shows the Grafana login page as soon as the session expires. Every method in this guide removes the need for a session on the screen.
Which method should I use on Grafana Cloud?
Shared dashboard links. Anonymous access, JWT URL login and the auth proxy are server-side settings that Grafana Cloud does not let you change.
My shared dashboard shows empty panels.
Shared dashboards do not support template variables, frontend data sources, library panels or exemplars. Replace variables with fixed values in a copy of the dashboard made for the wall, then share that copy.
Is putting a token in the URL safe?
Over HTTPS the URL is encrypted in transit, and DisplayOps stores content URLs server-side and never shows them on screen. Use a dedicated Viewer user with an expiry you are comfortable with, and rotate the token when someone who knew it leaves.
How do I rotate between several dashboards?
Either a Grafana playlist opened with the kiosk parameter, or a DisplayOps slideshow with one website item per dashboard and a duration for each. The slideshow is easier to change from the portal and works across different tools.
Can DisplayOps log in to Grafana for me?
Not yet. Managed credentials, starting with HTTP basic auth and header injection for service-account tokens, are on the roadmap and are being built as a security feature with encrypted storage, not a convenience checkbox.
Related
Put the Grafana dashboard on the wall and forget about it.
Three screens free. Flash, pair, paste the URL.