# How Frigate Handles Camera Groups and Multi-Camera Views: Configuration to UI Rendering

> Discover how Frigate handles camera groups and multi-camera views. Learn about YAML configuration and UI rendering for seamless grouped stream display.

- Repository: [Blake Blackshear/frigate](https://github.com/blakeblackshear/frigate)
- Tags: internals
- Published: 2026-05-25

---

**Frigate organizes cameras into named groups via YAML configuration and renders multi-camera views through React components that filter, persist, and display grouped streams based on user permissions.**

Frigate's video surveillance platform allows users to organize cameras into logical groups that appear as unified views in the web interface. The primary keyword configuration lives under the `camera_groups` key in your [`config.yml`](https://github.com/blakeblackshear/frigate/blob/main/config.yml), while the frontend implementation spans React hooks, context providers, and dashboard components. Understanding this pipeline—from backend validation to permission-aware rendering—enables you to build efficient multi-camera monitoring layouts.

## Defining Camera Groups in Configuration

Camera groups are declared in the YAML configuration under the top-level key **`camera_groups`**. Each entry maps a group name to a `CameraGroupConfig` object that specifies which cameras belong together, what icon represents the group, and how it should be ordered in the UI selector.

```yaml
camera_groups:
  front_door:
    cameras: [front_left, front_right]
    icon: "door_front"
    order: 1
  backyard:
    cameras: [back_left, back_right]
    icon: "tree"
    order: 2

```

### Schema Validation on Backend and Frontend

The configuration schema is validated on both sides of the stack. In [`frigate/config/config.py`](https://github.com/blakeblackshear/frigate/blob/main/frigate/config/config.py), the FrigateConfig class declares `camera_groups: Dict[str, CameraGroupConfig]` using Pydantic models to enforce structure at load time. The TypeScript type that mirrors this structure lives in [`web/src/types/frigateConfig.ts`](https://github.com/blakeblackshear/frigate/blob/main/web/src/types/frigateConfig.ts), specifically lines 342-346, where `CameraGroupConfig` defines the interface for the React frontend.

## Selecting and Persisting Groups in the UI

The **CameraGroupSelector** component in [`web/src/components/filter/CameraGroupSelector.tsx`](https://github.com/blakeblackshear/frigate/blob/main/web/src/components/filter/CameraGroupSelector.tsx) builds the dropdown interface that lets users switch between groups. It reads the full configuration via SWR (`useSWR<FrigateConfig>("config")`) and uses `useMemo` to build an ordered list of available groups.

The component handles permission filtering by checking `hasFullCameraAccess` and `allowedCameras` before displaying a group option. If a user lacks access to any camera within a group, that group is filtered from the selector.

### State Persistence Across Sessions

The selector persists the chosen group using `useUserPersistedOverlayState("cameraGroup", "default")`. This hook stores the selection in user-scoped localStorage, ensuring that returning users see their preferred camera group without reselecting it manually.

## Loading Groups from URL Parameters

When users navigate directly to a specific group view, Frigate parses the `group` query parameter from the URL. In [`web/src/pages/Live.tsx`](https://github.com/blakeblackshear/frigate/blob/main/web/src/pages/Live.tsx) (lines 29-34), the `useSearchEffect` hook checks for the parameter and validates it against the configuration:

```tsx
useSearchEffect("group", (cameraGroup) => {
  if (config && cameraGroup && loaded) {
    const group = config.camera_groups[cameraGroup];
    if (group) {
      setCameraGroup(cameraGroup);
      return false;   // keep URL clean – UI handles icon change
    }
    return true;
  }
  return false;
});

```

This allows deep linking to specific views (e.g., `/live?group=backyard`) while maintaining clean URLs once the state is loaded.

## Filtering Cameras for Multi-Camera Views

The **LiveDashboardView** component in [`web/src/views/live/LiveDashboardView.tsx`](https://github.com/blakeblackshear/frigate/blob/main/web/src/views/live/LiveDashboardView.tsx) handles the actual rendering logic for multi-camera layouts. It receives the selected `cameraGroup` and filters the master camera list to include only those specified in the group configuration.

Lines 17-21 demonstrate the filtering logic:

```tsx
return cameras
  .map((cam) => cam.name)
  .filter((cam) => config.camera_groups[cameraGroup]?.cameras.includes(cam))
  .join(",");

```

If the selected group is `"default"`, the view falls back to displaying all cameras with `ui.dashboard` enabled. For custom groups, it extracts the camera names from `config.camera_groups[group].cameras` and further filters them against the user's `allowedCameras` list.

### Birdseye Global View

When a group contains the special pseudo-camera `birdseye`, Frigate renders a unified composite view instead of individual streams. The Live page checks for this condition using an `includesBirdseye` memo and conditionally renders `LiveBirdseyeView` when `selectedCameraName === "birdseye"`. This provides a global multi-camera perspective without consuming multiple video decoder resources.

## Access Control and Permission Filtering

Frigate enforces camera access permissions at multiple points in the group rendering pipeline. The `useAllowedCameras` hook in [`web/src/hooks/use-allowed-cameras.ts`](https://github.com/blakeblackshear/frigate/blob/main/web/src/hooks/use-allowed-cameras.ts) returns the subset of cameras the current user is authorized to view based on their role.

Both the CameraGroupSelector and LiveDashboardView apply this filter:

- **Selector level**: Groups containing no accessible cameras are hidden entirely
- **Dashboard level**: The final camera list intersects with `allowedCameras` before rendering

This ensures that sensitive camera feeds remain invisible even if a user manually constructs a URL with a restricted group name.

## Per-Group Streaming Settings

Frigate stores group-specific streaming preferences in `AllGroupsStreamingSettings` (defined in [`web/src/types/frigateConfig.ts`](https://github.com/blakeblackshear/frigate/blob/main/web/src/types/frigateConfig.ts) lines 81-83). The `StreamingSettingsProvider` context manages these parameters, allowing each group to maintain independent settings for resolution, audio enablement, and compatibility mode.

When the user switches groups, the provider updates the underlying stream parameters for every camera in the group, ensuring that performance-intensive settings like high-resolution birdseye views don't affect standard single-camera streams.

## Summary

- **Configuration**: Define groups in [`config.yml`](https://github.com/blakeblackshear/frigate/blob/main/config.yml) under `camera_groups` with camera lists, icons, and order values, validated by [`frigate/config/config.py`](https://github.com/blakeblackshear/frigate/blob/main/frigate/config/config.py) and [`web/src/types/frigateConfig.ts`](https://github.com/blakeblackshear/frigate/blob/main/web/src/types/frigateConfig.ts)
- **UI Selection**: The `CameraGroupSelector` component filters available groups by permissions and persists selection via `useUserPersistedOverlayState`
- **URL Handling**: `useSearchEffect` in [`Live.tsx`](https://github.com/blakeblackshear/frigate/blob/main/Live.tsx) parses the `group` query parameter for direct linking to specific views
- **Rendering**: [`LiveDashboardView.tsx`](https://github.com/blakeblackshear/frigate/blob/main/LiveDashboardView.tsx) filters the camera array based on group membership and renders either individual streams or the birdseye composite view
- **Security**: `useAllowedCameras` ensures users only see cameras and groups they have permission to access
- **Settings**: Per-group streaming configurations are managed through `StreamingSettingsProvider` and stored in `AllGroupsStreamingSettings`

## Frequently Asked Questions

### How do I create a camera group that shows only specific cameras?

Define the group in your [`config.yml`](https://github.com/blakeblackshear/frigate/blob/main/config.yml) under the `camera_groups` key with a `cameras` array containing the camera IDs you want included. For example, create a "front_yard" group listing only your porch and driveway cameras. The UI will automatically populate the selector with this group once Frigate reloads the configuration.

### What is the difference between a regular camera group and the birdseye view?

A regular camera group displays individual camera streams side-by-side in a grid or list layout, while the birdseye view composites all cameras into a single unified stream. Birdseye appears when you select a group containing the special `birdseye` pseudo-camera, handled in [`Live.tsx`](https://github.com/blakeblackshear/frigate/blob/main/Live.tsx) by rendering `LiveBirdseyeView` instead of individual camera components.

### Why does my camera group not appear in the dropdown selector?

The `CameraGroupSelector` filters out groups where you lack camera access permissions. Verify that your user role includes access to at least one camera in the group via the `useAllowedCameras` logic. Additionally, ensure your YAML syntax is valid and the group is properly nested under `camera_groups` in the configuration file.

### Can different camera groups use different streaming quality settings?

Yes. Frigate stores streaming preferences per-group in `AllGroupsStreamingSettings` managed by the `StreamingSettingsProvider` context. When you switch groups, the UI applies that group's specific resolution, audio, and compatibility settings to all cameras in the view, allowing high-quality settings for important groups and lower bandwidth options for others.