Cursor on Target (CoT) is an XML-based message format developed by the US Air Force Research Laboratory in the early 2000s to solve a specific problem: how do you share the position, identity, and status of a target or unit between heterogeneous military systems that were not designed to interoperate? CoT's answer was a minimal, extensible XML schema that any system could produce and consume, with no central registry or coordination authority required.

Two decades later, CoT has become the de facto standard for position reporting and event sharing in the tactical edge ecosystem. ATAK (Android Team Awareness Kit), WinTAK, iTAK, TAK Server, and hundreds of plugins and custom integrations all speak CoT. Any defense software that needs to exchange position data with tactical field systems will need to generate or consume CoT messages. This article explains the format in detail and shows how to implement a CoT parser and generator.

What CoT Is and How It Became the De Facto Standard

CoT achieved dominance not through a formal standardization process but through organic adoption driven by operational utility. The Air Force Research Laboratory released the format as part of its "Cursor on Target" concept — the idea that any sensor should be able to cue any weapon or display by sharing a common data structure describing a target. The simplicity of the XML format, combined with its extensibility and the absence of licensing restrictions, enabled rapid adoption.

The critical enabling factor was ATAK's adoption of CoT as its internal and external data format. ATAK became the dominant dismounted soldier situational awareness application, and because everything ATAK produces is a CoT event, any system that integrates with ATAK must speak CoT. The format spread from ATAK to UAV ground control stations, vehicle-mounted BMS displays, command post software, and web-based COP systems. By the mid-2010s, building a tactical software system that did not support CoT was a significant integration liability.

XML Structure: Event, Point, Detail Elements

A CoT message is an XML document with a single root element: <event>. Every CoT message is an event, regardless of whether it describes a position update, a sensor report, a chat message, or a mission task. The event element carries several mandatory attributes that identify the event type, source, and time window.

A minimal CoT position report looks like this:

<event version="2.0"
       uid="ALPHA-1-1"
       type="a-f-G-U-C"
       how="m-g"
       time="2026-05-11T08:30:00.000Z"
       start="2026-05-11T08:30:00.000Z"
       stale="2026-05-11T08:31:00.000Z">
  <point lat="48.3794"
         lon="31.1656"
         hae="150.0"
         ce="10.0"
         le="5.0"/>
  <detail>
    <contact callsign="ALPHA-1-1"/>
    <group name="Cyan" role="Team Member"/>
    <status battery="85"/>
    <track speed="0.0" course="270.0"/>
  </detail>
</event>

Breaking down the key attributes:

uid: A globally unique identifier for the entity being reported. The UID persists across all reports for the same entity. For a soldier using ATAK, the UID is typically derived from the device's hardware identifier. For a UAV, the UID is typically the airframe serial number. UID uniqueness is enforced by convention, not by a registry — implementations should use a meaningful, collision-resistant UID scheme (for example: <callsign>-<unit>-<device-hash>).

type: A hierarchical string encoding the entity classification. The type string uses a dot-separated hierarchy: the first character encodes the affiliation domain (a = atoms, meaning physical entities), the second segment encodes affiliation (f = friendly, h = hostile, n = neutral, u = unknown), the third segment encodes domain (G = ground, A = air, S = sea, U = subsurface), and subsequent segments encode unit type. The type a-f-G-U-C decodes as: atom, friendly, ground, unit, combat. The type a-h-A decodes as: atom, hostile, air.

time / start / stale: Three ISO 8601 UTC timestamps that define when the event was generated (time), when the reported state became valid (start), and when the report should be considered expired (stale). The stale time is critical — a consumer should stop displaying an entity or reduce its visual confidence when the current time exceeds the stale timestamp. Setting stale appropriately is a common source of errors: a report with a stale time 24 hours in the future will linger on the COP indefinitely after the source goes offline.

point: The position of the entity in WGS84 coordinates. lat and lon are in decimal degrees. hae is height above the WGS84 ellipsoid in meters (not height above mean sea level — be aware of this distinction when integrating with systems that use MSL). ce and le are circular error and linear error — the 1-sigma position uncertainty in meters horizontally and vertically, respectively.

detail: An extensible XML element that carries application-specific data. The detail element has no fixed schema — any child elements are valid. The TAK ecosystem defines a set of well-known detail sub-elements (contact, group, status, track, precisionlocation) that ATAK recognizes and displays. Custom plugins add their own detail sub-elements.

CoT Types: Classification Hierarchy

The CoT type hierarchy is the most important aspect of the format for a C2 system developer. The type string determines how the receiving system classifies, symbolizes, and handles the event. A few critical type prefixes:

a-f-G (Friendly Ground): Friendly ground unit. Rendered with blue rectangle symbol per MIL-STD-2525. All friendly dismounted and mounted units use this prefix, with additional segments specifying unit type.

a-h-G (Hostile Ground): Hostile ground unit. Rendered with red diamond symbol. Track reported by a sensor with hostile assessment.

a-u-G (Unknown Ground): Unknown affiliation ground contact. Rendered with yellow question mark. Used for unidentified radar contacts and for contacts where affiliation has not been assessed.

a-f-A (Friendly Air): Friendly air track. Used for friendly UAVs, helicopters, and fixed-wing aircraft.

b-m-p-s-p-loc: A mission planning waypoint — part of the broadcast/management type hierarchy. Used for route planning and mission overlay sharing.

t-x-c-t: A GeoChat message. ATAK uses CoT to transmit text messages between users; the type hierarchy identifies the event as a communication event rather than a position report.

TAK Server: Routing, Filtering, and Federation

TAK Server is the server-side component of the TAK ecosystem. It receives CoT messages from connected clients (ATAK devices, WinTAK instances, custom integrations) and routes them to other connected clients based on configurable rules. A basic TAK Server deployment enables all connected clients to see all CoT events from all other connected clients — a flat broadcast model.

For operational deployments, filtering and federation are essential. Data packages (configuration files distributed to clients) control which clients connect to which TAK Server instances. Groups limit which clients can see which events — assigning clients to a group means they only receive events from other clients in the same group. Enterprise Sync allows mission packages, maps, and configuration data to be distributed from the TAK Server to connected clients.

Federation connects multiple TAK Server instances, enabling CoT events to flow between server instances in different geographic locations or at different security levels. A TAK Server at battalion level can federate with a TAK Server at brigade level, with federation rules controlling which event types cross the boundary. Federation is the mechanism by which lower-echelon positions become visible on higher-echelon COP systems without requiring direct client connections to the higher system.

Implementation in Python: Parsing and Generating CoT

The Python ecosystem has several CoT libraries. The pytak library (maintained by the TAK community) provides a complete implementation of CoT event generation and a queue-based architecture for integrating with TAK Server. For parsing, Python's standard xml.etree.ElementTree is sufficient; for production, lxml with XSD validation is recommended.

Generating a position report:

import uuid
from datetime import datetime, timezone, timedelta
import xml.etree.ElementTree as ET

def generate_cot_position(uid, callsign, lat, lon, hae, affiliation="f", domain="G"):
    now = datetime.now(timezone.utc)
    stale = now + timedelta(minutes=1)
    fmt = "%Y-%m-%dT%H:%M:%S.000Z"

    event = ET.Element("event", {
        "version": "2.0",
        "uid": uid,
        "type": f"a-{affiliation}-{domain}-U-C",
        "how": "m-g",
        "time": now.strftime(fmt),
        "start": now.strftime(fmt),
        "stale": stale.strftime(fmt)
    })
    ET.SubElement(event, "point", {
        "lat": str(lat),
        "lon": str(lon),
        "hae": str(hae),
        "ce": "10.0",
        "le": "5.0"
    })
    detail = ET.SubElement(event, "detail")
    ET.SubElement(detail, "contact", {"callsign": callsign})
    ET.SubElement(detail, "track", {"speed": "0.0", "course": "0.0"})
    return ET.tostring(event, encoding="unicode")

Connecting to a TAK Server over TCP and sending a CoT event requires establishing a TCP socket connection to port 8087 (or TLS on 8089) and writing the XML string followed by a null terminator byte (\x00 or \n depending on server version). The pytak library abstracts this and also supports multicast UDP for network-local deployments.

Stale time guidance: Set the stale time to approximately 2× the expected update interval for the entity type. For a dismounted soldier updating every 30 seconds, stale should be 60 seconds. For a UAV updating at 1 Hz, stale should be 5–10 seconds. A stale time that is too long causes ghost tracks to persist on the COP after an entity goes offline; a stale time that is too short causes valid tracks to flicker when updates are delayed by network jitter.