ja4plus — command-line output formats
Feature set structured-output · three formats, two contracts.
Table no stability promise
For a person reading a terminal. Columns may change between releases.
ja4plus analyze capture.pcap
Source Type Fingerprint
------------------------------------------------------------------------------------------
192.168.1.10:54321 -> 93.184.216.34:443 ja4 t13d1516h2_8daaf6152771_02713d6af862
192.168.1.10:54321 -> 93.184.216.34:443 ja4t 64240_2-1-3-1-1-4_1460_8
93.184.216.34:443 -> 192.168.1.10:54321 ja4s t130200_1301_234ea6891581
93.184.216.34:443 -> 192.168.1.10:54321 ja4x 2bab15409345_af684594efb4_000000000000
192.168.1.22:41002 -> 10.0.0.5:22 ja4ssh c36s36_c76s124_c0s0
[ja4plus] 4812 packets, 5 fingerprints, 3 connections
JSON Lines schema_version 1
One object per line. Every field is always present; an absent value is null.
ja4plus analyze capture.pcap --format json
{"schema_version":1,"timestamp":"2026-08-06T12:34:56.789012Z","type":"ja4","fingerprint":"t13d1516h2_8daaf6152771_02713d6af862","raw":"t13d1516h2_002f,0035,...","raw_original_order":"t13d1516h2_1301,1303,...","src_ip":"192.168.1.10","src_port":54321,"dst_ip":"93.184.216.34","dst_port":443,"identified_as":null}
{"schema_version":1,"timestamp":"2026-08-06T12:34:56.789012Z","type":"ja4t","fingerprint":"64240_2-1-3-1-1-4_1460_8","raw":null,"raw_original_order":null,"src_ip":"192.168.1.10","src_port":54321,"dst_ip":"93.184.216.34","dst_port":443,"identified_as":null}
With --lookup, only identified_as changes. No field appears or disappears.
ja4plus analyze capture.pcap --format json --lookup | jq -c '{type,fingerprint,identified_as}'
{"type":"ja4","fingerprint":"t13d1516h2_8daaf6152771_02713d6af862","identified_as":"Chromium Browser"}
{"type":"ja4t","fingerprint":"64240_2-1-3-1-1-4_1460_8","identified_as":null}
CSV schema_version 1
Fixed column order. The header is identical whatever flags the user passed.
ja4plus analyze capture.pcap --format csv
schema_version,timestamp,type,fingerprint,raw,raw_original_order,src_ip,src_port,dst_ip,dst_port,identified_as
1,2026-08-06T12:34:56.789012Z,ja4,t13d1516h2_8daaf6152771_02713d6af862,"t13d1516h2_002f,0035,...","t13d1516h2_1301,1303,...",192.168.1.10,54321,93.184.216.34,443,
1,2026-08-06T12:34:56.789012Z,ja4t,64240_2-1-3-1-1-4_1460_8,,,192.168.1.10,54321,93.184.216.34,443,
Diagnostics
Results go to standard output. Everything else goes to standard error, so a pipe stays clean.
ja4plus analyze broken.pcap --format json > out.jsonl
[ja4plus] warning: ja4x failed on packet 812: certificate length exceeds packet
[ja4plus] 1 fingerprinter error, 4811 packets read
ja4plus analyze capture.pcap --output out.jsonl
Error: out.jsonl already exists. Pass --force to overwrite.
Field reference
| Field | Type | Meaning |
schema_version | integer | Rises when a field is removed or its meaning changes. |
timestamp | string or null | The packet timestamp, in RFC 3339 form. |
type | string | The method name, lowercase. |
fingerprint | string | The fingerprint. Never empty. |
raw | string or null | The unhashed form, when the method defines one. |
raw_original_order | string or null | The unhashed wire-order form. |
src_ip, dst_ip | string | Addresses. Empty when the packet carries none. |
src_port, dst_port | integer | Ports. Zero when the packet carries none. |
identified_as | string or null | The application name from the mapping file. Null without --lookup. |
This mockup is guidance, not a contract. It shows the intent of the
output formats and roughly what a user sees. An implementer may diverge where the
feature's requirements and acceptance criteria are still met. The one part that is a
contract is the CSV column order and the JSON field set, and those live in
features/05-structured-output.md.