# Raspberry Pi - Kiosk

## Configure kiosk mode

<p class="callout info">Checked 7 Oct 2026 against Raspberry Pi OS 2026-10-06 (Debian 13 "Trixie"). Since the 2024-10-22 release, every Raspberry Pi model runs a **Wayland** desktop with the **labwc** compositor by default, and the Chromium package/command is now `chromium` (it used to be `chromium-browser`). The old X11 tools (`xset`, `xdotool`, `unclutter`, `DISPLAY=:0`) do not work on a default install. The old method is kept at the bottom under "Older Raspberry Pi OS (Bullseye / X11)".</p>

Raspberry Pi OS no longer has a default `pi` user (removed in April 2022). Use the username you set in Raspberry Pi Imager and work in that user's home directory (`~`).

### 1. Base setup

Flash **Raspberry Pi OS (64-bit)** with Raspberry Pi Imager. In OS customisation set the hostname, username/password and Wi-Fi, and turn on SSH. Kiosk mode needs a Raspberry Pi 3 or newer with at least 1 GB RAM.

Change hostname if not already done

```bash
sudo hostnamectl set-hostname <new-hostname>
sudo reboot
```

Update the system

```bash
sudo apt update
sudo apt -y full-upgrade
```

### 2. Boot to the desktop with auto login (labwc)

```bash
sudo raspi-config
```

- `1 System Options > S5 Boot` → `B2 Desktop`
- `1 System Options > S6 Auto Login` → answer **Yes** to "automatically log in to the desktop"
- `6 Advanced Options > A7 Wayland` → `W2 Labwc` (already the default; older Bookworm images on Pi 4/5 used Wayfire, so switch them to labwc)

### 3. Turn off screen blanking

In `sudo raspi-config`: `2 Display Options > D2 Screen Blanking` → **No**. (Desktop alternative: Control Centre &gt; Display &gt; turn **Screen Blanking** off.)

### 4. Install wtype (only needed to rotate tabs)

`wtype` is the Wayland replacement for `xdotool`. It simulates the Ctrl+Tab keypress.

```bash
sudo apt -y install wtype
```

### 5. Clear Chromium cache (optional)

```bash
rm -rf ~/.cache/chromium ~/.config/chromium
```

### 6. Start Chromium in kiosk mode from the labwc autostart file

```bash
mkdir -p ~/.config/labwc
nano ~/.config/labwc/autostart
```

Add these two lines (replace the URLs; use one URL and drop the second line if you don't need to rotate tabs)

```shell
chromium https://YOUR-URL-1 https://YOUR-URL-2 --kiosk --noerrdialogs --disable-infobars --no-first-run --enable-features=OverlayScrollbar --start-maximized &
~/switchtab.sh
```

The `&` at the end of the first line is required so the tab-switch script also runs. Flags: `--noerrdialogs` hides error dialogs, `--disable-infobars` hides info bars, `--no-first-run` skips the first-run screens, `--enable-features=OverlayScrollbar` uses overlay scrollbars, `--start-maximized` starts full screen.

### 7. Tab switch script (only for 2+ URLs)

```bash
nano ~/switchtab.sh
```

Paste the following in

```shell
#!/bin/bash
# Find Chromium browser process ID
chromium_pid=$(pgrep chromium | head -1)
# Check if Chromium is running
while [[ -z $chromium_pid ]]; do
  echo "Chromium browser is not running yet."
  sleep 5
  chromium_pid=$(pgrep chromium | head -1)
done
echo "Chromium browser process ID: $chromium_pid"
# Loop to send keyboard events
while true; do
  # Send Ctrl+Tab using `wtype` command
  wtype -M ctrl -P Tab -p Tab
  sleep 10
done
```

Make it executable (no sudo / 777 needed)

```bash
chmod +x ~/switchtab.sh
```

### Firefox instead of Chromium (optional)

Use this as the first line of `~/.config/labwc/autostart` instead of the Chromium line. If you also use `switchtab.sh`, change both `pgrep chromium` to `pgrep firefox`.

```shell
firefox --kiosk --private-window https://YOUR-URL &
```

### 8. Reboot

```bash
sudo reboot
```

The Pi should log in, start labwc and open the browser full screen. No systemd service is needed. The labwc autostart file replaces the old `kiosk.service`.

### Mouse cursor

`unclutter` is X11-only and does nothing under labwc/Wayland. Run the kiosk without a mouse attached; plug one in only to dismiss cookie pop-ups, then unplug it. labwc 0.8.4 and newer (Trixie) also has a `HideCursor` action you can bind to a key in `~/.config/labwc/rc.xml`; the cursor comes back when the pointer moves (see [labwc-actions(5)](https://labwc.github.io/labwc-actions.5.html)).

### Hardening (optional)

- Use SSH keys and set `PasswordAuthentication no` in `/etc/ssh/sshd_config`.
- Make the SD card read-only: `sudo raspi-config` → `4 Performance Options > P2 Overlay File System` → Yes. Turn it off again before making changes or running updates.
- Put the Pi in a case that blocks access to the USB ports.

### Sources

- [Raspberry Pi tutorial: How to use a Raspberry Pi in kiosk mode](https://www.raspberrypi.com/tutorials/how-to-use-a-raspberry-pi-in-kiosk-mode/)
- [Raspberry Pi OS release notes](https://downloads.raspberrypi.com/raspios_arm64/release_notes.txt) (labwc default 2024-10-22, chromium-browser renamed to chromium, Trixie 2025-10-01)
- [Raspberry Pi documentation: Configuration](https://www.raspberrypi.com/documentation/computers/configuration.html) (screen blanking, boot to desktop, auto login, Wayland/labwc, overlay file system)
- [Firefox kiosk mode (Mozilla)](https://firefox-source-docs.mozilla.org/browser/components/enterprisepolicies/docs/index.html)

### Other community kiosk projects

[https://reelyactive.github.io/diy/pi-kiosk/](https://reelyactive.github.io/diy/pi-kiosk/)

[https://github.com/debloper/piosk](https://github.com/debloper/piosk)

## Older Raspberry Pi OS (Bullseye / X11)

<p class="callout warning">Legacy method. Only use it on Bullseye or older, or on a Pi switched to X11 (`raspi-config > 6 Advanced Options > A7 Wayland > W1 X11`, not recommended by Raspberry Pi). It depends on X11 tools and on the old `chromium-browser` command and `pi` user, so it does not work on a default Trixie or current Bookworm install.</p>

Install the following

```shell
sudo apt install xdotool unclutter
```

Create a kiosk file

```bash
sudo nano /home/pi/kiosk.sh
```

Paste the following in for chromium

```shell
#!/bin/bash

xset s noblank
xset s off
xset -dpms

unclutter -idle 0.5 -root &

sed -i 's/"exited_cleanly":false/"exited_cleanly":true/' /home/pi/.config/chromium/Default/Preferences
sed -i 's/"exit_type":"Crashed"/"exit_type":"Normal"/' /home/pi/.config/chromium/Default/Preferences

#/usr/bin/chromium-browser --noerrdialogs --disable-infobars --kiosk https://www.raspberrypi.com/ https://time.is/London &
#/usr/bin/chromium-browser --no-sandbox --window-size=1024,768 --kiosk --window-position=0,0 https://hdrcameras.onling.com:5001/webman/3rdparty/SurveillanceStation/?launchApp=SYNO.SS.App.VideoViewerVue.Instance&SynoToken=W9ZwQIG7NiF1Q &
#/usr/bin/chromium-browser --window-size=1080,720 --kiosk --window-position=0,0 https://www.hammerdownrange.com/lobby/index.php &
/usr/bin/chromium-browser --window-size=1080,720 --kiosk --window-position=0,0 https://www.hammerdownrange.com/lineup/lineup.php &
 
while true; do
   xdotool keydown ctrl+Tab; xdotool keyup ctrl+Tab;
   sleep 10
done
```

Paste the following in for firefox

```bash
# Disable screen blanking and power management (X11 only)
xset s noblank
xset s off
xset -dpms

# Hide mouse cursor (X11 only)
unclutter -idle 0.5 -root &

# Optional: Clean any crash flags (Firefox is more forgiving, but harmless to keep)
sed -i 's/"exited_cleanly":false/"exited_cleanly":true/' ~/.mozilla/firefox/*.default*/prefs.js 2>/dev/null || true

# Launch Firefox in kiosk mode
# -kiosk          → Fullscreen kiosk (hides UI, prevents exiting easily)
/usr/bin/firefox --kiosk --private-window https://synology.onling.com/webman/3rdparty/SurveillanceStation/login.cgi?SynoToken=nQhMc44EQyoEpeg &

# Optional: Cycle tabs / refresh every 10 seconds (your original behavior)
# If you only have one URL, you can comment this out or change it to a refresh instead
while true; do
    # Send Ctrl+Tab to cycle tabs (if you open multiple tabs)
    xdotool keydown ctrl+Tab; xdotool keyup ctrl+Tab;
    sleep 10
done
```

Make it executable

```bash
sudo chmod +x /home/pi/kiosk.sh
```

Make a service file to auto startup

```shell
sudo nano /lib/systemd/system/kiosk.service
```

Paste the following in

```shell
[Unit]
Description=Firefox Kiosk Mode
After=graphical.target
Wants=graphical.target

[Service]
Type=simple
Environment=DISPLAY=:0
ExecStart=/home/pi/kiosk.sh
Restart=always
RestartSec=5
User=pi
WorkingDirectory=/home/pi

[Install]
WantedBy=graphical.target
```

Make it so it auto starts and start it

```shell
sudo systemctl enable kiosk.service
sudo systemctl start kiosk.service
```