← eitp.io

EITP v1.3

Emotional Intelligence Transfer Protocol

Version
1.3
Date
May 20, 2026
Supersedes
v1.2 (May 18, 2026)
Author
Matthew Kiselstein (SentientIQ)
Status
Living specification, single-implementation
License
CC BY 4.0
Status of This Document
This is not an IETF RFC. It is a protocol specification published by the original implementer, documenting a production system running across automotive, RV, and powersports verticals. The specification is derived entirely from working code. All thresholds, packet formats, and taxonomy values reflect the production implementation. This document invites interoperable implementations and community contribution.
Abstract. Large Language Models begin every conversation at zero context. They infer tone, intent, and emotional state from the user's first message — or they guess. EITP eliminates this cold-start problem by capturing behavioral telemetry (mouse kinematics, scroll patterns, click dynamics, proximity to interactive elements, tab behavior) and transforming it into structured emotional context that is delivered to the LLM before or alongside the first message. In production, 62% of buyers who convert do so under uncertainty or cognitive distress — emotional states invisible without behavioral telemetry. The protocol defines the signal capture layer, transport mechanism, inference contract, and a nine-dimensional packet format that gives LLMs the context to respond with relevance from the first interaction.
Notational conventions. The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY" in this document are to be interpreted as described in RFC 2119.

Changelog — v1.2 → v1.3

v1.3 introduces one new packet dimension — Provenance — and refines the bot-filtering model to acknowledge a class of session that passes the human-proof gate (§8) but produces motion the inference engine judges physically impossible. Both changes are additive; v1.2 packets remain forward-compatible.

Changelog — v1.1 → v1.2

v1.2 reconciles the specification with the reference implementation as of May 2026. Every change below reflects a decision the running platform already made; the spec is catching up, not introducing new requirements.

1. Introduction

1.1 The Cold-Start Problem

Every LLM-powered conversation begins the same way: the model receives a user's first message and must infer everything — intent, emotional state, urgency, context — from that single text input. This is the cold-start problem.

But the user wasn't cold before they typed. They spent minutes browsing. They scrolled past pricing. They hovered over a call-to-action and pulled away. They switched tabs to compare a competitor. They came back. Their mouse slowed to a crawl on the financing section. All of this behavioral signal — rich, continuous, and expressive — is discarded the moment the chat window opens.

EITP captures this signal, transforms it into structured emotional context, and delivers it to the LLM so the first response is informed rather than generic.

Production evidence from the reference implementation:

62% of buyers who convert do so under uncertainty or cognitive distress. These buyers work 2.7x harder to reach a decision than engaged, confident buyers. Without behavioral telemetry, an LLM has no way to distinguish a paralyzed buyer (who needs guidance) from a confident one (who needs space).

1.2 Design Goals

  1. Implementable. A developer can build a conformant producer or consumer from this document alone.
  2. Layered. You can implement the packet format (Section 5) without the inference pipeline (Section 7). A consumer needs only Sections 5, 6, and 9.
  3. Privacy-first. No PII crosses the wire. Form values are never transmitted. Text selections are sanitized. IP addresses are injected server-side and excluded from consumer-facing packets.
  4. LLM-agnostic. The EITP packet is a JSON data structure. It is not specific to any model provider, framework, or inference strategy.

1.3 Terminology

Producer
A client-side system that captures behavioral telemetry and transmits it. Typically a JavaScript library running in the browser.
Consumer
A system that receives EITP packets and uses the emotional context. Typically an LLM or an application layer that injects EITP context into an LLM prompt.
Bridge
A server-side intermediary that receives telemetry from producers over WebSocket, injects server-side context (e.g., IP address), and forwards to a message bus.
Inference Engine
A system that processes raw telemetry and produces EITP v1.3 packets. May use AI, rules, or any combination.
Session
A bounded period of user interaction, identified by a session ID. Expires after a configurable timeout (default: 5 minutes of inactivity).
Emotion
A categorical label from the 28-value emotion axis (Section 6) describing how the user feels.
Behavior
A categorical label from the 10-value behavior axis (Section 6) describing what the user is doing. Orthogonal to emotion.
Intervention
A proactive action taken by a consumer in response to an EITP packet — typically a conversational message initiated before the user sends their first message.

1.4 Architecture Overview

EITP defines six layers. Implementations may target any subset, provided they produce or consume conformant data structures at layer boundaries.

Layer 1: Signal Capture Browser trackers capture raw behavioral events ↓ Layer 2: Transport Events batched and transmitted via WebSocket ↓ Layer 3: Filtering Bot detection removes non-human sessions ↓ Layer 4: Inference Raw telemetry transformed into emotional classification ↓ Layer 5: Packet Construction EITP v1.3 packet assembled (10 dimensions) ↓ Layer 6: Consumption Packet delivered to LLM as context

A minimal producer implements Layers 1–2 only (capture and transmit raw telemetry). A full-stack implementation covers Layers 1–5. A consumer needs only to understand the Layer 5 packet format (Section 5) and the taxonomy (Section 6).

2. Conformance Levels

EITP defines five conformance roles. An implementation may fulfill one or more roles simultaneously.

2.1 Producer Level 1 (Telemetry)

A Level 1 Producer:

2.2 Producer Level 2 (Full)

A Level 2 Producer meets all Level 1 requirements and additionally:

2.3 Bridge

A conformant Bridge:

2.4 Inference Engine

A conformant Inference Engine:

2.5 Consumer

A conformant Consumer:

3. Signal Capture Layer

The signal capture layer consists of eight independent tracker modules — mouse, click, scroll, viewport, tab, form, selection, and the proximity engine — that attach to DOM events, compute derived metrics, and emit typed events through a shared track(type, data) interface. Each module is independently implementable. A Level 1 Producer requires any three. A Level 2 Producer requires all eight plus gesture detection (§3.2) and page content extraction (§3.10), neither of which is a standalone tracker: gesture detection operates on the mouse tracker's history buffer, and page content extraction is a library function invoked when assembling each batch.

3.1 Mouse Tracker

The mouse tracker captures cursor position and computes the first three kinematic derivatives in real time. This is the foundational signal source — mouse kinematics encode hesitation, urgency, confusion, and confidence in ways that text alone cannot express.

Physics Chain

At each sampling tick, the tracker computes the full kinematic state from consecutive position samples:

// Position (raw input)
x, y                          // pixels

// Velocity (1st derivative)
vx = dx / dt                    // px/s
vy = dy / dt                    // px/s

// Acceleration (2nd derivative)
ax = dvx / dt                   // px/s²
ay = dvy / dt                   // px/s²

// Jerk (3rd derivative)
jx = dax / dt                   // px/s³
jy = day / dt                   // px/s³

// Scalar magnitudes
speed = √(vx² + vy²)          // px/s
jerk  = √(jx² + jy²)          // px/s³

Event: mouse

Emitted at each sampling tick.

FieldTypeUnitDescription
xnumberpxCursor X position (clientX)
ynumberpxCursor Y position (clientY)
vxnumberpx/sX velocity
vynumberpx/sY velocity
axnumberpx/s²X acceleration
aynumberpx/s²Y acceleration
jxnumberpx/s³X jerk
jynumberpx/s³Y jerk
speednumberpx/sVelocity magnitude
jerknumberpx/s³Jerk magnitude

Configuration

ParameterDefaultUnit
Sampling rate20Hz
History buffer100samples
Inactivity threshold5000ms

3.2 Gesture Detection

Gesture detection operates on a sliding window of the last 10 mouse samples from the history buffer. Three gesture patterns are detected:

Circular Motion

The centroid of the 10 points is computed. Each point's distance from the centroid is measured. Circularity is defined as max(0, 1 - (variance / avgRadius²)). A score of 1.0 indicates a perfect circle; a score below the threshold indicates non-circular motion.

Event: circular_motion

FieldTypeDescription
circularitynumber (0–1)Circularity score
radiusnumber (px)Average radius from centroid
durationnumber (ms)Time span of window

Thresholds: circularity > 0.85, radius > 20px

Zigzag (Direction Changes)

Direction is quantized to 8 compass octants (π/4 buckets). Changes are counted with a minimum movement of 30px and 300ms debounce between changes.

Event: direction_changes

FieldTypeDescription
countnumberDirection changes in window (>6)
durationnumber (ms)Time span of window
avgSpeednumber (px/s)Average speed across window

Threshold: > 6 direction changes in 10 samples

Dwell (Hesitation)

Emitted when cursor speed drops below the micro-movement threshold for longer than the dwell threshold. Only fires when the cursor is inside the viewport.

Event: mouse_pause

FieldTypeDescription
durationnumber (ms)Time spent dwelling
x, ynumber (px)Cursor position
viewport.relX, viewport.relYnumber (0–1)Relative viewport position

Thresholds: speed < 20 px/s, duration > 500ms

Exit Vector

Event: mouse_exit — emitted when the cursor leaves the document.

FieldTypeDescription
anglenumber (degrees)Exit angle from viewport center
velocitynumber (px/s)Exit speed
edgestring"top" | "right" | "bottom" | "left"
x, ynumber (px)Exit position

3.3 Click Tracker

Event: click

FieldTypeDescription
x, ynumber (px)Click position
target.tagstringElement tag name
target.classstringElement class name
target.idstringElement ID
target.textstringText content (first 50 chars)
mouseVelocitynumber (px/s)Cursor speed at moment of click
mouseJerknumber (px/s³)Cursor jerk at moment of click

Event: rage_click

Emitted when 3 or more clicks occur within a 500ms window. Indicates frustration with an unresponsive element.

FieldTypeDescription
countnumberNumber of rapid clicks (≥3)
areanumber (px²)Bounding box area of click cluster

Thresholds: ≥ 3 clicks within 500ms

3.4 Scroll Tracker

Event: scroll

Debounced at 100ms.

FieldTypeDescription
depthnumber (0–100)Current scroll depth percentage
maxDepthnumber (0–100)Maximum depth reached this session
velocitynumber (px/s)Scroll velocity (positive = down)
directionstring"down" | "up"

3.5 Proximity Engine

The proximity engine tracks cursor distance to interactive elements using a spatial grid (cell size: 160px). It detects when the cursor enters, hovers over, lingers near, or leaves the proximity zone of categorized page elements.

Element Kinds

Eleven element kinds, listed in priority order with their associated intent levels:

KindIntent LevelExamples
pricePrice displays, cost elements
purchase_buttonhighBuy, Add to Cart, Order
checkout_buttonhighCheckout, Complete Purchase
subscribe_buttonhighSubscribe, Upgrade
demo_ctamedium-highBook Demo, Schedule, Try
signup_ctamedium-highSign Up, Register, Get Started
tier_cardmediumPricing tier/plan containers
pricing_navmediumPricing navigation links
feature_navlow-mediumFeature navigation links
learn_morelow-mediumLearn More, Read More
ctalowGeneric calls to action

Proximity Events

For each element kind, four events are generated:

Proximity Enter Payload

FieldTypeDescription
distancenumber (px)Distance from element edge
overbooleanTrue if directly over element
element_typestringThe element kind
textstringElement text (first 80 chars)
intentstringIntent level for this kind
signals.hasDiscountbooleanText/class contains discount language
signals.hasTrialbooleanText/class contains trial language
signals.hasUrgencybooleanText/class contains urgency language

Price elements additionally include: currency, value (parsed numeric), isOriginal, isSale.

Event: pricing_comparison

Emitted when 2 or more tier_card elements are simultaneously visible in the viewport. Cooldown: 5000ms between emissions.

Configuration

ParameterDefaultUnit
Grid cell size160px
Enter radius140px
Spatial hysteresis12px (leave = 152px)
Time hysteresis600ms

3.6 Viewport Tracker

Event: viewport_resize

Debounced at 250ms.

FieldTypeDescription
width, heightnumber (px)Viewport dimensions
orientationstring"landscape" | "portrait"

Event: viewport_boundary

Fires once when user scrolls to within 50px of the page top or bottom.

FieldTypeDescription
boundarystring"top" | "bottom"
scrollDepthnumber0 (top) or 100 (bottom)

Event: viewport_approach (Exit Intent)

Emitted when the cursor is within 100px of the top viewport edge AND moving upward with velocity exceeding 400 px/s. Suppressed when the cursor is over a <nav>, <header>, or [role="navigation"] element.

FieldTypeDescription
edgestring"top"
distancenumber (px)Distance from top edge
velocitynumber (px/s)Cursor speed magnitude
vector.vx, vector.vynumber (px/s)Velocity components

Thresholds: distance < 100px, upward velocity > 400 px/s

3.7 Tab Tracker

Event: tab_switch

FieldTypeDescription
actionstring"away" | "return"
awayDurationnumber (ms)Time spent away (on return)
activeTimenumber (ms)Time spent active (on away)
totalSwitchesnumberCumulative switch count (on return)

Event: long_tab_return

Emitted when the user returns after an absence exceeding 30 seconds. This is a strong comparison-shopping signal — the user likely visited a competitor or alternative.

FieldTypeDescription
awayDurationnumber (ms)Time away (>30,000ms)
sessionTimenumber (ms)Total session time

3.8 Form Tracker

Event: form_focus

FieldTypeDescription
typestringField type (text, email, select, etc.)
namestringField name attribute
idstringField ID attribute

Event: form_blur

FieldTypeDescription
typestringField type
namestringField name attribute
durationnumber (ms)Time spent focused
hasValuebooleanWhether field has a value on blur

Field abandonment is defined as hasValue === false AND duration > 2000ms. No separate event is emitted; abandonment is inferred from form_blur events meeting both conditions.

Event: form_submit

FieldTypeDescription
idstringForm ID
actionstringForm action URL
methodstringGET | POST
Privacy. Form field values are never transmitted. Only field metadata (type, name, duration, hasValue) crosses the wire.

3.9 Selection Tracker

Event: text_selection

Emitted on non-empty text selection. Text is PII-sanitized before transmission.

FieldTypeDescription
textstringSanitized text (first 100 chars)
lengthnumberFull selection length
hasPricebooleanSelection matches price pattern

Event: text_selection_with_price

Emitted additionally when the selected text contains a price pattern ($NNN.NN).

FieldTypeDescription
textstringRaw text (first 100 chars)
pricestringMatched price string
lengthnumberFull selection length

PII Sanitization Patterns

Producers must replace the following patterns with [REDACTED] before transmission:

PatternRegex
Email[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}
Phone\d{3}[-.]?\d{3}[-.]?\d{4}
SSN\d{3}-\d{2}-\d{4}
Credit card(\d{4}[\s-]?){3}\d{4}
Zip code\d{5}(-\d{4})?

3.10 Page Content Extraction

Page content extraction provides the object of attention — not just how the user is behaving, but what they are looking at. This is what makes EITP different from pure analytics. The LLM receives both emotional state and the content that produced it.

Extracted fields:

FieldDescriptionLimits
pageTitleDocument title
h1First H1 element text
headingsH2 element textsMax 8
tablesTable headers and row dataMax 3 tables, 15 rows each
structuredDataJSON-LD data (Product, Vehicle, Offer, ItemList, FAQPage)
visibleContentParagraph text near viewport centerMax 5 paragraphs
metaDescription and keywords from meta tags

Content extraction should be cached for 5 seconds per section to minimize DOM reads.

4. Transport Layer

4.1 WebSocket Primary Transport

The primary transport is WebSocket (wss://). The producer connects to a Bridge endpoint and communicates using NATS text protocol framing over WebSocket frames.

Handshake

// Server sends on connection:
INFO {"server_id":"eitp-bridge","version":"2.0.0","proto":1,"max_payload":1048576}\r\n

// Client responds:
CONNECT {"tenant_id":"...","session_id":"..."}\r\n

// Server acknowledges:
+OK\r\n

Protocol Commands

CommandDirectionFormat
PUBClient → BridgePUB <subject> <size>\r\n<payload>\r\n
SUBClient → BridgeSUB <subject> <sid>\r\n
MSGBridge → ClientMSG <subject> <sid> <size>\r\n<payload>\r\n
PINGBothPING\r\n
PONGBothPONG\r\n

Keepalive: Producers should send PING\r\n every 30 seconds. Bridges must respond with PONG\r\n.

4.2 Subject Namespace

Messages are routed via subject strings. The following subjects are defined:

SubjectDirectionPayload
telemetry.rawProducer → BridgeTelemetry batch (Section 4.3)
emotions.{tenantId}.detected.{sessionId}Engine → PersistenceEmotion event
emotions.{tenantId}.{sessionId}Engine → ConsumerEmotional profile for chat context
seer.{tenantId}.intervention.request.{sessionId}Engine → ConsumerEITP v1.3 packet (Section 5)
bot.{tenantId}.detection.{sessionId}Engine → AnalyticsBot classification event

Bridges must enforce a whitelist on client PUB subjects. At minimum, only telemetry.raw should be allowed from untrusted clients.

4.3 Batching

Producers must batch events before transmission. Events are accumulated in a buffer and flushed on a timer or when the buffer reaches capacity.

Batch Envelope

{
  "type": "telemetry_batch",
  "events": [
    {
      "type": "mouse",
      "data": { /* event-specific payload */ },
      "timestamp": 1740700800000,
      "currentSection": "pricing"
    },
    // ... more events
  ],
  "sessionId": "sq_1740700800000_abc123def",
  "tenantId": "org_xxx",
  "vertical": "rv_dealer",
  "pageContent": { /* Section 3.10 extraction */ },
  "timestamp": 1740700800000
}

Flush Parameters

ParameterDefaultDescription
Flush interval3000msTimer-based flush
Batch size50 eventsMaximum events per batch
Priority threshold40 eventsEarly flush for priority events
Max buffer500 eventsHard buffer cap (oldest events dropped)

Priority events that trigger early flush: click, rage_click, form_submit, text_selection_with_price, viewport_approach, mouse_pause, and all proximity events.

Producers should also flush on beforeunload and visibilitychange (hidden) to capture final events before the user leaves.

4.4 Reconnection Strategy

When the WebSocket connection drops, producers should reconnect with exponential backoff:

ParameterValue
Base delay1,000ms
Backoff factor2
Maximum delay30,000ms
JitterRandom 0–1,000ms
Maximum attempts5

Formula: delay = min(1000 * 2^attempt, 30000) + random(0, 1000)

After exhausting all reconnection attempts, the producer should fall back to HTTP POST with the same batch envelope format. On tab visibility change (hidden → visible), the producer should send an immediate PING to verify connection health.

4.5 Server-Side IP Injection

Bridges must inject the client's IP address into telemetry payloads before forwarding to the message bus. Clients must not self-report their IP address. This is a security requirement: client-reported IPs are trivially spoofable, and IP is used downstream for geolocation and bot detection.

4.6 Rate Limiting

Bridges must enforce rate limits to prevent abuse. Reference implementation defaults:

LimitValue
Maximum message size50,000 bytes
Maximum events per second (producer)500
Maximum events per type per second100

5. The EITP v1.3 Packet

The EITP v1.3 packet is the core data structure of the protocol. It is a JSON object with ten dimensions that together describe the user's emotional state, behavioral context, pre-arrival origin, the content they are engaging with, and the inference engine's attestation that the underlying motion was physically possible (the provenance verdict, §5.12). A conformant Inference Engine must produce packets matching this schema. A conformant Consumer must accept packets matching this schema.

5.1 Packet Envelope

{
  "sessionId": "sq_1740700800000_abc123def",
  "tenantId":  "org_xxx",
  "timestamp": 1740700800000,

  "emotion":            { /* 5.2 */ },
  "spatial":            { /* 5.3 */ },
  "temporal":           { /* 5.4 */ },
  "behavioral":         { /* 5.5 */ },
  "patterns":           { /* 5.6 */ },
  "intent":             { /* 5.7 */ },
  "pageContent":        { /* 5.8 */ },
  "globalIntelligence": { /* 5.9 */ },
  "channel":            { /* 5.10 */ },
  "provenance":         { /* 5.12 — v1.3+ */ }
}
FieldTypeRequiredDescription
sessionIdstringYesUnique session identifier
tenantIdstringYesTenant/organization identifier
timestampnumberYesEpoch milliseconds at packet creation

5.2 Dimension 1: Emotion

{
  "primary":    "paralysis",
  "behavior":   "analysis",
  "context":    "pricing",
  "confidence": 0.82,
  "intensity":  0.65,
  "trajectory": "intensifying"
}
FieldTypeRequiredDescription
primarystringYesOne of the 28 canonical emotions (Section 6). How the buyer feels.
behaviorstring | nullYesOne of the 10 canonical behaviors (Section 6) or null. What the buyer is doing.
contextstring | nullNoFree-text subject (e.g. "pricing", "trade_in", "financing"). Lowercase, ≤64 chars. May be null.
confidencenumber (0.0–1.0)YesInference engine's certainty in the (emotion, behavior) classification
intensitynumber (0.0–1.0)YesStrength of the emotional signal
trajectorystringYes"intensifying" | "stable" | "cooling"

v1.2 separates emotion and behavior into orthogonal fields. v1.1's composite labels (e.g. decision_paralysis, analysis_paralysis) collapsed these into a single string and produced 277 drifting variants in production. Consumers that still want the composite read can derive it as ${behavior}_${primary} when both are present.

trajectory is computed from the session's emotional history. An engine should maintain at least the last 3 emotion classifications per session to determine trajectory direction.

5.3 Dimension 2: Spatial

{
  "currentSection": "pricing",
  "visitCount":     3,
  "trigger":        "meet-seer-introduction"
}
FieldTypeRequiredDescription
currentSectionstringYesDOM section ID the user is currently viewing
visitCountnumberYesHow many times the user has visited this section
triggerstring | nullNoSpatial event that triggered this packet

A user returning to the same section repeatedly is a strong signal. Three visits to “pricing” means something different than one visit. The visitCount gives the consumer this context.

5.4 Dimension 3: Temporal

{
  "sessionDuration":     234000,
  "timeSinceLastEmotion": 45000
}
FieldTypeRequiredDescription
sessionDurationnumber (ms)YesTime since session start
timeSinceLastEmotionnumber (ms)YesTime since last emotion classification

5.5 Dimension 4: Behavioral

{
  "scrollDepth": 72,
  "clickCount":  4
}
FieldTypeRequiredDescription
scrollDepthnumber (0–100)YesMaximum scroll depth in current batch
clickCountnumberYesClick events in current batch

5.6 Dimension 5: Patterns

{
  "detected": [
    "extended_dwelling_on_pricing",
    "comparison_shopping_tab_pattern"
  ]
}
FieldTypeRequiredDescription
detectedstring[]YesBehavioral patterns identified by the inference engine

Pattern names are free-form strings assigned by the inference engine. Examples from production: "rage_clicks", "exit_intent_with_rapid_scrolling", "price_comparison_between_tiers", "repeated_section_revisit".

5.7 Dimension 6: Intent

{
  "level":      "high",
  "action":     "comparison",
  "confidence": 0.75
}
FieldTypeRequiredDescription
levelstringYesIntent strength (e.g., "high", "medium", "low")
actionstringYesInferred action (e.g., "comparison", "purchase", "exit")
confidencenumber (0.0–1.0)YesConfidence in intent classification

5.8 Dimension 7: Page Content

This dimension gives the consumer awareness of what the user is looking at, not just how they are behaving. A paralyzed buyer hovering over a “2024 Arctic Wolf 3650SUITE” needs different help than one hovering over a “Financing Calculator.”

{
  "pageTitle":      "2024 Arctic Wolf 3650SUITE | Prosser's Premium RV",
  "h1":            "2024 Cherokee Arctic Wolf 3650SUITE",
  "headings":       ["Specifications", "Floor Plan", "Features"],
  "tables":         [{ "headers": ["Spec", "Value"], "rows": [["Length", "39ft"]] }],
  "structuredData": [{ "type": "Vehicle", "name": "Arctic Wolf 3650SUITE", "price": "$59,995" }],
  "visibleContent": "Experience the ultimate in fifth wheel living...",
  "meta": {
    "description": "Shop the 2024 Arctic Wolf 3650SUITE at Prosser's Premium RV"
  }
}
FieldTypeRequired
pageTitlestring | nullNo
h1string | nullNo
headingsstring[]No
tablesarray of {headers, rows}No
structuredDataarray of objectsNo
visibleContentstring | nullNo
metaobjectNo

The entire pageContent dimension is optional — a packet may set it to null. But when present, it transforms the consumer's ability to generate contextually relevant responses.

5.9 Dimension 8: Global Intelligence

Global intelligence aggregates emotional signals across all active sessions for a tenant. It provides market-level context that individual session data cannot.

{
  "evi":                  0.73,
  "trend":                "rising",
  "percentile":           85,
  "isAnomaly":            false,
  "anomalySeverity":      "none",
  "predictedEvi":         0.76,
  "predictedDirection":   "up",
  "predictionConfidence": 0.68,
  "contagion":            null
}
FieldTypeDescription
evinumberEmotional Volatility Index (aggregate across sessions)
trendstringCurrent trend direction
percentilenumberPercentile rank against historical baselines
isAnomalybooleanWhether current conditions are anomalous
predictedEvinumber30-minute EVI prediction
contagionobject | nullEmotional contagion spread data

This dimension is optional. It is only available in implementations that track aggregate emotional state across sessions. A packet may set globalIntelligence to null.

5.10 Dimension 9: Channel Origin

Channel origin records where the visitor came from before arriving on the site. This is a pre-arrival intent signal — the referring source is a self-selection event that carries information about the visitor's decision stage before the first behavioral event is recorded.

{
  "referrer":     "rvtrader.com",
  "utm_source":   "google",
  "utm_medium":   "cpc",
  "utm_campaign": "summer-inventory"
}
FieldTypeRequiredDescription
referrerstring | nullNoHTTP referrer hostname (e.g., "rvtrader.com", "google.com")
utm_sourcestring | nullNoUTM source parameter from inbound URL
utm_mediumstring | nullNoUTM medium parameter (e.g., "cpc", "email", "social")
utm_campaignstring | nullNoUTM campaign parameter

Resolution order: utm_source takes precedence over referrer. If both are null, the session originated from direct navigation. All fields are optional — the entire channel dimension may be null.

Consumers should use channel origin to inform opening frame and tone, not to mention the source directly. A visitor from a comparison marketplace is already in active evaluation mode — the consumer should skip exploratory framing and engage on specifics. A visitor from a paid social ad is earlier in the funnel and should be treated accordingly.

Privacy note. referrer is the HTTP Referer hostname only — never the full URL, never a path, never query parameters. UTM values are extracted from the inbound URL and not re-transmitted beyond the bridge. No PII can be embedded in these fields.

5.11 Experimental Extension

Packets may include an experimental context for A/B testing intervention strategies:

{
  "isExperiment": true,
  "experimentContext": {
    "experimentId": "exp_001",
    "hypothesis":    "Empathy-led interventions outperform direct offers",
    "vertical":      "rv_dealer"
  }
}

Consumers should log experimental context alongside outcomes to enable Thompson Sampling or other exploration/exploitation strategies.

5.12 Dimension 10: Provenance

Provenance records the inference engine's judgment about whether the telemetry batch underlying this packet was produced by a physically-attested human body. Human motion has physical limits: cursor jerk (the third derivative of position) rarely exceeds 104 px/s3; scroll velocity stays in the 50–8000 px/s band; interactive events cannot fire faster than human reaction time (~200 ms). When a batch violates these limits — cursor jerk above 106 px/s3, perfectly periodic event timing, 100+ Hz mouse-event density — the motion was not produced by a human body, and any emotion label drawn from it would be fiction.

{
  "physical_plausibility": "plausible"
}
FieldTypeRequiredDescription
physical_plausibilitystringYesOne of "plausible" or "declined". The inference engine's verdict on whether the underlying motion was physically possible. Default value: "plausible". A producer that does not implement plausibility classification must still emit "plausible" — the field is required so that any consumer can rely on its presence.
ValueMeaning
"plausible"The inference engine committed to an emotion classification on motion consistent with a human body. This is the default for every conformant batch.
"declined"The inference engine refused to label because the motion was physiologically impossible. Other fields on the packet (emotion.primary, behavior) may be null in this case. The packet is still published — it is substrate evidence of the engine's refusal — but consumers of aggregate signals should exclude it.

This dimension complements the producer-side human-proof gate defined in §8. The proof gate runs against raw telemetry before classification, with finite signals (scroll variance, mouse tremor, speed variance) and hard-reject guards (synthetic event, burst density). Provenance is a second, semantic layer applied by the inference engine itself — flagging the small class of sessions that pass the proof gate but produce motion an inferring model can recognize as fabricated. The two layers are independent. A session may pass the proof gate and still produce "declined" packets; a session that fails the proof gate produces no packets at all.

Consumer guidance. Producers of Dimension 8 (Global Intelligence) — the Emotional Volatility Index and its derivatives — must exclude "declined" packets from aggregate computation. Single-session consumers (an LLM receiving a packet for conversational context) may handle "declined" as if the packet contained no emotion signal: skip the intervention, do not engage on inferred emotional state.

Why an additive packet field rather than a separate channel. The honesty property the protocol claims at the substrate level (the platform tells on itself) only holds if the verdict travels with the data. A separate channel allows downstream consumers to subscribe to the data without subscribing to the verdict, recreating the contamination the dimension exists to prevent. Provenance is a structural commitment to ship the verdict in the same packet as the classification, so any conformant Consumer sees both or neither.

6. The Two-Axis Taxonomy

A conformant Inference Engine must classify into two orthogonal axes: an emotion (how the buyer feels) and a behavior (what the buyer is doing). Both vocabularies are closed. Implementations may use additional internal labels but must map to a canonical value when producing EITP packets. Invalid or unrecognized labels must be emitted as null — the value "unknown" is explicitly prohibited.

Composite states like analysis_paralysis, decision_paralysis, or price_sensitivity decompose as (emotion, behavior, context) — for example (paralysis, analysis, null), (paralysis, deliberation, null), and (uncertainty, evaluation, "pricing") respectively. Context (free-text, ≤64 lowercase chars) names what the emotion is about when a subject exists ("pricing", "payment", "trade_in", "delivery", …) and is stored separately from the canonical emotion and behavior values so the triple can be queried independently.

6.1 Emotion Axis — 28 canonical values

The emotion axis describes the buyer's internal state. Loosely grouped for readability; the spec imposes no group structure beyond this listing.

Uncertainty & doubt

ValueDescription
uncertaintyAmbiguous intent, insufficient signal to classify further.
hesitationApproach-retreat pattern near commitment points. Dwell near CTAs.
indecisionSustained inability to commit between visible options.
ambivalenceEqual pull toward multiple options. Alternating without deepening.
apprehensionAnticipatory tension before a decision point.
doubtActive skepticism about a previously held position.
confusionMisunderstanding interface or content. Circular motion, rage clicks on non-interactive elements.
bewildermentSurprise-flavored confusion in response to unexpected content.
disorientationLoss of orientation within site structure. Repeated nav use, back-button bursts.

Tension & load

ValueDescription
anxietyGeneral tension in interaction pattern. Hesitant mouse, frequent pauses.
overwhelmChoice or information volume exceeds processing capacity. Rapid shallow scrolling.
paralysisDecision lock. Repeated revisits without state change.
frustrationRepeated failed interactions. Rage clicks, high jerk, erratic velocity.
rageIntense frustration with sustained signal. Compound rage-click episodes.
impatienceTime pressure exceeding session pace. Rapid sequential clicks on slow-responding elements.
fatigueCognitive depletion late in session. Declining engagement amplitude.

Withdrawal

ValueDescription
avoidanceActive steering away from a content region.
withdrawalProgressive disengagement without explicit exit signal.
resignationAcceptance of an unfavorable read (e.g. price out of reach) without abandonment.
indifferenceLow affective amplitude across the session.
apathySustained indifference with declining interaction.

Engagement & commitment

ValueDescription
curiosityActive exploration, increasing engagement. Accelerating scroll depth, section discovery.
anticipationForward-leaning posture toward a known target outcome.
excitementHigh-amplitude positive engagement. Burst clicks on high-value content.
determinationFocused task pursuit, low extraneous motion.
urgencyTime-pressured decision making. High velocity, direct navigation, minimal browsing.
trustEstablished confidence signal — e.g. dwell on testimonials or credentials after a price view.
satisfactionPositive outcome signal. Smooth navigation post-action, decreased urgency metrics.

6.2 Behavior Axis — 10 canonical values

The behavior axis describes what the buyer is observably doing, independent of how they feel about it.

ValueDescription
exploratory_browsingOpen-ended discovery with no fixed target.
scanningRapid surface read across many items.
passive_browsingLow-effort consumption without commitment behaviors.
deliberationActive weighing of options — not stuck. Methodical section visits, steady pace.
contemplationSingle-target consideration with dwell.
evaluationCriterion-based assessment against a specific element (price, spec, financing).
analysisSystematic decomposition across multiple criteria. Deep scrolling, tab switching, extended sessions.
comparison_shoppingCross-option comparison. Tab switching (especially long returns), multi-item viewing, pricing comparison events.
disengagementDeclining interaction, imminent abandonment. Decreasing events, exit intent signals, long inactivity.
abandonmentExplicit exit signal — tab close, navigation away, exit intent at high velocity.

Production Evidence

Data source. The following data is from the reference implementation running across automotive, RV, and powersports dealer websites. Sample sizes are small but directionally significant. These numbers are presented as evidence that the taxonomy captures real behavioral differences, not as statistical claims of general validity. Composite labels are shown here for continuity with v1.1; in v1.2 the same observations are stored as (emotion, behavior, context) triples.
Composite (v1.1)v1.2 decompositionConversionsAvg SessionAvg Events
decision_paralysis(paralysis, deliberation)1638.9 min25.1
overwhelm(overwhelm, scanning)1019.2 min45.6
cognitive_load(overwhelm, analysis)9126.5 min17.3
frustration(frustration, evaluation)642.0 min50.0

Key finding: 62% of converting buyers convert under uncertainty or cognitive distress. Distressed buyers work 2.7x harder (measured by median message count) to reach a decision than engaged, confident buyers. This is the core thesis — these are the buyers who need help, and they are invisible without behavioral telemetry.

Extension Rules

Implementations may define additional internal labels for vertical-specific reads (e.g. "trade_in_anxiety", "spouse_approval_seeking"). However, when producing EITP v1.3 packets, emotion.primary must be one of the 28 canonical emotions and emotion.behavior must be one of the 10 canonical behaviors or null. Vertical-specific context belongs in emotion.context (free text) or patterns.detected.

When the inference engine reaches for a label outside these enums, the raw output should be persisted to an out-of-vocabulary record (the reference implementation calls this emotion_classification_failures) so the taxonomy can evolve based on real failures rather than hypothetical ones.

7. Inference Pipeline

This section documents the reference implementation's inference approach. It is informative, not normative — alternative implementations may use different inference strategies (rules, statistical models, different AI providers, or hybrid approaches) as long as they produce conformant EITP packets.

Changed in v1.2. The reference implementation previously ran a two-tier pipeline (fast triage model → capable model on escalation). That tier-1 gate was retired in May 2026. The current production path is single-tier, capable-model-primary, with cost control moved upstream into rule-gating and a per-session inference budget. See §7.3 for the rationale.

7.1 Pipeline Architecture

telemetry.raw ↓ 5–10 s Buffer (accumulate events per session) ↓ Cheap Pre-Filter (user-agent + IP blocklist) ↓ passed sessions only Human-Proof Gate (§8 — scroll variance / mouse tremor / speed variance) ↓ proven-human sessions only Rule Gate (signal density, dedup, per-session inference budget) ↓ qualifying batches only Capable-Model Inference (single-tier, prompt-cached static system prompt) ↓ intervention_needed === true Intervention Decision (cooldowns, suppression, Thompson sampling) ↓ EITP v1.3 Packet Publication

7.2 Buffering

Raw telemetry is accumulated per session before inference. The reference implementation uses a 5–10 s window depending on signal density. Shorter windows lose temporal context across mouse-pause / scroll cycles; longer windows delay intervention beyond the buyer's natural attention span.

7.3 Single-Tier Inference

The reference implementation calls a single capable frontier model (Anthropic claude-sonnet-4-6 at time of writing) once per qualifying batch. It classifies the (emotion, behavior, context) triple, returns confidence, intensity, trajectory, and an intervention_needed boolean in one round trip.

v1.1's two-tier "fast triage → capable escalation" design was retired in May 2026. At the platform's volume, the fast-tier model wasn't materially improving cost-per-correct- classification once the rule gate was tightened: most fast-tier resolutions were either batches that didn't need any inference call (now caught by the rule gate) or batches that the capable model would have read differently. Removing the tier-1 hop also removed a class of label-disagreement bugs where the two tiers produced incompatible reads of the same batch.

Cost control now lives upstream of inference: a session-level inference budget (default: 6 capable-model calls per session lifetime), per-minute rate caps, dedup against the previous batch's classification, and a rule gate that suppresses inference on signal-sparse batches.

Implementations may still run a multi-tier pipeline if it pays for itself at their volume. The conformance contract is the packet, not the model count.

7.4 Prompt Caching

The capable-model system prompt is static and cached by the provider's prompt-cache facility. The reference implementation deliberately keeps the static prompt above the provider's minimum cache size (2048 tokens for Anthropic Sonnet at time of writing) so the cache hit pays for itself on every call. Tenant- and session-specific context is appended below the static block to avoid invalidating the cached prefix.

7.5 Knowledge Injection

The inference engine injects proven patterns from a knowledge store into the model's user-message context (below the cached system prompt). Patterns are filtered by tenant match, vertical match, confidence ≥ 70%, and sample size ≥ 5. This gives the model awareness of what has worked before for similar behavioral patterns without invalidating the prompt cache.

7.6 Thompson Sampling

The reference implementation uses Thompson Sampling with Beta distributions for exploration / exploitation of intervention strategies. Beta parameters are derived from historical conversion data — tenant-specific priors with global hierarchical shrinkage fallback (0.5x weight for global priors).

This means the system automatically balances between using proven interventions (exploit) and testing new approaches (explore), converging on optimal strategies as data accumulates.

7.7 Feedback Loop

A 60-second aggregation cycle processes emotional events and produces pattern intelligence:

Validated patterns (sample size ≥ 10) are injected back into inference prompts, creating a closed loop where the system learns from its own observations.

7.8 Observability

Each inference call should log: the input batch hash, the cached vs. uncached prompt-token split, the model's full structured output, the resulting EITP packet, intervention decision, and per-call cost attribution. The reference implementation persists these to llm_cost_log per (tenant, session, batch) tuple, which is what makes the rule-gate and budget thresholds tunable from production data rather than guesswork.

8. Bot Filtering

Bot filtering is normative because — unlike analytics where bot traffic merely inflates numbers — in EITP, bot traffic triggers expensive LLM inference calls. A single bot flood can generate thousands of dollars in API costs. A conformant Inference Engine must implement bot detection.

Changed in v1.2. v1.1's bot filter relied on negative thresholds — detect "impossible" velocities, regular timing, hover bursts. In production those thresholds generated false positives on fast humans, high-DPI cursors, and VPN / mobile-carrier IP ranges. v1.2 inverts the question: bots are the default; sessions must demonstrate physiological human signal to be admitted to the inference pipeline. The finite space of "what does a real human's hand produce?" is more tractable than the infinite space of "what could a bot look like?"

8.1 Cheap Pre-Filter (Required)

Before any per-session signal analysis, an Inference Engine must apply two zero-cost checks:

  1. User-agent matching: Reject known crawler, headless-browser, SEO/monitoring, and automation patterns at the bridge layer. ~90% catch rate at near-zero cost.
  2. IP blocklist: A dynamic, hot-reloadable blocklist of individually confirmed bad actors. Hardcoded IP / ASN ranges should not be used — in practice they collide with legitimate VPN, mobile-carrier, and cloud-preview traffic.

8.2 Human-Proof Gate (Required)

After the pre-filter, sessions must pass a human-proof gate before any LLM inference call is made. A session is assumed bot until one of three physiological signals fires on a single batch. The signals exploit the fact that human hands produce variance that scripts don't reliably reproduce; the targets are small enough to enumerate.

Proof pathSignalDefault threshold
Scroll variance5+ scrolls in the human velocity range (50–8000 px/s) whose stdDev exceeds 30% of mean. Human scroll coefficient of variation runs 35–60%; bots produce uniform or linearly-interpolated velocities.session age ≥ 3 s
Mouse tremor10 mouse events within a 100–500 ms window whose mean jerk > 5 px/s³ AND stdDev between 8 and 5×10&sup6;. Upper bound excludes scripted teleport jumps (10&sup8;+) while admitting ordinary high-DPI cursor motion (10⁴–10&sup6;).
Speed variance10 mouse events with 5+ nonzero speeds, stdDev > 40% of mean, speed range > 200 px/s. Catches fast-cursor humans whose jerk signatures exceed the tremor upper bound.session age ≥ 2 s

8.3 Hard-Reject Guards (Required)

Two guards run before the proof paths and override them. Either firing must reject the session.

8.4 Why thresholds are tight, not loose

A session that fails to demonstrate human signal is held in a "not-yet-proven" state — the engine waits for the next batch rather than committing to a verdict on too little data. This is deliberately asymmetric: false negatives (real humans temporarily failing to qualify) cost only a delayed first intervention, but false positives (bots admitted to the inference pipeline) cost real LLM dollars per batch. The reference implementation publishes proven-human events on a dedicated NATS subject so downstream consumers can reason about session liveness without re-running the gate.

8.5 Detection Logging

Gate verdicts should be logged with both the verdict and the underlying joint distribution at decision time:

FieldTypeDescription
session_idstringSession identifier
verdictstring"proven_human" | "rejected" | "pending"
proof_methodstring | null"scroll_variance" | "mouse_tremor" | "mouse_speed_variance" | null
rejection_reasonstring | null"synthetic" | "burst" | "user_agent" | "ip_blocklist" | null
metricsobjectComputed scroll / tremor / speed / burst / synthetic features at decision time (mean, stdDev, counts, windows). Persisted unconditionally so the training corpus for future gate revisions captures the full joint distribution, not only the path that short-circuited the verdict.
event_countnumberEvents analyzed in the batch
session_age_msnumberTime since session start

8.6 Future Threat: LLM-driven crawlers

Today's automation doesn't produce physiological signatures — mouse tremor and scroll-velocity variance remain reliable. Tomorrow's Opus-class models running site crawlers may. The space of physiological human signal is finite; the gate's thresholds are designed to evolve as that threat materializes, and the logged metrics distribution is what makes that evolution data-driven.

9. Consumption Contract

The consumption contract defines how a Consumer — typically an LLM or an application feeding an LLM — uses EITP packets. The goal is to produce responses that feel naturally informed, not surveilled.

9.1 Injection

The EITP packet should be injected into the LLM's system prompt or provided as a tool call parameter. The Consumer should present the packet dimensions in priority order:

  1. Spatial — where the user is on the page
  2. Temporal — how long they've been there
  3. Emotional — what they appear to be feeling
  4. Behavioral + Intent — what patterns are detected
  5. Page Content — what they're looking at
  6. Global Intelligence — market-level context

This priority order reflects what a skilled human salesperson would notice: where someone is standing, how long they've been there, their body language, what they're looking at, and broader market context — in that order.

9.2 Anti-Creepiness Rules

These rules are normative. A conformant Consumer:

The “Velvet Gloves” principle. The intervention must feel like the LLM naturally understands the user's situation. If the emotion is decision_paralysis, the right response is: “Choosing between these two can feel tough — want me to break down the key differences?” Not: “I detected you hovering between two options for 3 minutes.”

9.3 Cooldown Compliance

Consumers must respect these timing constraints:

ConstraintDefaultDescription
Intervention cooldown300 seconds (5 min)Minimum time between proactive interventions for the same session. Per-tenant override via seer_config.intervention_gap_ms.
Window suppression120 secondsSuppress proactive interventions when the user has the chat window open
Minimum session time10 secondsGrace period before any intervention is allowed

These defaults prevent the system from being overly aggressive. Consumers may use longer cooldowns but should not use shorter ones.

Changed in v1.2. The intervention cooldown default was raised from 60 s to 300 s (5 min) in May 2026. Production data showed 60 s permitted intervention stacking inside a single buyer's deliberation window — the system was crowding the buyer rather than helping them. 5 min is the floor at which a second proactive intervention reads as a separate attentive moment rather than a continuation.

10. Privacy and Security

10.1 PII Sanitization

Producers must sanitize all text payloads before transmission. The following PII patterns must be replaced with [REDACTED]: email addresses, phone numbers, Social Security numbers, credit card numbers, and zip codes. The specific regex patterns are defined in Section 3.9.

10.2 No Form Values

Form field values must not be transmitted. The form tracker captures only metadata: field type, field name, focus duration, and a boolean indicating whether the field has a value. The actual content the user types is never part of the telemetry stream.

10.3 IP Address Handling

10.4 Tenant Isolation

All message subjects must be tenant-scoped. A Bridge must not allow cross-tenant telemetry. An Inference Engine receiving a batch with a mismatched tenantId must reject it.

10.5 Consent

EITP does not define a consent mechanism. Implementations should comply with applicable privacy regulations (GDPR, CCPA, etc.) regarding behavioral data collection. The protocol is designed to minimize data collection — no PII, no form values, no keystroke logging — but consent for behavioral telemetry remains the implementer's responsibility.

11. Wire Format Examples

11.1 Telemetry Batch

A complete telemetry batch as published to telemetry.raw:

{
  "type": "telemetry_batch",
  "sessionId": "sq_1740700800000_k8f2m9x1q",
  "tenantId": "org_39lXO2Ptox5W4kHBttbNUfOovN1",
  "vertical": "rv_dealer",
  "timestamp": 1740700800000,
  "pageContent": {
    "pageTitle": "2024 Arctic Wolf 3650SUITE | Prosser's Premium RV",
    "h1": "2024 Cherokee Arctic Wolf 3650SUITE",
    "headings": ["Specifications", "Floor Plan", "Features"],
    "structuredData": [{
      "type": "Vehicle",
      "name": "Arctic Wolf 3650SUITE",
      "price": "$59,995"
    }]
  },
  "events": [
    {
      "type": "mouse",
      "timestamp": 1740700800100,
      "currentSection": "pricing",
      "data": {
        "x": 450, "y": 320,
        "vx": 12, "vy": -5,
        "ax": -80, "ay": 15,
        "jx": 200, "jy": -100,
        "speed": 13, "jerk": 224
      }
    },
    {
      "type": "mouse_pause",
      "timestamp": 1740700802500,
      "currentSection": "pricing",
      "data": {
        "duration": 2400,
        "x": 455, "y": 318,
        "viewport": { "relX": 0.32, "relY": 0.42 }
      }
    },
    {
      "type": "price_proximity_enter",
      "timestamp": 1740700803000,
      "currentSection": "pricing",
      "data": {
        "distance": 45,
        "over": false,
        "element_type": "price",
        "currency": "$",
        "value": 59995,
        "isSale": true
      }
    },
    {
      "type": "scroll",
      "timestamp": 1740700805000,
      "currentSection": "specifications",
      "data": {
        "depth": 45,
        "maxDepth": 45,
        "velocity": 120,
        "direction": "down"
      }
    }
  ]
}

11.2 EITP v1.3 Packet

A complete packet as published to seer.{tenantId}.intervention.request.{sessionId}:

{
  "sessionId": "sq_1740700800000_k8f2m9x1q",
  "tenantId": "org_39lXO2Ptox5W4kHBttbNUfOovN1",
  "timestamp": 1740700810000,

  "emotion": {
    "primary":    "paralysis",
    "behavior":   "deliberation",
    "context":    "pricing",
    "confidence": 0.82,
    "intensity":  0.65,
    "trajectory": "intensifying"
  },

  "spatial": {
    "currentSection": "pricing",
    "visitCount": 3,
    "trigger": null
  },

  "temporal": {
    "sessionDuration": 234000,
    "timeSinceLastEmotion": 45000
  },

  "behavioral": {
    "scrollDepth": 72,
    "clickCount": 4
  },

  "patterns": {
    "detected": [
      "extended_dwelling_on_pricing",
      "repeated_section_revisit"
    ]
  },

  "intent": {
    "level": "high",
    "action": "comparison",
    "confidence": 0.75
  },

  "pageContent": {
    "pageTitle": "2024 Arctic Wolf 3650SUITE | Prosser's Premium RV",
    "h1": "2024 Cherokee Arctic Wolf 3650SUITE",
    "headings": ["Specifications", "Floor Plan", "Features"],
    "structuredData": [{
      "type": "Vehicle",
      "name": "Arctic Wolf 3650SUITE",
      "price": "$59,995"
    }],
    "visibleContent": "Experience the ultimate in fifth wheel living..."
  },

  "globalIntelligence": {
    "evi":                  0.73,
    "trend":                "rising",
    "percentile":           85,
    "isAnomaly":            false,
    "anomalySeverity":      "none",
    "predictedEvi":         0.76,
    "predictedDirection":   "up",
    "predictionConfidence": 0.68,
    "contagion":            null
  },

  "channel": {
    "referrer":     "rvtrader.com",
    "utm_source":   "google",
    "utm_medium":   "cpc",
    "utm_campaign": "summer-inventory"
  }
}

12. Implementation Guidance

12.1 Building a Minimal Producer

The fastest path to an EITP producer is three tracker modules with batched WebSocket delivery:

  1. Mouse tracker — position + velocity at 20Hz. Skip acceleration/jerk for v1.
  2. Click tracker — position, target element, rage click detection.
  3. Scroll tracker — depth and direction.
  4. Batch buffer — accumulate events, flush every 3 seconds over WebSocket.

This minimal producer gives an inference engine enough signal to detect: frustration (rage clicks), hesitation (slow mouse near CTAs), engagement depth (scroll), and comparison behavior (scroll direction reversals).

12.2 Building a Minimal Consumer

A minimal consumer parses three fields from the EITP packet and prepends them to the LLM system prompt:

// Minimum viable consumption
const emotionLine = packet.emotion.behavior
  ? `${packet.emotion.primary} / ${packet.emotion.behavior}`
  : packet.emotion.primary;

const context = [
  `User state: ${emotionLine} (${packet.emotion.trajectory})`,
  packet.emotion.context && `About: ${packet.emotion.context}`,
  `Currently viewing: ${packet.spatial.currentSection}`,
  `Page: ${packet.pageContent?.h1 || packet.pageContent?.pageTitle || 'unknown'}`,
  `Time on site: ${Math.round(packet.temporal.sessionDuration / 60000)} minutes`
].filter(Boolean).join('\n');

// Inject into system prompt
systemPrompt = context + '\n\n' + systemPrompt;

Even this minimal injection transforms the LLM's first response from generic to contextual. The full reference implementation adds priority ordering, anti-creepiness instructions, intervention history, and page content awareness.

12.3 Building a Bridge

A Bridge requires:

  1. WebSocket server accepting connections from producers
  2. Message bus client (NATS, Redis Pub/Sub, Kafka, or equivalent) for internal routing
  3. IP injection — extract req.socket.remoteAddress (or X-Forwarded-For behind a proxy) and inject into the payload before forwarding
  4. Subject whitelist — untrusted clients can only publish to telemetry.raw
  5. Rate limiter — per-IP or per-session throttling
  6. Max message size — reject payloads exceeding 50KB

Appendix A: Complete Event Type Catalog

Event TypeSourceKey Fields
mouseMouse Trackerx, y, vx, vy, ax, ay, jx, jy, speed, jerk
circular_motionGesture Detectioncircularity, radius, duration
direction_changesGesture Detectioncount, duration, avgSpeed
mouse_pauseGesture Detectionduration, x, y, viewport
mouse_exitMouse Trackerangle, velocity, edge, x, y
iframe_exitMouse Trackerx, y, iframeSrc
clickClick Trackerx, y, target, mouseVelocity, mouseJerk
rage_clickClick Trackercount, area
scrollScroll Trackerdepth, maxDepth, velocity, direction
{kind}_proximity_enterProximity Enginedistance, over, element_type, intent, signals
{kind}_hoverProximity Engineover, element_type, meta
{kind}_proximityProximity Enginedistance, element_type
{kind}_proximity_leaveProximity Engineelement_type
pricing_comparisonProximity Enginetier_count, tiers
viewport_resizeViewport Trackerwidth, height, orientation
viewport_boundaryViewport Trackerboundary, scrollDepth
viewport_approachViewport Trackeredge, distance, velocity, vector
tab_switchTab Trackeraction, awayDuration, totalSwitches
long_tab_returnTab TrackerawayDuration, sessionTime
form_focusForm Trackertype, name, id
form_blurForm Trackertype, name, duration, hasValue
form_submitForm Trackerid, action, method
text_selectionSelection Trackertext, length, hasPrice
text_selection_with_priceSelection Trackertext, price, length

Additionally, the 11 proximity element kinds produce 44 templated event strings (4 events × 11 kinds), bringing the total event vocabulary to approximately 63 unique strings.

Appendix B: Proximity Element Selectors

The proximity engine identifies elements using CSS selectors. Implementations may customize these selectors for their domain. The reference implementation uses:

KindSelectors (abbreviated)
price[class*="price"], [data-price], .cost, .amount, .msrp, .sale-price
purchase_buttonbutton:has-text("buy"), button:has-text("add to cart"), [data-action="purchase"]
checkout_buttonbutton:has-text("checkout"), button:has-text("complete"), .checkout-btn
subscribe_buttonbutton:has-text("subscribe"), button:has-text("upgrade"), .subscribe-cta
demo_ctaa:has-text("demo"), a:has-text("trial"), button:has-text("schedule")
signup_ctaa:has-text("sign up"), button:has-text("register"), button:has-text("get started")
tier_card[class*="tier"], [class*="plan-card"], [class*="pricing-card"]
pricing_nava[href*="pricing"], a:has-text("pricing"), nav a:has-text("plans")
feature_nava[href*="features"], a:has-text("features")
learn_morea:has-text("learn more"), a:has-text("read more")
cta.cta, [class*="cta"], button[class*="primary"]

Appendix C: Configuration Reference

Default values for all configurable parameters in the reference implementation:

Signal Capture

ParameterDefaultUnitModule
Sampling rate20HzMouse
History buffer size100samplesMouse
Micro-movement threshold20px/sGestures (dwell)
Dwell threshold500msGestures (dwell)
Circularity threshold0.85unitlessGestures (circular)
Circle minimum radius20pxGestures (circular)
Zigzag direction changes>6countGestures (zigzag)
Zigzag minimum movement30pxGestures (zigzag)
Zigzag debounce300msGestures (zigzag)
Rage click threshold3clicksClick
Rage click window500msClick
Scroll debounce100msScroll
Proximity grid cell size160pxProximity
Proximity enter radius140pxProximity
Proximity spatial hysteresis12pxProximity
Proximity time hysteresis600msProximity
Viewport boundary100pxViewport
Exit vector threshold400px/sViewport
Resize debounce250msViewport
Long absence threshold30,000msTab
Field abandonment duration2,000msForm
Inactivity threshold5,000msMouse

Transport

ParameterDefaultUnit
Batch size50events
Flush interval3,000ms
Priority flush threshold40events
Maximum buffer500events
Reconnect base delay1,000ms
Reconnect max delay30,000ms
Reconnect max attempts5count
Keepalive interval30,000ms
Max message size50,000bytes
Max events per second500count

Inference & Intervention

ParameterDefaultUnit
Buffer flush interval10,000ms
Intervention cooldown60,000ms
Window suppression120,000ms
Minimum session time10,000ms
Bot classification wait3 batches~30s
EITP enrichment timeout1,500ms
Session timeout300,000ms (5 min)

EITP v1.3 Specification — May 2026
Published by SentientIQ
Licensed under CC BY 4.0

Try the Playground