Skip to main content

PTZ Camera Control API (Pan Tilt Zoom)

Viewtron PTZ cameras can be controlled programmatically via HTTP API — pan, tilt, zoom, focus, iris, presets, and cruise tours. Unlike the webhook-based detection features, PTZ control uses outbound HTTP requests that you send to the camera. Any programming language or tool that can make HTTP requests (Python, JavaScript, curl, mobile apps) can control PTZ movement in real time.

The API supports continuous movement commands with adjustable speed (1-8), preset positions for instant recall, and cruise tours that cycle through multiple presets automatically. Viewtron PTZ cameras also include AI auto-tracking, which can be combined with the real-time traject data for intelligent tracking applications.

What You Can Build

  • Remote camera control apps — build a web or mobile interface to pan, tilt, and zoom cameras from anywhere
  • Automated patrol routes — program cruise tours that cycle through preset positions on a schedule
  • Event-driven camera positioning — move the PTZ to a preset position when an alarm triggers on another camera
  • Integration with VMS software — add PTZ control to custom video management systems
  • Auto-tracking override — programmatically interrupt or redirect auto-tracking when needed
  • Multi-camera coordination — move multiple PTZ cameras to coordinated positions simultaneously
  • Tour guide systems — create scripted camera movements for demonstrations or presentations

How It Works

  1. Install a PTZ camera — Viewtron PTZ cameras connect via standard IP networking
  2. Query capabilities — use PtzGetCaps to discover speed range, preset count, and cruise limits
  3. Send movement commands — POST to PtzControl with the desired direction and speed
  4. Use presets — save positions with PtzAddPreset and recall them instantly with PtzGotoPreset
  5. Run cruise tours — configure tours in the camera UI, then start/stop them via API with PtzRunCruise and PtzStopCruise
  6. Stop movement — send the Stop action to halt any current movement

PTZ Control Commands

Movement Actions

All movement commands use the same URL pattern: POST http://<host>/PtzControl[/channelId]/<action>

ActionDescription
UpTilt up
DownTilt down
LeftPan left
RightPan right
LeftUpPan left and tilt up simultaneously
LeftDownPan left and tilt down simultaneously
RightUpPan right and tilt up simultaneously
RightDownPan right and tilt down simultaneously
ZoomInZoom in (telephoto)
ZoomOutZoom out (wide angle)
NearFocus near
FarFocus far
IrisOpenOpen iris (brighter)
IrisCloseClose iris (darker)
StopStop all current movement

Preset Commands

CommandURLMethodDescription
PtzGotoPreset/PtzGotoPreset[/channelId]POSTMove to a saved preset position
PtzGetPresets/PtzGetPresets[/channelId]POST/GETList all saved presets
PtzAddPreset/PtzAddPreset[/channelId]POSTSave the current position as a preset
PtzDeletePreset/PtzDeletePreset[/channelId]POSTDelete a saved preset

Cruise Tour Commands

CommandURLMethodDescription
PtzGetCruises/PtzGetCruises[/channelId]POST/GETList configured cruise tours
PtzRunCruise/PtzRunCruise[/channelId]POSTStart a cruise tour
PtzStopCruise/PtzStopCruise[/channelId]POSTStop the running cruise tour

PTZ Capabilities

Use PtzGetCaps to query the camera's PTZ limits before sending commands:

<?xml version="1.0" encoding="UTF-8"?>
<config version="2.0.0" xmlns="http://www.ipc.com/ver10">
<caps>
<controlMinSpeed type="uint32">1</controlMinSpeed>
<controlMaxSpeed type="uint32">8</controlMaxSpeed>
<presetMaxCount type="uint32">255</presetMaxCount>
<cruiseMaxCount type="uint32">8</cruiseMaxCount>
<cruisePresetMinSpeed type="uint32">1</cruisePresetMinSpeed>
<cruisePresetMaxSpeed type="uint32">8</cruisePresetMaxSpeed>
<cruisePresetMaxHoldTime type="uint32">240</cruisePresetMaxHoldTime>
<cruisePresetMaxCount type="uint32">16</cruisePresetMaxCount>
</caps>
</config>
FieldDescriptionTypical Value
controlMinSpeed / controlMaxSpeedMovement speed range1 - 8
presetMaxCountMaximum saved presets255
cruiseMaxCountMaximum cruise tours8
cruisePresetMaxCountMaximum presets per cruise tour16
cruisePresetMaxHoldTimeMaximum seconds at each preset240

XML Request/Response Examples

PtzControl — Move Camera

<!-- POST http://<host>/PtzControl/1/Right -->
<?xml version="1.0" encoding="utf-8"?>
<actionInfo version="1.0" xmlns="http://www.ipc.com/ver10">
<speed>4</speed>
</actionInfo>

PtzGotoPreset — Go to Preset

<!-- POST http://<host>/PtzGotoPreset/1 -->
<?xml version="1.0" encoding="utf-8"?>
<presetInfo version="1.0" xmlns="http://www.ipc.com/ver10">
<id>2</id>
</presetInfo>

PtzAddPreset — Save Current Position

<!-- POST http://<host>/PtzAddPreset/1 -->
<?xml version="1.0" encoding="utf-8"?>
<presetInfo version="1.0" xmlns="http://www.ipc.com/ver10">
<name><![CDATA[Front Gate]]></name>
</presetInfo>

PtzGetPresets — List Saved Presets

<!-- Response from GET http://<host>/PtzGetPresets/1 -->
<?xml version="1.0" encoding="UTF-8"?>
<config version="1.0" xmlns="http://www.ipc.com/ver10">
<presetInfo type="list" maxCount="360">
<itemType type="string" maxLen="10"></itemType>
<item id="1"><![CDATA[Front Gate]]></item>
<item id="2"><![CDATA[Parking Lot]]></item>
<item id="3"><![CDATA[Loading Dock]]></item>
</presetInfo>
</config>

Quick Start Example

This standalone script demonstrates PTZ camera control using Python and the requests library with Basic Auth:

#!/usr/bin/env python3
"""PTZ Camera Controller — Viewtron IP Camera API"""

import requests
from requests.auth import HTTPDigestAuth
import xml.etree.ElementTree as ET
import time

# pip install requests

# Camera connection settings
CAMERA_IP = "192.168.1.108"
CAMERA_PORT = 80
USERNAME = "admin"
PASSWORD = "your_password"
CHANNEL = 1

BASE_URL = f"http://{CAMERA_IP}:{CAMERA_PORT}"
AUTH = HTTPDigestAuth(USERNAME, PASSWORD)


def ptz_get_caps():
"""Get PTZ capabilities (speed range, preset count, cruise limits)."""
url = f"{BASE_URL}/PtzGetCaps/{CHANNEL}"
resp = requests.get(url, auth=AUTH, timeout=5)
resp.raise_for_status()
print("PTZ Capabilities:")
print(resp.text)
return resp.text


def ptz_move(action, speed=4, duration=1.0):
"""Move the camera in a direction for a specified duration.

Actions: Up, Down, Left, Right, LeftUp, LeftDown, RightUp, RightDown,
ZoomIn, ZoomOut, Near, Far, IrisOpen, IrisClose, Stop
Speed: 1 (slowest) to 8 (fastest)
"""
url = f"{BASE_URL}/PtzControl/{CHANNEL}/{action}"
xml_body = (
'<?xml version="1.0" encoding="utf-8"?>\n'
'<actionInfo version="1.0" xmlns="http://www.ipc.com/ver10">\n'
f' <speed>{speed}</speed>\n'
'</actionInfo>'
)
resp = requests.post(url, data=xml_body, auth=AUTH,
headers={'Content-Type': 'application/xml'}, timeout=5)
resp.raise_for_status()
print(f"Moving: {action} (speed {speed})")

if action != "Stop" and duration > 0:
time.sleep(duration)
ptz_stop()


def ptz_stop():
"""Stop all PTZ movement."""
url = f"{BASE_URL}/PtzControl/{CHANNEL}/Stop"
xml_body = (
'<?xml version="1.0" encoding="utf-8"?>\n'
'<actionInfo version="1.0" xmlns="http://www.ipc.com/ver10">\n'
' <speed>1</speed>\n'
'</actionInfo>'
)
requests.post(url, data=xml_body, auth=AUTH,
headers={'Content-Type': 'application/xml'}, timeout=5)
print("Stopped.")


def ptz_goto_preset(preset_id):
"""Move the camera to a saved preset position."""
url = f"{BASE_URL}/PtzGotoPreset/{CHANNEL}"
xml_body = (
'<?xml version="1.0" encoding="utf-8"?>\n'
'<presetInfo version="1.0" xmlns="http://www.ipc.com/ver10">\n'
f' <id>{preset_id}</id>\n'
'</presetInfo>'
)
resp = requests.post(url, data=xml_body, auth=AUTH,
headers={'Content-Type': 'application/xml'}, timeout=5)
resp.raise_for_status()
print(f"Going to preset {preset_id}")


def ptz_add_preset(name):
"""Save the current camera position as a named preset."""
url = f"{BASE_URL}/PtzAddPreset/{CHANNEL}"
xml_body = (
'<?xml version="1.0" encoding="utf-8"?>\n'
'<presetInfo version="1.0" xmlns="http://www.ipc.com/ver10">\n'
f' <name><![CDATA[{name}]]></name>\n'
'</presetInfo>'
)
resp = requests.post(url, data=xml_body, auth=AUTH,
headers={'Content-Type': 'application/xml'}, timeout=5)
resp.raise_for_status()
print(f"Saved preset: {name}")


def ptz_get_presets():
"""List all saved preset positions."""
url = f"{BASE_URL}/PtzGetPresets/{CHANNEL}"
resp = requests.get(url, auth=AUTH, timeout=5)
resp.raise_for_status()
print("Saved Presets:")

root = ET.fromstring(resp.text)
ns = {'ns': 'http://www.ipc.com/ver10'}
for item in root.findall('.//ns:presetInfo/ns:item', ns):
preset_id = item.get('id')
name = item.text or '(unnamed)'
print(f" Preset {preset_id}: {name}")
return resp.text


def ptz_run_cruise(cruise_id):
"""Start a cruise tour."""
url = f"{BASE_URL}/PtzRunCruise/{CHANNEL}"
xml_body = (
'<?xml version="1.0" encoding="utf-8"?>\n'
'<cruiseInfo version="1.0" xmlns="http://www.ipc.com/ver10">\n'
f' <id>{cruise_id}</id>\n'
'</cruiseInfo>'
)
resp = requests.post(url, data=xml_body, auth=AUTH,
headers={'Content-Type': 'application/xml'}, timeout=5)
resp.raise_for_status()
print(f"Started cruise tour {cruise_id}")


def ptz_stop_cruise():
"""Stop the running cruise tour."""
url = f"{BASE_URL}/PtzStopCruise/{CHANNEL}"
resp = requests.post(url, data=b'', auth=AUTH, timeout=5)
resp.raise_for_status()
print("Stopped cruise tour")


if __name__ == '__main__':
# 1. Check PTZ capabilities
ptz_get_caps()
print()

# 2. List saved presets
ptz_get_presets()
print()

# 3. Pan right for 2 seconds at speed 4, then stop
ptz_move("Right", speed=4, duration=2.0)
print()

# 4. Zoom in for 1 second
ptz_move("ZoomIn", speed=3, duration=1.0)
print()

# 5. Go to preset 1
ptz_goto_preset(1)
print()

# 6. Save current position as a new preset
# ptz_add_preset("API Test Position")

# 7. Run cruise tour 1
# ptz_run_cruise(1)
# time.sleep(30)
# ptz_stop_cruise()

To run:

pip install requests
python3 ptz_controller.py

Update the CAMERA_IP, USERNAME, and PASSWORD variables with your camera's credentials.

Relevant API Endpoints

EndpointPurposeReference
PtzGetCapsQuery speed range, preset count, cruise limitsPTZ Commands
PtzControlMove camera (pan, tilt, zoom, focus, iris, stop)PTZ Commands
PtzGotoPresetMove to a saved preset positionPTZ Presets
PtzGetPresetsList all saved presetsPTZ Presets
PtzAddPresetSave current position as a named presetPTZ Presets
PtzDeletePresetDelete a saved presetPTZ Presets
PtzGetCruisesList configured cruise toursPTZ Cruise Tours
PtzRunCruiseStart a cruise tourPTZ Cruise Tours
PtzStopCruiseStop the running cruise tourPTZ Cruise Tours
Auto-Tracking PTZ

Viewtron PTZ cameras include AI auto-tracking that automatically follows detected targets. When auto-tracking is active, the camera moves to keep the target centered in the frame. You can combine PTZ API control with real-time traject data to build intelligent tracking applications that coordinate multiple cameras or override tracking behavior programmatically.

Questions & Development Inquiries

Mike Haldas is available for questions, consultation, and custom software development for Viewtron API related projects. Email details about your project to mike@viewtron.com.