Skip to main content
The UDP protocol transmits raw head tracking data over a network using UDP packets. This is useful for custom applications, development, external tools, or networked tracking setups.

How It Works

The UDP protocol:
  1. Creates a UDP socket bound to any local address
  2. Packages 6DOF tracking data into a binary format
  3. Sends UDP datagrams to a configured IP address and port
  4. Data is sent in real-time with minimal overhead

Data Format

Each UDP packet contains 48 bytes of binary data:
// Six double-precision floats (8 bytes each)
double data[6] = {
    headpose[Yaw],    // 0-7:   Yaw in degrees
    headpose[Pitch],  // 8-15:  Pitch in degrees  
    headpose[Roll],   // 16-23: Roll in degrees
    headpose[TX],     // 24-31: X position in cm
    headpose[TY],     // 32-39: Y position in cm
    headpose[TZ]      // 40-47: Z position in cm
};
Byte order: Native (host) byte order Packet size: 48 bytes No header or checksum - pure tracking data

Use Cases

Custom Applications

Game Development

Integrate head tracking into your own game or application

Research Tools

Collect tracking data for analysis or machine learning

Visualization

Real-time visualization of head movements

Networked Tracking

Run OpenTrack on one PC, game on another

Integration Examples

  • Unity/Unreal Engine: Read UDP data for camera control
  • Python scripts: Process tracking data for analysis
  • Arduino/Raspberry Pi: Control hardware based on head position
  • OBS Studio: Dynamic camera control for streaming
  • VR applications: Hybrid tracking systems

Setup Instructions

1

Select UDP protocol

In OpenTrack, go to the Output dropdown and select “UDP over network”.
2

Configure network settings

Click the settings button next to the Output dropdown.Network configuration:
  • IP Address: Destination IP (where to send data)
    • Default: 192.168.0.2
    • For same computer: 127.0.0.1
    • For network: Enter target PC’s IP
  • Port: UDP port number
    • Default: 4242
    • Choose any available port (1024-65535)
3

Start OpenTrack

Click Start. OpenTrack will:
  • Bind a UDP socket
  • Begin sending tracking data to configured address
  • Send packets at tracking input rate (typically 50-60 Hz)
4

Receive data in your application

Implement UDP receiver in your application. See code examples below.

Configuration

Default Settings

IP Address: 192.168.0.2
Port: 4242

Network Modes

Localhost (same computer):
IP: 127.0.0.1
Port: 4242
Local network:
IP: 192.168.1.100 (target PC's LAN IP)
Port: 4242
Remote/Internet:
IP: <public IP or hostname>
Port: <forwarded port>
For internet transmission:
  • Configure port forwarding on router
  • Use firewall exceptions
  • Consider security implications of exposing UDP port
  • Data is sent unencrypted

Receiving Data

Python Example

import socket
import struct

# Create UDP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('0.0.0.0', 4242))  # Listen on all interfaces, port 4242

print("Listening for OpenTrack UDP data on port 4242...")

while True:
    # Receive packet
    data, addr = sock.recvfrom(1024)
    
    # Unpack 6 doubles (48 bytes)
    if len(data) == 48:
        yaw, pitch, roll, x, y, z = struct.unpack('dddddd', data)
        
        print(f"Yaw: {yaw:7.2f}°  Pitch: {pitch:7.2f}°  Roll: {roll:7.2f}°  "
              f"X: {x:6.1f}cm  Y: {y:6.1f}cm  Z: {z:6.1f}cm")

C++ Example

#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>

#pragma comment(lib, "ws2_32.lib")

struct TrackingData {
    double yaw, pitch, roll;
    double x, y, z;
};

int main() {
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);
    
    // Create socket
    SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    
    // Bind to port
    sockaddr_in addr{};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(4242);
    addr.sin_addr.s_addr = INADDR_ANY;
    bind(sock, (sockaddr*)&addr, sizeof(addr));
    
    std::cout << "Listening on port 4242...\n";
    
    while (true) {
        TrackingData data;
        int received = recvfrom(sock, (char*)&data, sizeof(data), 
                                0, nullptr, nullptr);
        
        if (received == sizeof(data)) {
            std::cout << "Yaw: " << data.yaw 
                     << "  Pitch: " << data.pitch 
                     << "  Roll: " << data.roll << "\n";
        }
    }
    
    closesocket(sock);
    WSACleanup();
}

Unity C# Example

using UnityEngine;
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;

public class OpenTrackReceiver : MonoBehaviour
{
    private UdpClient udpClient;
    private Thread receiveThread;
    
    public float yaw, pitch, roll;
    public float x, y, z;
    
    void Start()
    {
        udpClient = new UdpClient(4242);
        receiveThread = new Thread(ReceiveData);
        receiveThread.Start();
    }
    
    void ReceiveData()
    {
        IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, 0);
        
        while (true)
        {
            try
            {
                byte[] data = udpClient.Receive(ref endpoint);
                
                if (data.Length == 48)  // 6 doubles
                {
                    yaw   = BitConverter.ToDouble(data, 0);
                    pitch = BitConverter.ToDouble(data, 8);
                    roll  = BitConverter.ToDouble(data, 16);
                    x     = BitConverter.ToDouble(data, 24);
                    y     = BitConverter.ToDouble(data, 32);
                    z     = BitConverter.ToDouble(data, 40);
                }
            }
            catch (Exception e)
            {
                Debug.LogError("UDP Error: " + e.Message);
            }
        }
    }
    
    void OnDestroy()
    {
        receiveThread?.Abort();
        udpClient?.Close();
    }
    
    void Update()
    {
        // Use tracking data to control camera
        transform.rotation = Quaternion.Euler(-pitch, yaw, -roll);
        transform.position = new Vector3(x/100f, y/100f, z/100f);
    }
}

Data Interpretation

Coordinate System

Rotation (degrees):
  • Yaw: Left (-) / Right (+)
  • Pitch: Down (-) / Up (+)
  • Roll: Left (-) / Right (+)
Position (centimeters):
  • X: Left (-) / Right (+)
  • Y: Down (-) / Up (+)
  • Z: Back (-) / Forward (+)

Typical Value Ranges

AxisTypical RangeUnits
Yaw-180 to +180degrees
Pitch-90 to +90degrees
Roll-180 to +180degrees
X-30 to +30cm
Y-20 to +20cm
Z-20 to +20cm
Actual ranges depend on OpenTrack mapping settings. Users can configure custom ranges.

Troubleshooting

”Can’t bind socket” Error

Cause: Another application is using the port, or permission denied. Solution:
  1. Check if another program is using the port:
    • Windows: netstat -ano | findstr :4242
    • Linux: netstat -tulpn | grep 4242
  2. Try a different port number
  3. Run OpenTrack as administrator
  4. Check firewall settings

Not Receiving Data

Symptoms: Application receives no UDP packets. Solution:
  1. Verify OpenTrack is sending:
    • Check OpenTrack status shows “Running”
    • Verify settings show correct IP and port
  2. Check firewall:
    • Add exception for OpenTrack
    • Allow inbound UDP on chosen port
    • Temporarily disable firewall to test
  3. Network connectivity:
    • Ping target IP to verify connectivity
    • Ensure both PCs on same network
    • Check router doesn’t block UDP
  4. Wireshark capture:
    • Use Wireshark to verify packets are being sent
    • Filter: udp.port == 4242

Wrong Byte Order

Symptoms: Values are nonsensical or extremely large. Cause: Byte order mismatch between sender and receiver. Solution:
  • OpenTrack sends in host byte order
  • If sender and receiver have different architectures:
    // Convert to network byte order (big-endian)
    double value = ...;
    uint64_t* ptr = (uint64_t*)&value;
    *ptr = htobe64(*ptr);  // Host to big-endian
    

High Latency

Cause: Network congestion or WiFi interference. Solution:
  • Use wired Ethernet instead of WiFi
  • Reduce other network traffic
  • Check for packet loss with ping statistics
  • Consider lowering OpenTrack update rate

Packet Loss

Symptoms: Intermittent or choppy tracking. Solution:
  • UDP doesn’t guarantee delivery - this is normal
  • For critical applications, implement your own packet numbering
  • Monitor packet loss rate
  • Consider TCP if reliability is required (custom implementation needed)

Advanced Usage

Multiple Receivers

Send to multiple destinations:
  1. Use broadcast address:
    IP: 192.168.1.255
    
  2. Or run multiple OpenTrack instances with different ports
  3. Or implement UDP forwarding in your receiver

Custom Protocol Extension

Add metadata to packets:
# Example: Add timestamp and packet ID
import struct
import time

# Receive OpenTrack data
data, addr = sock.recvfrom(1024)
yaw, pitch, roll, x, y, z = struct.unpack('dddddd', data)

# Add metadata
timestamp = time.time()
packet_id = get_next_packet_id()

# Store or forward with metadata
extended_data = struct.pack('ddddddQI', 
    yaw, pitch, roll, x, y, z, 
    int(timestamp * 1000000), packet_id
)

Data Recording

Record tracking sessions:
import csv
import time

with open('tracking_log.csv', 'w', newline='') as f:
    writer = csv.writer(f)
    writer.writerow(['timestamp', 'yaw', 'pitch', 'roll', 'x', 'y', 'z'])
    
    while True:
        data, _ = sock.recvfrom(1024)
        if len(data) == 48:
            values = struct.unpack('dddddd', data)
            writer.writerow([time.time()] + list(values))

Performance Characteristics

Bandwidth Usage

At typical 60 Hz update rate:
  • Packet size: 48 bytes
  • Packets per second: 60
  • Bandwidth: ~23 Kbps
  • With IP/UDP overhead: ~31 Kbps
Very low bandwidth - suitable for network transmission.

Latency

Local (127.0.0.1):
  • Latency: <1ms
  • Perfect for same-machine applications
LAN (wired):
  • Latency: 1-3ms
  • Excellent for networked setups
LAN (WiFi):
  • Latency: 5-20ms
  • May have jitter and packet loss
Internet:
  • Latency: Varies greatly
  • Not recommended for real-time use
The UDP protocol provides maximum flexibility for custom applications and development. For standard gaming use cases, prefer FreeTrack or SimConnect protocols for better game compatibility.