Raspberry Pi Kiosk Tutorial — Boot Any Web Page Fullscreen
A no-frills guide to turning a Raspberry Pi into a fullscreen browser kiosk that loads a web page on boot. Works with any URL — local or remote.
Why so many “Pi kiosk” guides go sideways
Every week someone on r/raspberry_pi asks how to make their Pi boot straight into a fullscreen web page on an HDMI display. The usual answers either assume you have a desktop environment (so the cursor sits there forever, the screen blanks, Chromium nags about restoring sessions, the keyboard never appears on touchscreens) or they wire up Wayland/Cage in ways that fight the GPU on the Pi 5.
This post is the short, opinionated version that actually works on Raspberry Pi OS Lite with no desktop environment installed. It loads any URL you give it. If you later want to use the Pi to display IoT dashboards or workflow visualizations, see the companion post that uses this same technique to display Krill Server SVG dashboards.
The hard rules (do not skip these)
- Use Raspberry Pi OS Lite — no desktop. A desktop environment brings a cursor, screen blanking, notifications, and a session manager that all fight you. Flash Lite from the Pi Imager.
- Use X11, not Wayland. Xorg’s
-nocursorflag completely disables the mouse pointer at the server level. Every “hide the cursor” hack on Wayland (unclutter, transparent themes, etc.) is unreliable. - Run as a dedicated unprivileged user, not
pi. This keeps the kiosk session isolated and lets you SSH in as your normal user without disturbing the display. - Disable screen blanking and DPMS at the X server level every boot —
xset s off,xset s noblank,xset -dpms. The “raspi-config” toggle is not enough. - For touchscreens, install
onboardand pre-seed it withdconfso it auto-shows on text input without a desktop session manager.
What you need
- Raspberry Pi 4 or 5 (Pi 5 strongly recommended for Chromium)
- HDMI display (touchscreen optional)
- A fresh install of Raspberry Pi OS Lite (64-bit)
- A URL you want to display — anything reachable from the Pi
Step 1 — Install the bare minimum
After flashing Lite and SSHing in:
1
2
3
4
sudo apt update
sudo apt install -y \
xserver-xorg xserver-xorg-input-libinput xinit x11-xserver-utils \
chromium fonts-liberation ca-certificates
For touchscreens, also install the on-screen keyboard:
1
sudo apt install -y onboard dconf-cli at-spi2-core
Step 2 — Create a kiosk user
1
sudo useradd -m -s /bin/bash -G video,audio,input,render,tty kiosk
Step 3 — Allow non-root X
1
2
3
4
sudo tee /etc/X11/Xwrapper.config >/dev/null <<'EOF'
allowed_users=anybody
needs_root_rights=yes
EOF
Step 4 — (Pi 5 only) tell Xorg which GPU card to use
The Pi 5 exposes two DRM cards: card0 (vc4 display controller) and card1 (v3d 3D renderer). Xorg gets confused and fails with “Cannot run in framebuffer mode” unless you point it at the display card explicitly:
1
2
3
4
5
6
7
8
sudo mkdir -p /etc/X11/xorg.conf.d
sudo tee /etc/X11/xorg.conf.d/99-kiosk.conf >/dev/null <<'EOF'
Section "Device"
Identifier "Pi5 Display"
Driver "modesetting"
Option "kmsdev" "/dev/dri/card0"
EndSection
EOF
If card0 isn’t the vc4 card on your unit, find the right one with:
1
2
3
for c in /sys/class/drm/card*; do
grep -l "DRIVER=vc4-drm" "$c/device/uevent" 2>/dev/null
done
Step 5 — The kiosk launch script
Drop this at /home/kiosk/kiosk.sh (replace KIOSK_URL with your page):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#!/bin/bash
KIOSK_URL="https://example.com"
# Wait until the URL responds (handy if it's a service on the same Pi)
for i in {1..30}; do
curl -sk "$KIOSK_URL" >/dev/null 2>&1 && break
sleep 1
done
# Kill screen blanking and power management
xset s off
xset s noblank
xset -dpms
# (touchscreen only) start the on-screen keyboard
if command -v onboard >/dev/null; then
dconf write /org/gnome/desktop/a11y/applications/screen-keyboard-enabled true 2>/dev/null || true
onboard &
fi
exec chromium \
--kiosk \
--noerrdialogs \
--disable-infobars \
--disable-session-crashed-bubble \
--disable-translate \
--no-first-run \
--disable-pinch \
--overscroll-history-navigation=0 \
--autoplay-policy=no-user-gesture-required \
--start-fullscreen \
--password-store=basic \
--disable-component-update \
--check-for-update-interval=31536000 \
"$KIOSK_URL"
1
2
sudo chown kiosk:kiosk /home/kiosk/kiosk.sh
sudo chmod +x /home/kiosk/kiosk.sh
Step 6 — The launcher (starts X with no cursor)
This is the magic line. -nocursor tells the X server to never render a pointer at all — the only reliable way to hide it.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
sudo tee /usr/local/bin/kiosk-launcher >/dev/null <<'EOF'
#!/bin/bash
KIOSK_USER="kiosk"
KIOSK_UID=$(id -u "$KIOSK_USER")
mkdir -p "/run/user/$KIOSK_UID"
chown "$KIOSK_USER:$KIOSK_USER" "/run/user/$KIOSK_UID"
chmod 700 "/run/user/$KIOSK_UID"
chvt 7
exec su - "$KIOSK_USER" -c "
export XDG_RUNTIME_DIR=/run/user/$KIOSK_UID
exec xinit /home/$KIOSK_USER/kiosk.sh -- :0 vt7 -nocursor -nolisten tcp
"
EOF
sudo chmod +x /usr/local/bin/kiosk-launcher
Step 7 — Run it on boot with systemd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
sudo tee /etc/systemd/system/kiosk.service >/dev/null <<'EOF'
[Unit]
Description=Raspberry Pi Kiosk (X11)
After=network-online.target
Wants=network-online.target
ConditionPathExists=/dev/dri/card0
[Service]
Type=simple
ExecStartPre=/bin/sleep 3
ExecStart=/usr/local/bin/kiosk-launcher
TTYPath=/dev/tty7
TTYReset=yes
TTYVHangup=yes
TTYVTDisallocate=yes
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable kiosk.service
sudo systemctl start kiosk.service
Reboot. The Pi should boot straight into your URL, no cursor, no UI chrome, no desktop.
“But what page should I show?”
If you don’t already have something to display, here are dirt-simple ways to host a page on the Pi itself so the kiosk just loads http://localhost:
Option A — A static HTML file with Python
1
2
3
mkdir -p ~/site && cd ~/site
echo '<h1 style="font:10vw sans-serif">Hello kiosk</h1>' > index.html
python3 -m http.server 80
Set KIOSK_URL="http://localhost" in kiosk.sh. Wrap the python3 line in its own systemd service if you want it to survive reboot.
Option B — Nginx serving a folder
1
2
3
sudo apt install -y nginx
sudo rm /var/www/html/index.nginx-debian.html
echo '<h1>It works</h1>' | sudo tee /var/www/html/index.html
Option C — A Grafana / Home Assistant / Node-RED / etc. dashboard
Point KIOSK_URL at whatever service you already run (http://localhost:3000, http://homeassistant.local:8123/lovelace/0?kiosk, etc.). Most dashboards have a ?kiosk URL parameter that strips their own chrome — combine that with this guide and you get a true fullscreen display.
Going further — IoT and workflow dashboards
If you want to display real-time sensor data, GPIO state, automations, or custom SVG diagrams that update live (think factory-floor mimic boards, water systems, lab experiments), the same kiosk technique above is exactly what powers the Krill Server kiosk mode. The Krill installer bundles all of the steps in this post into a single krill_kiosk_install.sh script, plus certificate trust, an authenticated WebAssembly client, and a binding system that lets you wire SVG shapes to live data with a tag like id="k_pin22".
If that sounds useful, read the companion post: Turn a Raspberry Pi Into a Kiosk With Custom SVG Dashboards.
Troubleshooting
| Symptom | Fix |
|---|---|
| Cursor still visible | You forgot -nocursor on the xinit line, or you’re on Wayland. |
| Screen blanks after 10 min | xset calls didn’t run — make sure they’re in the script that xinit launches, not in .bashrc. |
| Xorg fails on Pi 5 | Add the 99-kiosk.conf from Step 4 pointing at the vc4 card. |
| Chromium “restore session” bubble | The --disable-session-crashed-bubble and --no-first-run flags handle it; if it persists, delete ~/.config/chromium. |
| On-screen keyboard never appears | Make sure at-spi2-core is installed and the dconf write line ran. The keyboard only auto-shows when the page focuses a real <input>. |
| Page loads before service is ready | The for i in {1..30} curl loop in kiosk.sh waits for it. Tune the loop count if your service is slow to start. |
Uninstall
1
2
3
4
5
sudo systemctl disable --now kiosk.service
sudo rm /etc/systemd/system/kiosk.service /usr/local/bin/kiosk-launcher
sudo rm /etc/X11/Xwrapper.config /etc/X11/xorg.conf.d/99-kiosk.conf
sudo userdel -r kiosk
sudo apt remove --purge -y chromium xserver-xorg xinit onboard
Last verified: 2026-04-14