Conformance Diff

Compare your parser/collector against reference captures: status, header order, JA3/JA4, tokens.

The diff answers one question: would the server’s anti-fraud gate see your parser’s traffic differently from the real app’s? Give it two captures — a reference from the genuine client and a subject from your own collector, parser, or replay run — and it reports every measurable shape divergence: status distribution drift, HTTP/2 header-order signatures, cookie ordering and splitting, JA3/JA4 per SNI, decoded body keysets, and token mint→use joins with timing deltas.

This is the productized version of the manual analyze_traffic.py comparison loop. The motivation: anti-fraud gates rarely reject on one loud signal — they accumulate quiet ones. A wrong header order, a swapped cookie pair, and a too-fast token reuse each look harmless alone; stacked, they become a 451. The diff surfaces every dimension side by side so you can close them all at once.

[!NOTE] This workflow compares traffic from systems you are authorized to test. The diff is passive — it compares two captures you already hold and sends nothing to any server.

Load the reference and subject captures

Import both captures first (/docs/en/capture/importing/):

  1. The reference: a pcap/pcapng (or HAR) recording of the real application, ideally with a TLS keylog so JA3/JA4 and decrypted bodies are available.
  2. The subject: your collector’s output — a pcap recorded while your parser ran, or replay history captured back into the workspace (/docs/en/replay/fingerprints/ covers the TLS fingerprint control that makes replay comparable).

Both sessions must be enabled for the API lab. The more complete the import (keylog present, decode pipeline configured), the more dimensions the diff can measure.

Run the diff

Open the API labCollector tab → Conformance view (the default), then:

  1. Pick the real-app capture under Reference (real app).
  2. Pick your parser/replay capture under Subject (parser / replay).
  3. Optionally set a Path filter — a substring matched against request paths (e.g. /catalog/product/card) to scope the diff to one endpoint.
  4. Optionally set a Join cookie — the token name to join carriers to minters on (e.g. __gsac_a-goldapple). Leave blank and the diff auto-detects the most common shared cookie.
  5. Click Run conformance diff.

The same run also evaluates device-identity rules and a token lifecycle report against the subject; both appear below the diff sections.

Read the findings

The report opens with a severity-ordered findings list; each finding maps to a divergence class:

FindingSeverityMeaning
Status drift: 451 appears N× in subject vs M× in referencehigh (4xx/5xx), else warningSubject gets statuses the reference does not; a 4xx/5xx-heavy subject fails the iteration instantly.
Header-order signature differs on METHOD host/pathwarningThe most common ordered header-name sequence differs per endpoint.
Cookie order differs on METHOD host/pathwarningCookie names appear in a different order inside the Cookie header.
TLS fingerprint differs for SNI (JA4 … vs reference …)highThe JA3 or JA4 set for that SNI does not match.
Join field "X" disagrees in N joined pairswarningA carrier header disagrees with the value the minting request’s body declared.
Subject capture conforms to the reference on all measured dimensionsinfoNothing diverged on any measured dimension.

Below the findings, the Status distribution table shows per-status counts for both sides (drifted rows highlighted), and TLS per SNI lists each host with a match/drift badge. The rejection-class distribution buckets responses into labels such as accepted, antifraud-reject (451), rate-limited (429), and client-certificate-required (a 400 whose body names the missing client cert).

Report sections in detail

Each section compares reference and subject per endpoint key (METHOD authority+path) and reports the top signatures on each side — up to 8 samples per section — with a matches verdict on the most common entry:

SectionWhat it compares
Header-order signaturesOrdered request-header name sequences (lowercased, HTTP/2 :-pseudo-headers excluded).
Cookie ordersOrder of cookie names inside each Cookie header, per endpoint.
Cookie header countsHow many Cookie headers each request carries — catches header-splitting differences.
TLS per SNIUnique JA3, JA4, and ALPN sets per server name; a host matches only when both JA3 and JA4 sets agree.
Body keysetsSorted JSON key paths (two levels deep) of decoded request bodies per endpoint — schema-shape drift.
Token joinSee below.

Token joins and timing deltas

When a join cookie is set or auto-detected, the diff classifies each side’s requests as minters (a response set the cookie via Set-Cookie) or carriers (the request sends it), then joins carriers to minters by exact cookie value. The join block reports:

  • joined / unmatched pair counts for both sides;
  • Δt min/median/p90/max — the delay between a token being minted and first carried, in seconds. Reusing a token 0.1 s after minting where the real app waits seconds is a timing tell;
  • requests before first mint — carrier requests preceding any minting event — bootstrap-less traffic the real app would never produce.

The underlying report can also check field agreement across the join — e.g. that a plaid-os-version header on later requests equals mobileSdk.data.text.AndroidSDK from the minting request’s decoded body.

Typical fixes by divergence class

DivergenceTypical fix
Status drift to 451/403The symptom, not the cause — work the behavioral rows below, then re-measure.
Header-order signature differsEmit request headers in the captured order; most HTTP stacks sort or reorder them by default.
Cookie order differs / splittingSerialize cookies in the observed name order as a single Cookie header (or the same split the app uses).
TLS fingerprint differsMatch the ClientHello — use the captured JA3/JA4 as the replay/collector fingerprint target (/docs/en/replay/fingerprints/).
Body keyset differsAlign the decoded request JSON schema: same keys, same nesting, no extra debug fields.
Join Δt or pre-mint requests offReproduce the app’s bootstrap sequence and token cadence rather than minting and firing back-to-back.

[!TIP] Fix one class, re-run the diff, and confirm its finding disappears before moving on — the findings list is your regression check. When every dimension conforms but combined changes still get rejected, switch to the Probes view: it replays single and pairwise mutations and flags stacked rejections — mutations accepted individually but rejected in combination.

Traffic Jam documentation. Built with Hugo.