# Player setup runbook: make a screen open /player on boot

Last updated Oct 27, 2026 · Page: https://freebeeads.com/docs/repo/player-setup · Markdown: https://freebeeads.com/docs/md/repo/player-setup.md · All docs: https://freebeeads.com/llms-full.txt

This is for ops. It covers the three boxes we put behind mall screens today
(a Windows mini PC, a Mac mini, an Android TV box) and tells you how to make
each one open the browser player full screen every time it powers on, stay
awake, and recover on its own. Read it once end to end before your first
install. The iPad quick start lives in `web/PLAYER.md`.

The player URL is `https://<your web host>/player`. Add `?vision=1` to turn
the camera counter on at first load (it asks for permission once; only
counts leave the device, never images). It counts people walking past and
the faces that look; use `?vision=faces` on a box too slow for that. Check
the camera with `/player/vision-test` before going live
(`docs/AUDIENCE_MEASUREMENT.md`).

## What a good install looks like

1. Box powers on, logs in by itself, Chrome opens full screen on `/player`.
2. First time: the screen shows a 6-character code. Type it into
   **Devices > Pair a device** and pick the screen. The code refreshes itself
   if it expires, so there is no rush.
3. Within a minute the loop starts. On the **Devices** page the card for
   that screen shows: a green last check-in dot, the player version
   (`web-1.1.0` or later), uptime climbing, cache "n of n ready", queued records 0,
   camera "counting" (if you enabled it), and "Healthy".
4. Pull the wifi for a few minutes. The screen keeps looping from its cache,
   the card's dot goes amber then red, and "queued records" grows on the
   player's own status overlay (tap any corner 5 times, or add `?debug=1`).
   Plug wifi back in: the records upload in order and the dot goes green.
   Nothing is counted twice.

If step 3 never happens, the checklist at the end of this page is for you.

## Windows mini PC (Windows 10 or 11, Chrome)

1. **Create a local account for the screen** with no password: Settings >
   Accounts > Other users > Add account > "I don't have this person's sign-in
   information" > "Add a user without a Microsoft account". Name it `screen`.
2. **Auto sign-in**: press Win+R, run `netplwiz`, untick "Users must enter a
   user name and password", pick `screen`, OK. (On Windows 11 if the box is
   missing, set the registry value
   `HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\PasswordLess\Device\DevicePasswordLessBuildVersion`
   to `0` and reopen netplwiz.)
3. **Never sleep**: Settings > System > Power > Screen and sleep: all "Never".
   Then in Control Panel > Power Options > Change plan settings > Change
   advanced power settings: Hard disk "Never", USB selective suspend "Disabled".
   In BIOS, turn on "Restore on AC power loss" (or "Power on after power
   failure") so the box boots itself after an outage.
4. **Disable Windows Update reboots** as far as the edition allows: Settings
   > Windows Update > Advanced options > Active hours 00:00 to 23:00 is not
   possible, so set 10:00 to 23:00 (the mall day) and accept that overnight
   reboots happen. The player comes back on its own after a reboot.
5. **Kiosk shortcut**: create a file
   `C:\Users\screen\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\player.cmd`
   with this content (one line for the Chrome command):

   ```bat
   @echo off
   timeout /t 20 /nobreak >nul
   start "" "C:\Program Files\Google\Chrome\Application\chrome.exe" --kiosk --noerrdialogs --disable-infobars --disable-session-crashed-bubble --autoplay-policy=no-user-gesture-required --check-for-update-interval=31536000 --user-data-dir=C:\screen-profile "https://<your web host>/player?vision=1"
   ```

   The 20 second wait lets wifi connect first. `--user-data-dir` keeps the
   screen's pairing separate from any other Chrome profile on the box.
6. **Hide the mouse pointer**: install AutoHideMouseCursor (free) in the
   same Startup folder, or just unplug the mouse after setup.
7. Reboot and watch it come up by itself. Pair it. Done.

**Exit kiosk mode** on site: Alt+F4 closes Chrome; the player restarts at the
next reboot. To open the player's status overlay instead, tap or click a
screen corner 5 times.

## Mac mini (macOS 13 or later, Chrome)

1. **Account**: System Settings > Users & Groups > add a Standard user
   `screen` with a simple password (macOS requires one). Then under Login
   Options set "Automatically log in as" `screen`. FileVault must be OFF for
   auto login to work (System Settings > Privacy & Security > FileVault).
2. **Never sleep**: System Settings > Displays > Advanced: "Prevent automatic
   sleeping when the display is off" on. Then in Terminal, as an admin:

   ```sh
   sudo pmset -a sleep 0 displaysleep 0 disksleep 0 autorestart 1 womp 1
   sudo systemsetup -setrestartfreeze on
   ```

   `autorestart 1` boots the Mac after a power cut. Also turn off the screen
   saver and "Require password after sleep" for the `screen` user.
3. **Kiosk launcher**: as the `screen` user, create
   `~/Library/LaunchAgents/com.freebee.player.plist`:

   ```xml
   <?xml version="1.0" encoding="UTF-8"?>
   <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
   <plist version="1.0"><dict>
     <key>Label</key><string>com.freebee.player</string>
     <key>ProgramArguments</key><array>
       <string>/Applications/Google Chrome.app/Contents/MacOS/Google Chrome</string>
       <string>--kiosk</string>
       <string>--noerrdialogs</string>
       <string>--disable-infobars</string>
       <string>--disable-session-crashed-bubble</string>
       <string>--autoplay-policy=no-user-gesture-required</string>
       <string>--user-data-dir=/Users/screen/screen-profile</string>
       <string>https://<your web host>/player?vision=1</string>
     </array>
     <key>RunAtLoad</key><true/>
     <key>KeepAlive</key><true/>
     <key>ThrottleInterval</key><integer>10</integer>
   </dict></plist>
   ```

   Load it once with `launchctl load ~/Library/LaunchAgents/com.freebee.player.plist`.
   `KeepAlive` relaunches Chrome if it ever quits or crashes.
4. **Camera permission** (only if you use `?vision=1`): the first launch asks
   "Chrome would like to access the camera". Click OK once; macOS remembers.
5. **Hide the pointer**: unplug the mouse, or move it to a corner. Chrome
   kiosk hides it after a few seconds of no movement.
6. Reboot and confirm it comes up by itself. Pair it.

**Exit kiosk mode** on site: Cmd+Q quits Chrome; `KeepAlive` relaunches it in
10 seconds, so first run `launchctl unload ~/Library/LaunchAgents/com.freebee.player.plist`
from Terminal (switch user with fast user switching or SSH in).

## Android TV box (Android TV 11 or later, or any Android box)

Android TV's Chrome is not in the Play Store on most boxes. Use one of:

- **Fully Kiosk Browser** (paid, recommended): it is built for this. Install
  it from the Play Store (or sideload the APK), then in its settings set
  Start URL `https://<your web host>/player?vision=1`, turn on "Launch on
  boot", "Keep screen on", "Kiosk mode", "Autoplay videos", "Enable camera
  access" (if you use vision), and "Reload on internet reconnect" OFF (the
  player handles reconnect itself and reloading would restart the loop).
- **Chrome sideloaded** with the ADB commands below.

ADB route (box in developer mode, `adb connect <box ip>`):

```sh
adb install chrome.apk
# keep the box awake while plugged in
adb shell settings put global stay_on_while_plugged_in 7
adb shell settings put system screen_off_timeout 2147483647
# open the player now
adb shell am start -n com.android.chrome/com.google.android.apps.chrome.Main -d "https://<your web host>/player?vision=1"
```

To launch at boot, install a small launcher app such as "AutoStart - No
root" and point it at Chrome, or set Fully Kiosk as the Home app (Settings >
Apps > Default apps > Home app). Then open the overlay on the screen once
(tap a corner 5 times with a USB mouse) and press **Fullscreen**; Chrome
remembers it for that site.

Android boxes are the least reliable of the three: Chrome on Android drops
large video caches under memory pressure, there is no true kiosk mode
without Fully Kiosk, and some boxes ignore the wake settings. Prefer a mini
PC for a screen that sells premium slots.

## Wake lock and auto update

- The player asks the browser for a **wake lock** so the display stays on
  even if the box's settings slip. The overlay shows "Wake lock: active".
  Browsers only grant it to a visible tab in a secure (https) context.
- The player checks for a **new build every 5 minutes** and reloads itself
  at the next slot boundary. You never need to visit a screen for an update.
- Every **15 seconds** the player checks in with its health (version,
  uptime, cache, queued records, camera state, last error). This is what the
  Devices page shows.

## Remote fixes from the Devices page

Before you drive to the mall, try these from the card:

- **Reload** when the page looks frozen or shows an old build.
- **Restart the loop** when ads stopped advancing but the page responds
  (for example after a long outage). Nothing is downloaded again.
- **Clear cache** when a creative looks wrong or outdated. The player drops
  its stored files and fetches today's loop again. Play records are not
  touched.

The screen runs a command at its next check-in (within 15 seconds when it
is online) and reports a one-line result back onto the card.

## When it does not pair or check in

1. The screen shows "API unreachable, retrying pairing": the box has no
   internet, or the web host cannot reach the backend. Check wifi first.
2. The code was accepted but Pair a device keeps waiting: the screen may
   have reloaded and now shows the same code (fine, keep waiting) or a new
   one (type the new one).
3. The card shows an old last check-in but the screen is playing: it is
   offline and playing from cache. That is the design. Fix the network; the
   queued records upload themselves.
4. Camera says "no permission": the browser blocked the camera. On the box,
   open the overlay, press "Vision off" then on again to re-prompt, or allow
   the camera in the browser's site settings for the player host.

## Limits of the browser player (what the native app will remove)

- A browser cannot start itself; it depends on the OS auto login and kiosk
  tricks above, which a Windows update or a macOS prompt can undo.
- Storage is at the browser's mercy. Chrome may evict cached creatives when
  the disk is low; the player then re-downloads at the next online moment.
- No hardware watchdog: if Chrome hangs hard, only a power cycle (or the
  Reload command, if the tab still checks in) brings it back.
- Camera counting runs in JavaScript and costs CPU on cheap boxes; counts
  may be lower than a native sensor would report.
- Screenshots of what is actually on the glass are not possible from a
  browser; the native app will add a periodic on-device thumbnail that
  stays on the device unless ops asks for it.
