Ours are TP-Link Tapo C120 and C210 units on Wi-Fi. Nothing below is specific to Tapo beyond the menu names; anything that serves RTSP goes in the same way, and the two things most likely to go wrong (a camera whose address changes, and a camera block whose stream paths still point at the previous camera) have nothing to do with the maker. When you want the whole file rather than one camera's worth, it is on the annotated config page. If you are still choosing cameras, which cameras work with Frigate comes first, and the cameras page explains why we have five jobs and not one wide shot.
The rule
One camera per job, named by the job. Water watches the fountain. Food watches the bowl. Treat watches the dispenser. Court watches the whole floor from above. Face is close enough to be a portrait. In Frigate those are cat_water_bowl, cat_food_bowl, cat_treat_dispenser, cat_scratching_pad and helen_food_face. Two more watch the bed and the playroom. The name follows the camera into everything downstream: the public proxy's allowlist, the pipeline's station map, the file names of the clips. Pick it once, before you save.
The camera side, before Frigate
Three things on the camera, none of them in Frigate.
A camera account. Tapo cameras do not let you use your cloud login for RTSP. In the Tapo app: the camera → Advanced → Camera Account. Set a username and a password. That pair is what goes into every RTSP URL; it is <CAMERA_USER> and <CAMERA_PASSWORD> throughout this site. We use the same pair on every camera, kept in a password manager. TP-Link's RTSP/ONVIF FAQ walks through it with screenshots.
A reserved address. On the router, give the camera's MAC a DHCP reservation so 192.168.1.<N> is always the same camera. A camera that changes address is a camera Frigate silently stops recording. Network hygiene has the table we keep.
The two paths. Every Tapo camera serves two RTSP streams on port 554: /stream1 is the main stream (2560×1440 on the C120, 2304×1296 on the C210) and /stream2 is the sub-stream at 640×360. Both carry H.264 video and a small PCMA/8000 audio track. Both are always on; you do not enable them.
Why two streams
Frigate does two different things with a camera, and they want different pictures. Detection looks at a small frame a couple of times a second and asks "is there a cat in it?" — 640×360 at 2 fps is more than enough for an animal that lingers at a bowl, and it keeps the decode cost and the detector cost tiny. Recording keeps the full-resolution main stream untouched, because the clip is what gets cut into a Short later. So: stream2 gets the detect role, stream1 gets the record role. Detecting on the main stream is the usual reason a Frigate box runs hot.
Why go2rtc in the middle
Frigate ships with go2rtc, a restreamer. Instead of Frigate pulling from the camera directly, go2rtc pulls each stream from the camera once and republishes it on rtsp://127.0.0.1:8554/<name>. Then anything that wants the picture takes it from go2rtc: Frigate's detect process, Frigate's record process, the ffmpeg that pushes the 24/7 YouTube stream, all without a second connection to the camera. Cheap Wi-Fi cameras get unhappy with more than one or two RTSP clients; with go2rtc they only ever see one.
The convention we use: <name> for the main stream, <name>_sub for the sub-stream. That is what the camera block below points at.
go2rtc:
streams:
cat_water_bowl:
- rtsp://<CAMERA_USER>:<CAMERA_PASSWORD>@192.168.1.<N>:554/stream1
cat_water_bowl_sub:
- rtsp://<CAMERA_USER>:<CAMERA_PASSWORD>@192.168.1.<N>:554/stream2
cameras:
cat_water_bowl:
ffmpeg:
inputs:
- path: rtsp://127.0.0.1:8554/cat_water_bowl_sub
roles:
- detect
- path: rtsp://127.0.0.1:8554/cat_water_bowl
roles:
- record
detect:
width: 640
height: 360
fps: 2
enabled: true
audio:
enabled: false
objects:
track:
- cat
- person
person is on a cat cam's track list because the Shorts pipeline refuses to publish a visit with a person in frame, and it can only refuse what Frigate detected. The config page explains the thresholds.
The naming and allowlist idea
The house has three more cameras — front door, back yard, carport — that are in Frigate for the ordinary reason people have cameras. They are configured differently: they pull from the camera directly with no go2rtc entry, because nothing but Frigate needs them; they have detect: enabled: false; and their names never appear in the public proxy's allowlist. A camera that is not in go2rtc cannot be restreamed, and a camera not in the allowlist cannot be seen from the website. How the four public cameras get out safely is its own page.
- Decide the job, then mount the camera. If you cannot say the job in one word, do not add the camera yet. Mount at the animal's height for bowls, overhead for the whole room. The cameras page shows ours.
- Create the camera account in the maker's app. Tapo: Advanced → Camera Account. Write the username and password into your password manager as the camera login. Do not reuse your Tapo cloud password.
- Reserve the address on the router. Find the camera's MAC in the app or the router's client list, add a DHCP reservation, and reboot the camera so it picks it up.
-
Open both streams in VLC or ffprobe.
rtsp://user:pass@192.168.1.N:554/stream1and/stream2. If VLC will not play them, Frigate will not either; fix that first. Note the sub-stream resolution — 640×360 on Tapo. -
Add both to go2rtc.
Two entries under
go2rtc: streams:, named<name>and<name>_sub. Save the config and let Frigate restart go2rtc. -
Add the camera block.
Copy the block above. Change the name in five places: both go2rtc keys, the camera key, and the two
path:lines underinputsthat point at them. Miss the paths and the new camera silently watchescat_water_bowl's streams. Sub for detect, main for record, 640×360 at 2 fps. Trackcatandperson. -
Restart Frigate and run the checks.
Five things, in order: a picture in the maker's app, ffprobe on the RTSP URL, the camera listed in
/api/stats,camera_fpsclose to what you set,skipped_fpsat 0.0.
The checks, as commands
# 1. the camera answers on RTSP at all (from any machine on the LAN)
ffprobe -rtsp_transport tcp "rtsp://<CAMERA_USER>:<CAMERA_PASSWORD>@192.168.1.<N>:554/stream2"
# look for: Video: h264 ... 640x360 and Audio: pcm_alaw, 8000 Hz
# 2. go2rtc has it (after a config reload)
curl -s http://127.0.0.1:5000/api/go2rtc/streams | python -c "import sys,json; print(list(json.load(sys.stdin)))"
# 3. Frigate is keeping up
curl -s http://127.0.0.1:5000/api/stats | python -c "import sys,json; c=json.load(sys.stdin)['cameras']['cat_water_bowl']; print(c['camera_fps'], c['skipped_fps'], c['detection_fps'])"
# 2.1 0.0 2.0
Frigate's own camera-specific docs list quirks for other makers (Reolink, Amcrest, Dahua, Hikvision); Tapo needs nothing special beyond the camera account. If a camera shows camera_fps 0.0 with everything else alive, it is the camera or the Wi-Fi, not Frigate: one of ours (a house camera) was doing exactly that when this page was written.