Content not loading
Symptom: the dashboard shows the sign as Online with a healthy heartbeat, but the wall is one of:
- Blank (white, black, or the kiosk's idle splash)
- Frozen on a previous URL that should have changed
- Showing partial content (header but no images, etc.)
- Showing a browser error page
This is content-side, not kiosk-side. The sign is doing its job; what it's been told to display has a problem.
Quick diagnostic
Three things to check, in order:
- Test the content URL from your laptop. Paste it into a browser. Does it load?
- Check the dashboard's content reachability indicator. On the sign detail page, the Content card shows reachable (green) or unreachable (red).
- Walk over to the wall (or have someone send a phone photo). Does the rendered output match what your browser shows?
If your laptop loads the URL fine but the wall is wrong, the issue is between the kiosk and the content origin — DNS, network path, TLS, HTTP headers — not the content itself.
The URL is unreachable from the venue
Even if you can load the URL from your office laptop, the kiosk on the venue network may not be able to.
Diagnose:
# From the kiosk:
$url = "https://your-content.example.com/page"
Test-NetConnection your-content.example.com -Port 443
Resolve-DnsName your-content.example.com
# Pull the actual response the kiosk would see
Invoke-WebRequest $url -UseBasicParsing |
Select-Object StatusCode, ContentType, @{n="Length";e={$_.Content.Length}}
Common causes:
| Symptom | Cause | Fix |
|---|---|---|
Test-NetConnection fails | Venue firewall blocks the content origin | Allowlist the content origin in venue IT |
| DNS fails | Content URL only resolves on a specific DNS | Use public DNS, or add a hosts entry |
| HTTP 403 / 401 | Origin requires auth, IP allowlisting, or rate-limits the kiosk's IP | Whitelist the kiosk's egress IP at the origin, or use auth in the URL |
| HTTP 200 but blank body | Content origin returning empty page (server-side bug) | Fix at the origin |
Mixed content (HTTPS / HTTP)
The desktop sign loads URLs in a Chromium-based browser, which enforces mixed-content rules. If your assigned URL is HTTPS but it tries to load HTTP subresources (images, scripts, stylesheets), Chromium silently blocks them.
Symptom: the page loads but visual elements are missing. Often shows up as "the layout is right but the images are broken."
Fix: make sure all subresources are HTTPS:
- Use protocol-relative URLs (
//cdn.example.com/img.png) so subresources match the parent's protocol - Or, more reliable, hard-code HTTPS everywhere in your content
- If the parent is HTTP and pulls HTTPS subresources, that's fine — Chromium only blocks the insecure direction
You can confirm this by loading the same URL in a Chromium-based browser on a venue laptop and checking the console for Mixed Content errors.
X-Frame-Options and Content-Security-Policy
DisplaySync does not iframe the assigned URL — it loads as the top-level document. So X-Frame-Options: DENY and frame-ancestors CSP directives don't apply.
But if your content depends on being iframeable for some other reason (a third-party widget you embed), the inner iframe respects those headers. If the page renders but a widget inside doesn't, check the widget's response headers.
The URL takes too long to load
Slow content origins can stall the kiosk's render — the page never finishes loading and the wall shows a hung spinner or a blank screen.
Symptom: the page renders for a moment showing a loading spinner, then stalls indefinitely (or shows a blank screen).
Fix the content side first. Slow first-byte responses indicate origin overload — fix that.
If you absolutely cannot fix the origin (third-party content, vendor app), expect the wall to look broken during the slow window every time.
The URL changed but the kiosk shows the old one
You changed the assigned URL in the dashboard, but the kiosk is still showing the previous content.
Likely causes:
| Diagnosis | Cause | Fix |
|---|---|---|
| Sign was offline at the time of the change | Command queued, not executed | Wait for sign to come online (it'll receive sign:display_content on reconnect) |
| Sign is showing stale cache | Browser cached aggressively | Send Refresh — forces a hard reload |
| Dashboard shows the new URL but kiosk audit log doesn't | Backend → kiosk WebSocket dropped the update | Send Refresh, or reboot the sign app |
| Dashboard shows the old URL | The save didn't take | Save again; if persistent, see Sign won't claim |
When in doubt, Refresh is the safest first step. It reloads the page from the assigned URL, bypassing browser cache.
The page renders but JavaScript looks broken
Some pages depend on browser features that need explicit permission (audio autoplay, full-screen, clipboard access). The kiosk runs Chromium with its standard policies, so autoplay-without-interaction is muted-only by default — no special command-line switches are baked in to relax that.
If your page depends on unmuted autoplay or another media-permission feature and it's not firing, this is the most common cause.
Workarounds:
- Don't depend on autoplay-without-interaction; design for it failing gracefully (a static fallback frame).
- Set
<video autoplay muted playsinline>so Chromium's muted-autoplay policy kicks in.
Reachability says "Unreachable" but the page actually works
The reachability monitor uses HTTP HEAD requests every 60 seconds. Some servers respond to GET but reject HEAD (with 405 or by hanging). The page works fine when loaded normally; the monitor sees failures.
Fix:
- Check your origin's HEAD response:
curl -I https://your-content.example.com/page - If it returns anything other than 2xx or 3xx (or hangs), the origin is misconfigured.
- Most frameworks have a one-line fix to map HEAD to a no-body GET response. Add it.
- Or front the origin with a CDN like Cloudflare; CDNs handle HEAD natively even when origins don't.
See Assigning content → Reachability monitoring for the full reachability contract.
The cached version of the page is stale
Browser cache can keep an old version of the page sticky even after the kiosk receives a Refresh command. Escalation ladder:
| Action | What it does | When it's enough |
|---|---|---|
| Refresh | Soft reload — respects Cache-Control headers on the page. Equivalent to F5. | When the page sets Cache-Control: no-cache (or similar) and the cached copy is genuinely stale only briefly. |
| Reboot app | Chromium renderer relaunches. Cache behavior depends on the kiosk's Electron partition config; in practice this clears most page-cached state. | When Refresh isn't enough and the assigned URL is showing stale resources. |
| Reboot device | Full restart. Hard cache flush plus everything else. | When even Reboot app didn't clear it. Rare. |
Origin-side fix is more reliable than command escalation. If your content URL changes frequently, set Cache-Control: no-cache, max-age=0 on the response headers. The kiosk then never caches the resource beyond a single render cycle. Static assets (CSS, JS, images) can keep longer cache lifetimes via fingerprinted filenames — the HTML is what should be uncached.
Wall is laggy / stuttering
A wall is displaying the right content but everything is sluggish — animations stutter, scroll feels jerky, transitions miss frames. Distinct from "wall flashed and reloaded itself" (a watchdog event) — the wall here is running, just slowly.
Diagnose: press Ctrl+Shift+S at the kiosk to open the Status Dashboard overlay. Check three rows:
| Metric | Baseline (static content) | Red flag |
|---|---|---|
| System CPU | 10-20% | sustained > 70% |
| App CPU | 5-15% | sustained > 50% |
| RAM (process) | 200-500 MB | > 80% of physical RAM or growing monotonically over hours |
A growing RAM line is the most common cause — a memory leak in the customer web app the kiosk is rendering. The leak doesn't show up at startup; it accumulates over hours.
Fix paths:
- Reboot app — fastest fix. Drops the leaked memory; the page reloads fresh. Buys hours-to-days before the leak re-manifests.
- Reboot device — if the leak is leaking outside the renderer (kernel buffers, GPU memory).
- Reduce content complexity if the same kiosk keeps hitting saturation. Big WebGL scenes, embedded video players, large image carousels all stress the renderer; consider serving a lower-fidelity version to fleet kiosks vs. preview screens.
For watchdog-driven reloads triggered by extreme freezes (>30s frozen JS), see The wall flashed and reloaded itself — different symptom, related cause.
Wall is blank with no errors
If the wall is genuinely showing nothing — not a loading state, not an error page, just a blank screen — and the dashboard says everything is healthy:
- Press Ctrl+Shift+S on the kiosk to confirm the kiosk is alive at all.
- Check the Cache Status card. If it shows
Items Cached: 0, the kiosk has nothing to fall back on, so a blank assigned URL produces a blank wall. - Send Refresh; watch the wall.
If Refresh produces nothing, restart the sign app: Reboot app. On relaunch, the kiosk reloads the assigned URL from scratch.
If even reboot doesn't help, the assigned URL is genuinely returning a blank page — fix at the content origin.
The wall flashed and reloaded itself
A wall briefly going blank or showing a flicker, then reloading the same content, is usually one of three in-process watchdogs deciding the page was unhealthy and forcing a fresh load. Visible behavior is the same; the cause differs:
| What the watchdog detected | Symptom in error.log | Operator action |
|---|---|---|
| FrameWatchdog — page rendered as ≥95% white for 5+ seconds | [WARN] FrameWatchdog: 95%+ white frame detected; reloading + frame_anomaly analytics event | Check the assigned URL — is the page actually showing white? Common cause: a CDN error page that returns whitespace. |
| PageWatchdog — JS thread frozen for ≥30s | [WARN] PageWatchdog: page frozen for 30000ms+; reloading + page_frozen analytics event | Check the page for runaway JS (infinite loop, large WebGL allocation). Server-side issues don't trigger this — only client-side hangs. |
| GpuMonitor — Electron renderer process crashed | [INFO] GpuMonitor: renderer crashed; scheduling reload in 1000ms + process_crash analytics event | Crashes that recover are usually one-offs. If recurring, check for GPU driver issues or content that stresses the renderer. |
A 60-second RecoveryCooldown is shared across the three watchdogs. If a fault keeps re-failing, you'll see one reload-flash, then 60 seconds of nothing, then another. The cooldown prevents tight reload loops.
If the same wall flashes more than ~3 times in a row, the watchdog is masking a real problem with the URL or the device — open Ctrl+Shift+S and check what's in the log.
Still stuck
Capture diagnostics per Getting support, and include:
- The exact assigned URL
- A
curl -I <url>andcurl -L <url>from the kiosk's PowerShell - A phone photo of the actual wall
- Last 200 lines of
sign.log