Skip to content

Hikvision Cameras & NVRs

Hikvision is a production-tier adapter . It communicates with cameras and NVRs through Hikvision’s ISAPI HTTP+XML protocol with full Digest authentication. The adapter includes input validation on channel/track/snapshot IDs, an SSRF guard on NVR credential resolution, and tenant scoping on every NVR lookup.

FeatureNotes
Live MJPEG / snapshot streaming_SnapshotCache shares one ISAPI fetch per channel across all concurrent viewers
PTZ controlPan / tilt / zoom continuous move, presets (read, set, go-to), patrols
Recording playbackTimeline search, segment download
NVR import wizardAuto-discover channels, inherit credentials per-channel with org scoping
Motion / line-crossing / intrusion eventsIngest via long-poll alertStream
License-plate recognition (LPR)Event tagging on supported cameras
Camera groups, recording templates, view layoutsFull CRUD

Hik-Connect cloud relay is not supported - local ISAPI only. Two-way audio (G.711u) is supported on compatible cameras via POST /api/v1/cameras/{id}/audio/start and POST /api/v1/cameras/{id}/audio/stop.

DGCBRRTSSSRFRG

See Adapter Contract for what each column means.

  • Hikvision camera or NVR firmware V4.x or later (ISAPI support)
  • HTTP (port 80) or HTTPS (port 443) access from the FreeSDN host
  • An admin-level account or a dedicated operator account with remote login enabled
  1. In FreeSDN, open Video Surveillance → Cameras and click Add Camera.
  2. Select vendor Hikvision, enter the camera IP/hostname, port, and credentials.
  3. FreeSDN tests the ISAPI connection. On success the camera appears in the camera list.

To add via the API directly:

Terminal window
# Add the camera - supply credentials directly in the same request body
curl -X POST https://freesdn.example.com/api/v1/cameras/ \
-H "Cookie: freesdn_access=<token>" \
-H "X-CSRF-Token: <csrf>" \
-H "Content-Type: application/json" \
-d '{
"name": "Lobby",
"ip_address": "10.0.1.50",
"port": 80,
"vendor": "hikvision",
"username": "freesdn",
"password": "s3cr3t",
"site_id": "<site-uuid>"
}'

The NVR import wizard is a four-step process: test connection → discover channels → configure → import.

Terminal window
curl -X POST https://freesdn.example.com/api/v1/cameras/nvrs/test-connection \
-H "Cookie: freesdn_access=<token>" \
-H "X-CSRF-Token: <csrf>" \
-H "Content-Type: application/json" \
-d '{
"host": "10.0.1.64",
"port": 80,
"username": "freesdn",
"password": "s3cr3t"
}'

Response includes device_name, model, firmware_version, serial_number.

Terminal window
curl -X POST https://freesdn.example.com/api/v1/cameras/nvrs/discover \
-H "Cookie: freesdn_access=<token>" \
-H "X-CSRF-Token: <csrf>" \
-H "Content-Type: application/json" \
-d '{
"host": "10.0.1.64",
"port": 80,
"username": "freesdn",
"password": "s3cr3t"
}'

Returns a channels list (channel ID, name, online status, PTZ flag, RTSP main/sub URLs) and a storage summary (total/used GB per disk).

The adapter queries three ISAPI endpoints in order and uses the first that responds:

  1. GET /ISAPI/ContentMgmt/InputProxy/channels (most NVRs)
  2. GET /ISAPI/System/Video/inputs/channels
  3. GET /ISAPI/Streaming/channels (fallback)
Terminal window
curl -X POST https://freesdn.example.com/api/v1/cameras/nvrs/import \
-H "Cookie: freesdn_access=<token>" \
-H "X-CSRF-Token: <csrf>" \
-H "Content-Type: application/json" \
-d '{
"host": "10.0.1.64",
"port": 80,
"username": "freesdn",
"password": "s3cr3t",
"site_id": "<site-uuid>",
"name": "Office NVR",
"selected_channels": [1, 2, 3, 4]
}'

selected_channels is optional - omit it to import all enabled channels. The import is idempotent on external_device_id; re-importing the same NVR automatically re-syncs its channels and returns a normal 201 response with "synced": true - no error is raised and no manual sync call is required.

After the initial import, sync re-queries the NVR for current channels, adds new cameras, marks missing cameras offline, and updates storage stats:

Terminal window
curl -X POST https://freesdn.example.com/api/v1/cameras/nvrs/<nvr-uuid>/sync \
-H "Cookie: freesdn_access=<token>" \
-H "X-CSRF-Token: <csrf>"

Returns {"added": N, "removed": N, "updated": N}.

The adapter constructs RTSP URLs using Hikvision’s NVR channel-numbering convention:

StreamURL pattern
Main stream, channel Nrtsp://user:pass@{host}:554/Streaming/Channels/{N*100+1}
Sub stream, channel Nrtsp://user:pass@{host}:554/Streaming/Channels/{N*100+2}
Standalone camera mainrtsp://user:pass@{host}:554/Streaming/Channels/101

Snapshot:

GET /ISAPI/Streaming/channels/{N*100+1}/picture

PTZ is available on supported cameras via the cameras module:

Terminal window
# Continuous move (pan right) - action and speed are query params
curl -X POST 'https://freesdn.example.com/api/v1/cameras/<id>/ptz?action=right&speed=50' \
-H "Cookie: freesdn_access=<token>" \
-H "X-CSRF-Token: <csrf>"
# Go to a saved preset - action=preset with the preset number as a query param
curl -X POST 'https://freesdn.example.com/api/v1/cameras/<id>/ptz?action=preset&preset=1' \
-H "Cookie: freesdn_access=<token>" \
-H "X-CSRF-Token: <csrf>"
# Save (set) a new preset at the current camera position - preset number and name are query params
curl -X POST 'https://freesdn.example.com/api/v1/cameras/<id>/ptz/presets?preset=1&name=Lobby+Default' \
-H "Cookie: freesdn_access=<token>" \
-H "X-CSRF-Token: <csrf>"

Search recordings by time range:

Terminal window
curl -H "Cookie: freesdn_access=<token>" -H "X-CSRF-Token: <csrf>" \
"https://freesdn.example.com/api/v1/cameras/recordings/search?camera_id=<id>&start_time=2026-06-01T00:00:00Z&end_time=2026-06-01T06:00:00Z"

Returns a list of recording segments with start/end times and a playback URL per segment.

The adapter subscribes to the long-poll ISAPI alertStream and ingests motion, line-crossing, intrusion, and LPR events into the FreeSDN event bus. Events appear on the Events page and can trigger Fabric connections.

  • Credentials are encrypted at rest with Fernet (derived from ENCRYPTION_SALT).
  • Adapter responses are passed through the central redact_secrets function (~89 sensitive keys plus Proxmox ipconfig0-ipconfig31 prefix patterns, camelCase-aware) before returning to the UI. Any credential-bearing fields in ISAPI responses are stripped at this layer.
  • Channel IDs, track IDs, and snapshot IDs are validated ([0-9]+, bounded) before being interpolated into ISAPI URL paths.
  • SSRF guard: the NVR host field is validated to block loopback, link-local, and cloud metadata endpoints. RFC 1918 private ranges are allowed by default (on-prem deployments). Set BLOCK_PRIVATE_CAMERA_SUBNETS=1 to also block private ranges; use ALLOWED_CAMERA_SUBNETS (comma-separated CIDRs) to add custom allowlist entries.
  • CamerasPage - camera grid with live thumbnail previews
  • CameraDetailPage - live stream, PTZ, events, recordings tabs
  • CameraWallPage - multi-camera wall view
  • NVRListPage / NVRDetailPage - NVR list and per-NVR channel view
  • MultiPlaybackPage - synchronized multi-channel playback

All cameras-module endpoints mount under /api/v1/cameras/. Sub-routers include nvrs, events, groups, views, recording-templates, access, streams/hls, reports, and lpr.