Flow Telemetry
The Flow telemetry record contains per-flow metadata produced by the DPI engine and flow tracker. Emitted at detection and during DPI updates and completion, it reports detected application and protocol identifiers, hostnames (SNI/HTTP Host), TLS certificate details, and protocol-specific metadata used for classification and enrichment.
Use the Flow record for event-driven detection, enrichment, routing decisions, and early-alerting workflows. For periodic bandwidth and KPI reporting use the flow_stats telemetry, and for final per-session counters and end-state details use the flow_purge record.
See the telemetry direction conventions for information on loca meanings of local_ and other_ prefixes.
Requirements
Flow telemetry was introduced in the Core Plugin in version 1.0.20. To begin streaming the telemetry:
- Install and configure the Netify Agent
- Install and configure a Sink Plugin for receiving the telemetry
- Install and configure the Core Plugin and add stream-flows to types
- Source
- Core Plugin
- Plugin Release
- 1.0.20
Flow Detection Lifecycle
The flow record format is used by three different stages of the flow detection lifecycle:
- flow
- Triggers the moment a new flow is detected.
- flow_dpi_update
- Triggers on a mid-stream refinement, for example, a TLS certificate detail after deeper packet analysis.
- flow_dpi_complete
- Marks the exact point the DPI engine has completed the flow analysis.
In most cases, the flow_dpi_complete is the only stage that you should be using for flow bandwidth stats and analytics. The flow and flow_dpi_update stages are typically used for special early-detection use cases involving routing, firewalling and QoS.
Optimizations
Flow Digests
The digest is a 7-tuple derived from the following flow properties:
- source IP
- destination IP
- source port
- destination port
- IP protocol (TCP, UDP, etc)
- VLAN ID
- network interface
As protocol dissection and classification occurs, additional properties are added to the digest and tracked in the digest_prev array. As an integrator, the only value of interest is the very first index (0), which will always be the 7-tuple digest that will never change over the entire duration of the flow tracking. For Netify 5.2 or later, digest_prev will always exist. For earlier versions, the digest should be used if digest_prev does not exist.
Local Rate
The local_rate is a burst rate, not a sustained average. Within a standard 15-second stats interval, a 1-second flow will report its full bandwidth for that second, not the full 15-second interval. Here are some considerations:
- Volatility: Rates calculated over short durations are statistically noisy and easily misinterpreted. Use this data knowing it reflects peak intensity, not long-term trends.
- Non-Additive: Because local_rate represents a burst, you cannot sum it across multiple flows. Doing so will create an inaccurate "phantom" total.
Visualization Best Practice: Avoid standard line charts which can become noisy. Use heatmaps or scatterplots to identify outliers, and always provide actual bandwidth for context.
Attributes
type
stringflow
objectflow.app_ip_override
booleanflow.app_proto_twins
booleanflow.bt
objectflow.bt.info_hash
stringflow.category
objectflow.category.application
integerflow.conntrack
objectflow.conntrack.id
integerflow.conntrack.mark
integerflow.conntrack.reply_dst_ip
stringflow.conntrack.reply_dst_port
integerflow.conntrack.reply_src_ip
stringflow.conntrack.reply_src_port
integerflow.detected_protocol_name
stringflow.detection_guessed
booleanflow.detection_packets
integerflow.detection_updated
booleanflow.dhc_hit
booleanflow.dhcp
objectflow.dhcp.class_ident
stringflow.dhcp.fingerprint
stringflow.digest
stringflow.digest_prev
array[string]flow.dns_host_name
stringflow.fhc_hit
booleanflow.first_seen_at
integerflow.gtp
objectflow.gtp.ip_dscp
integerflow.gtp.ip_version
integerflow.gtp.local_ip
stringflow.gtp.local_port
integerflow.gtp.local_teid
integerflow.gtp.other_ip
stringflow.gtp.other_port
integerflow.gtp.other_teid
integerflow.gtp.other_type
stringflow.gtp.version
integerflow.host_server_name
stringflow.http
objectflow.http.url
stringflow.http.user_agent
stringflow.ip_dscp
integerflow.ip_nat
booleanflow.ip_version
integerflow.last_seen_at
integerflow.local_bytes
integerflow.local_ip
stringflow.local_mac
stringflow.local_origin
booleanflow.local_packets
integerflow.local_port
integerflow.local_rate
numberflow.mdns
objectflow.mdns.answer
stringflow.nfq
objectflow.nfq.dst_iface
stringflow.nfq.src_iface
stringflow.other_bytes
integerflow.other_ip
stringflow.other_mac
stringflow.other_packets
integerflow.other_port
integerflow.other_rate
numberflow.other_type
stringflow.risks
objectflow.risks.risks
array[integer]flow.risks.ndpi_risk_score
integerflow.risks.ndpi_risk_score_client
integerflow.risks.ndpi_risk_score_server
integerflow.soft_dissector
booleanflow.ssl
objectflow.ssl.alpn
array[string]flow.ssl.alpn_server
array[string]flow.ssl.cipher_suite
stringflow.ssl.client_ja4
stringflow.ssl.client_sni
stringflow.ssl.encrypted_ch_version
stringflow.ssl.fingerprint
stringflow.ssl.issuer_dn
stringflow.ssl.server_cn
stringflow.ssl.subject_dn
stringflow.ssl.version
stringflow.ssh
objectflow.ssh.client
stringflow.ssh.server
stringflow.ssdp
objectflow.ssdp.user_agent
stringflow.stun
objectflow.stun.mapped
stringflow.stun.other
stringflow.stun.peer
stringflow.stun.relayed
stringflow.stun.response
stringflow.tcp
objectflow.tcp.resets
integerflow.tcp.retrans
integerflow.tcp.seq_errors
integerflow.total_bytes
integerflow.total_packets
integerflow.tags
array[string]flow.vlan_id
integerinterface
stringinternal
booleanFlow Attributes - Example
{
"flow": {
"app_ip_override": false,
"category": {
"application": 28,
"domain": 0,
"local_network": 0,
"other_network": 0,
"overlay": 0,
"protocol": 22
},
"conntrack": {
"id": 3603527535,
"mark": 0,
"reply_dst_ip": "192.168.4.44",
"reply_dst_port": 35636,
"reply_src_ip": "192.200.0.102",
"reply_src_port": 443
},
"detected_application": 11354,
"detected_application_name": "netify.tailscale",
"detected_protocol": 196,
"detected_protocol_name": "HTTP/S",
"detection_guessed": false,
"detection_updated": false,
"dhc_hit": false,
"digest": "c4c07ca55baa19a7fe3652bcd356765a7...",
"digest_prev": [
"463c53093403fcce8eeb01df5b5125df66a0f53b"
],
"dns_host_name": "login.tailscale.com",
"fhc_hit": false,
"first_seen_at": 1772738467573,
"host_server_name": "login.tailscale.com",
"ip_dscp": 0,
"ip_nat": false,
"ip_protocol": 6,
"ip_version": 4,
"last_seen_at": 1772738467684,
"local_ip": "192.168.4.44",
"local_mac": "f8:e9:03:01:69:13",
"local_origin": true,
"local_port": 35636,
"other_ip": "192.200.0.102",
"other_mac": "3c:7c:3f:a1:ed:58",
"other_port": 443,
"other_type": "remote",
"risks": {
"ndpi_risk_score": 0,
"ndpi_risk_score_client": 0,
"ndpi_risk_score_server": 0
},
"soft_dissector": false,
"ssl": {
"alpn": [
"h2",
"http/1.1"
],
"cipher_suite": "0x0000",
"client_ja4": "t13d1817h2_e8a523a41297_...",
"client_sni": "login.tailscale.com",
"encrypted_ch_version": "0xfe0d",
"version": "0x0303"
},
"vlan_id": 0
},
"interface": "wlp3s0",
"internal": true,
"type": "flow"
}