Docs
Self-hosted Frigate companion app · setup, configuration, troubleshooting
Last updated September 2026
On this page
These docs assume you already run Frigate NVR — the community build or a Frigate+ subscription — and want a phone-shaped window into it. If you don't have Frigate yet, start at the Frigate project's official documentation, get a single camera working in the web UI, then come back here.
01Quick start
You need two things: the app, and the URL your Frigate web UI answers on. Everything else is optional.
0. Install the app
iPhone: download ViewPane free on the App Store (iOS 16 or newer). Android: the build exists and is heading into Google Play closed testing — get on the list for the test and we'll email the opt-in link when it opens, or get the link when the public listing opens.
1. Add your server
On first launch, ViewPane asks for a server name, a Local URL, and (optionally) an External URL. The Local URL is what you type into a browser on your home network to reach Frigate — typically http://192.168.x.x:5000, or your auth proxy's port if you run one (see Frigate config). If Frigate asks for a login, enter the same credentials in the app; they're stored in your phone's OS keychain and sent only to your server.
2. Capture thumbnails
The Cameras tab shows one tile per camera. Tiles start empty — tap the refresh button in the toolbar to capture a snapshot from every camera. Thumbnails are yours to curate: they stay put until you refresh them, so you can pick the frames you like. Long-press a tile to reset one.
3. Go fullscreen
Tap any tile for the fullscreen live view — native-codec video streamed straight from your server, with pinch-to-zoom, pan, and landscape support. If fullscreen shows a stream error, your Frigate needs its restream (go2rtc) enabled — covered in the next section.
No Frigate yet?
Tap Try Demo Mode on the first screen. The whole app runs on sample data — no server, no account, nothing leaves the phone.
02Frigate config requirements
ViewPane talks to the standard Frigate HTTP API — version 0.14 or newer (tested on 0.16 and 0.17), community or Frigate+. Three config areas matter:
Snapshots + recordings
Event thumbnails need snapshots enabled; clip playback and the continuous-recording downloader (which pulls a time range of 24/7 footage, not just event clips) need record enabled:
cameras:
front_door:
snapshots:
enabled: true
record:
enabled: true
retain:
days: 7Restream (go2rtc) for fullscreen live
The fullscreen live view streams from Frigate's built-in go2rtc restream at /api/go2rtc/api/stream.mp4. If your cameras are defined under Frigate's go2rtc block (the recommended setup in Frigate's own docs), this already works. If fullscreen shows "check your Frigate restream config", add your camera streams to the go2rtc section of your Frigate config.
frigate-auth coexistence
If you front Frigate with the community frigate-auth nginx proxy (or any Basic-auth reverse proxy), point ViewPane at the proxy's port, not raw 5000, and enter the proxy credentials in the app's server settings. Your existing login keeps working everywhere else — ViewPane just presents the same credentials.
03Push relay setup
Push notifications (Pro) run through a small relay container you host next to Frigate. It subscribes to Frigate's MQTT event stream and forwards alerts to your phone — no cloud service ever holds your events. Add it to your existing compose file:
Best-effort, by design. A push travels from your relay through the Expo push API and then Apple's or Google's push service to your phone. Any hop can delay or drop it: your network, your carrier, battery optimization, the app being force-stopped, or a platform outage. The relay also filters on purpose (cooldowns, confidence thresholds, a per-device rate limit, a short hold on person events so face recognition can veto). ViewPane is a viewer for your own server, not an alarm system or a monitored security service. Don't make it your only way of knowing what your cameras see.
services:
viewpane-relay:
image: ghcr.io/kampbell562/viewpane-relay:0.2
container_name: viewpane-relay
restart: unless-stopped
ports:
- "8787:8787"
environment:
MQTT_URL: mqtt://mosquitto:1883
REGISTER_SECRET: "" # run: openssl rand -hex 32 (32+ chars)
TZ: America/Chicago # your timezone
# PUBLIC_BASE_URL: http://my-server:8787 # this relay as your PHONES reach it; enables snapshot images in alerts
# FRIGATE_URL: http://frigate:5000 # enables known-face suppression, snapshot proxy, clip transcode
# FRIGATE_AUTH: "user:pass" # Basic auth for FRIGATE_URL (needed for /snapshot and /clip)
volumes:
- viewpane-relay-data:/data
logging:
driver: json-file
options:
max-size: 10m
max-file: "3"
volumes:
viewpane-relay-data:The 0.2 and latest tags are both published by our CI and pull anonymously. Clip transcoding and known-face suppression need FRIGATE_URL (and FRIGATE_AUTH if Frigate has a login).
Generate the secret with openssl rand -hex 32. It's what proves your phone is allowed to register with your relay — treat it like a password. To verify the relay is up, run curl http://localhost:8787/health on the host — the health endpoint needs no authentication.
Then in the app: Settings → Motion Alerts (toggle on) → Background Push Relay → enter Relay URL (http://<your-server>:8787) + Register Secret → Connect Relay. Once connected, the Notification Rules screen gives you per-camera toggles, daily schedules, and, on Android, a critical-alert channel that can bypass Do Not Disturb. If Frigate's mqtt.topic_prefix isn't the default frigate, set MQTT_TOPIC_PREFIX to match.
04Tailscale walkthrough
Tailscale gives you remote access with zero port-forwarding. Four steps:
- Install Tailscale on the machine running Frigate and sign in.
- Install the Tailscale app on your phone, same account, toggle it on.
- Make sure MagicDNS is enabled in your Tailscale admin console (it is by default on new tailnets).
- In ViewPane, set the server's External URL to
http://<machine-name>:5000(or your auth proxy's port) — the machine name from your Tailscale admin console, not an IP.
Use the MagicDNS name, not the 100.x.x.x IP. ViewPane deliberately refuses plain-HTTP URLs on the 100.64/10 carrier-grade NAT range: on some mobile carriers that range is reachable outside your tailnet, which could leak credentials. The MagicDNS hostname only resolves inside your tailnet, so it's safe — and it survives IP changes.
With both URLs set, ViewPane races local against external on every connect and picks whichever answers — walk out the door and the badge flips from LOCAL to EXTERNAL on its own. WireGuard works the same way: any VPN that presents your server on a private address (10.x, 172.16–31.x, 192.168.x) is fine, as is any HTTPS reverse proxy.
05MQTT auth
If your broker currently runs with allow_anonymous true, lock it down — the relay and Frigate each get their own user:
# on the broker host mosquitto_passwd -c /mosquitto/config/passwd frigate mosquitto_passwd /mosquitto/config/passwd viewpane-relay
# mosquitto.conf allow_anonymous false password_file /mosquitto/config/passwd listener 1883
Point Frigate's mqtt: block at the frigate user, and give the relay its credentials via MQTT_USERNAME / MQTT_PASSWORD environment variables. Restart the broker first, then Frigate, then the relay — the relay reconnects automatically, but starting it last avoids a burst of auth-failure log noise.
Keep port 1883 off the public internet: bind it to localhost / your Docker network / your tailnet. The relay is the only thing that needs to reach it besides Frigate itself — your phone never talks to MQTT directly.
06FAQ
Does ViewPane work without Tailscale?
Yes. On your home network, the Local URL is all you need. For remote access, anything that presents your server on a private address works — Tailscale, WireGuard, or an HTTPS reverse proxy with a domain.
Why does the app reject my external URL?
ViewPane blocks plain-HTTP URLs on public and carrier-grade-NAT addresses on purpose — sending your Frigate credentials unencrypted over the open internet is how they get stolen. Use a Tailscale MagicDNS name, a VPN private address, or HTTPS.
Does it work with Reolink / Amcrest / Hikvision / brand-X cameras?
Camera brand doesn't matter. ViewPane talks to Frigate, and Frigate talks to the cameras. If your camera works in Frigate's web UI, it works in ViewPane.
Does it work with a commercial Frigate appliance?
Yes — same API, same app. Community build, Frigate+ models, and commercial appliances all present the standard Frigate HTTP API.
What's actually free?
One server, the multi-camera grid, fullscreen live view with pinch-to-zoom, the last 20 events, LAN + Tailscale access, and demo mode — permanently. Pro ($9.99/year) adds push notifications, full event history with filters, clip playback and save/share, unlimited servers, and Live Wall.
How does Pro billing work?
Pro is a yearly subscription billed by the App Store or Google Play. It renews through your store account and you cancel it there too — ViewPane never sees your payment details, only a yes/no entitlement.
Can I rely on ViewPane as a security or alarm system?
No. ViewPane shows you what your own Frigate server sees, and it can forward Frigate's detections as push notifications. It does not monitor anything itself, does not contact anyone on your behalf, and cannot guarantee a notification arrives or arrives quickly. Delivery depends on your relay, your network, and Apple's and Google's push services. If you need a monitored security or life-safety service, use one alongside ViewPane. The Terms spell this out.
Which OS versions?
iOS 16+ today (tested on iPhone). Android 13+ tested; the Android release is coming.
07Known limitations
Things ViewPane does on purpose, or cannot do, that you should know before relying on it. This list is kept current: if we learn of a defect that can silently lose or delay alerts, it is listed here until it is fixed.
The relay filters alerts by design
Confidence thresholds, per-camera cooldowns, per-device rate limits, and a short hold on person events (default 10 seconds) so Frigate's face recognition can cancel the push are all intentional. If you enroll faces in Frigate and enable face rules in the relay, the relay stays quiet about people it recognizes, which means a stranger your server misidentifies as an enrolled person is not reported. Events that Frigate itself discards (no snapshot persisted) are dropped silently.
Delivery depends on things we don't control
Once a push leaves your relay it travels through Expo's push service and then Apple's or Google's. Battery optimization, doze mode, force-stopping the app, carrier or Wi-Fi outages, and platform incidents can delay or drop it. There is no retry path once a platform push service has dropped a message. Android OEM battery managers (Samsung, Xiaomi, OnePlus) are the most common cause of "alerts stopped".
One push per event, retractions are best-effort
Each Frigate event produces at most one push. If Frigate later marks the event a false positive, the relay sends a silent retraction so the notification can be dismissed; if the retraction is dropped, a stale alert stays on your phone.
What ViewPane never does
It does not record, store, or back up footage. It does not detect anything itself. It does not contact anyone on your behalf. It is a viewer for a server you run, and the Terms of Use say so in the operative words.
Open defects affecting alert delivery
Found 2026-09-16, fixed in the next app update (affects 1.0 and 1.0.1): if you turn Motion Alerts off and back on in Settings, the app does not re-register this phone with your relay, so the switch shows on and the relay shows as reachable while no alert can arrive on this phone. The same can happen if the first Connect Relay attempt failed (notifications denied, or no push token yet). Workaround until the update: after turning Motion Alerts back on, open Settings and tap Connect Relay again; the confirmation "Push Notifications Active" means this phone is registered. Send yourself a test event to be sure.
08Troubleshooting
"Server Unreachable"
Check the URL in a browser on the same network first. The usual suspects: wrong port (your auth proxy's port vs Frigate's raw 5000), phone on cellular with no External URL configured, or Tailscale toggled off on the phone.
Connected, but "Couldn't Load Cameras"
The URL answered, but with something that isn't the Frigate API — usually a reverse proxy's login page. Point the app at your auth proxy and put the proxy credentials in the app's server settings instead of logging in via browser.
Fullscreen shows a stream error
The live view needs Frigate's go2rtc restream — see Frigate config. The grid thumbnails and events will still work without it. If the app reports an HTTP 5xx from the server, check your auth proxy's own log before Frigate: an htpasswd file the proxy's worker cannot read (for example one you tightened to 0600) makes nginx answer 500 to every request that carries credentials, while an unauthenticated request still gets the expected 401. Keep the file readable by the container's nginx user (0644, or group-readable by uid 101) and re-test with your real credentials.
A camera streams on Android but not iOS ("Stream not available")
If one camera plays fine on Android (and in Frigate's own UI) but iPhones only show a spinner and then a stream error, check that camera's go2rtc source in your Frigate config. An http-flv or rtmp source combined with H.265 (HEVC) video produces a stream Apple's video player silently refuses to render, even though every other player accepts it — we hit this ourselves with a Reolink camera set up exactly the way Frigate's docs suggest. Nothing looks wrong server-side: playlists are valid, segments download, other apps play them.
The fix is either one of: switch that camera's go2rtc source to its rtsp:// URL and restart Frigate, or set the camera's encoding to H.264. Only cameras using an FLV/RTMP source are affected — RTSP-sourced cameras stream to iOS without issue. If you moved to FLV because RTSP stuttered, see the next entry.
A Reolink camera stutters every couple of seconds on RTSP
Reolink's 4K 8-series (we measured the RLC-840A) stamps RTSP frames unevenly: a 100–500 ms jump at every keyframe, then a scramble of short gaps. Players honor timestamps, so the live view freezes and catches up on every 2-second GOP. FLV avoids it but breaks iOS (above). The fix that keeps iOS working is to pass the RTSP source through ffmpeg with a timestamp filter, all in the camera's go2rtc source line:
go2rtc:
streams:
living_room:
- 'ffmpeg:rtsp://user:pass@CAMERA-IP:554/h264Preview_01_main#video=copy#audio=copy#raw=-max_interleave_delta 1 -bsf:v setts=ts=if(eq(PREV_OUTPTS\,NOPTS)\,PTS\,PREV_OUTPTS+clip(PTS-PREV_OUTPTS\,0.03/TB\,0.06/TB))'Paste it exactly (single quotes, the \, included) into config.yml and restart Frigate. It copies video and audio untouched and clamps each frame's timestamp gap to 30–60 ms while tracking the camera's real rate, so nothing drifts. Costs about 3% of one core. It has to live in the config file; go2rtc's API rejects sources with spaces. After the restart, reload Frigate's web UI — an open live view falls back to 5 fps jsmpeg until you do. Full write-up on the blog.
Push notifications stopped arriving
In order: is the relay container running (docker logs viewpane-relay)? Does Settings still show the relay as connected? Are notifications paused in the app (check the pause button on the Cameras tab)? Is the camera muted or outside its schedule in Notification Rules? If the relay logs show MQTT auth errors, re-check the broker credentials.
Clips won't play or download
Clips need record enabled and retention long enough that the event's footage still exists. Very old events fall out of retention — the snapshot stays, the clip doesn't.
Live Wall feels slow away from home
By design: over an external connection the Live Wall caps its refresh around 1.5 fps so each frame completes before the next one fires. On LAN it runs at your configured rate.
Still stuck?
Send a bug report with your app version, device, Frigate version, and what you expected vs. what happened — a real human reads every one.