EITP v1.1
Emotional Intelligence Transfer Protocol
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.
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:
- Decision paralysis — 16 conversions observed, 38.9 minute average session duration, 25.1 emotional events per session
- Overwhelm — 10 conversions, 19.2 minute average, 45.6 events per session
- Cognitive overload — 9 conversions, 126.5 minute average, 17.3 events per session
- Frustration — 6 conversions, 42 minute average, 50 events per session
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
- Implementable. A developer can build a conformant producer or consumer from this document alone.
- Layered. You can implement the packet format (Section 5) without the inference pipeline (Section 7). A consumer needs only Sections 5, 6, and 9.
- 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.
- 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.1 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 22-value taxonomy (Section 6) describing the inferred emotional state of the user.
- 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.
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:
- Must implement at least 3 of the 8 tracker modules defined in Section 3
- Must batch events before transmission (Section 4.3)
- Must sanitize PII from all text payloads before transmission (Section 10.1)
- Must include a session identifier with every batch
- Must include a tenant identifier with every batch
- Should implement reconnection with exponential backoff (Section 4.4)
2.2 Producer Level 2 (Full)
A Level 2 Producer meets all Level 1 requirements and additionally:
- Must implement all 8 tracker modules
- Must implement the proximity engine (Section 3.5)
- Must implement page content extraction (Section 3.10)
- Must include page content in telemetry batches
2.3 Bridge
A conformant Bridge:
- Must accept WebSocket connections from producers
- Must inject the client's IP address into telemetry payloads server-side (Section 4.5)
- Must enforce rate limiting (Section 4.6)
- Must enforce a subject/topic whitelist on publish operations
- Must enforce a maximum message size
- Should support the NATS text protocol framing (Section 4.1)
2.4 Inference Engine
A conformant Inference Engine:
- Must produce EITP v1.1 packets conforming to Section 5
- Must classify emotions using the 22-value taxonomy (Section 6)
- Must implement bot filtering meeting the minimum requirements of Section 8
- Should track session emotional history for trajectory calculation
- May use any inference strategy (AI, rules, statistical models, or hybrid)
2.5 Consumer
A conformant Consumer:
- Must accept EITP v1.1 packets as defined in Section 5
- Must follow the consumption contract (Section 9)
- Must respect cooldown fields
- Must not expose telemetry details to the end user
3. Signal Capture Layer
The signal capture layer consists of eight independent tracker modules 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 the proximity engine and page content extractor.
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.
| Field | Type | Unit | Description |
|---|---|---|---|
x | number | px | Cursor X position (clientX) |
y | number | px | Cursor Y position (clientY) |
vx | number | px/s | X velocity |
vy | number | px/s | Y velocity |
ax | number | px/s² | X acceleration |
ay | number | px/s² | Y acceleration |
jx | number | px/s³ | X jerk |
jy | number | px/s³ | Y jerk |
speed | number | px/s | Velocity magnitude |
jerk | number | px/s³ | Jerk magnitude |
Configuration
| Parameter | Default | Unit |
|---|---|---|
| Sampling rate | 20 | Hz |
| History buffer | 100 | samples |
| Inactivity threshold | 5000 | ms |
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
| Field | Type | Description |
|---|---|---|
circularity | number (0–1) | Circularity score |
radius | number (px) | Average radius from centroid |
duration | number (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
| Field | Type | Description |
|---|---|---|
count | number | Direction changes in window (>6) |
duration | number (ms) | Time span of window |
avgSpeed | number (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
| Field | Type | Description |
|---|---|---|
duration | number (ms) | Time spent dwelling |
x, y | number (px) | Cursor position |
viewport.relX, viewport.relY | number (0–1) | Relative viewport position |
Thresholds: speed < 20 px/s, duration > 500ms
Exit Vector
Event: mouse_exit — emitted when the cursor leaves the document.
| Field | Type | Description |
|---|---|---|
angle | number (degrees) | Exit angle from viewport center |
velocity | number (px/s) | Exit speed |
edge | string | "top" | "right" | "bottom" | "left" |
x, y | number (px) | Exit position |
3.3 Click Tracker
Event: click
| Field | Type | Description |
|---|---|---|
x, y | number (px) | Click position |
target.tag | string | Element tag name |
target.class | string | Element class name |
target.id | string | Element ID |
target.text | string | Text content (first 50 chars) |
mouseVelocity | number (px/s) | Cursor speed at moment of click |
mouseJerk | number (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.
| Field | Type | Description |
|---|---|---|
count | number | Number of rapid clicks (≥3) |
area | number (px²) | Bounding box area of click cluster |
Thresholds: ≥ 3 clicks within 500ms
3.4 Scroll Tracker
Event: scroll
Debounced at 100ms.
| Field | Type | Description |
|---|---|---|
depth | number (0–100) | Current scroll depth percentage |
maxDepth | number (0–100) | Maximum depth reached this session |
velocity | number (px/s) | Scroll velocity (positive = down) |
direction | string | "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:
| Kind | Intent Level | Examples |
|---|---|---|
price | — | Price displays, cost elements |
purchase_button | high | Buy, Add to Cart, Order |
checkout_button | high | Checkout, Complete Purchase |
subscribe_button | high | Subscribe, Upgrade |
demo_cta | medium-high | Book Demo, Schedule, Try |
signup_cta | medium-high | Sign Up, Register, Get Started |
tier_card | medium | Pricing tier/plan containers |
pricing_nav | medium | Pricing navigation links |
feature_nav | low-medium | Feature navigation links |
learn_more | low-medium | Learn More, Read More |
cta | low | Generic calls to action |
Proximity Events
For each element kind, four events are generated:
{kind}_proximity_enter— cursor enters the 140px radius{kind}_hover— cursor is directly over the element{kind}_proximity— cursor is within radius but not directly over{kind}_proximity_leave— cursor exits the 152px leave radius (140px + 12px spatial hysteresis) or 600ms time hysteresis elapses
Proximity Enter Payload
| Field | Type | Description |
|---|---|---|
distance | number (px) | Distance from element edge |
over | boolean | True if directly over element |
element_type | string | The element kind |
text | string | Element text (first 80 chars) |
intent | string | Intent level for this kind |
signals.hasDiscount | boolean | Text/class contains discount language |
signals.hasTrial | boolean | Text/class contains trial language |
signals.hasUrgency | boolean | Text/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
| Parameter | Default | Unit |
|---|---|---|
| Grid cell size | 160 | px |
| Enter radius | 140 | px |
| Spatial hysteresis | 12 | px (leave = 152px) |
| Time hysteresis | 600 | ms |
3.6 Viewport Tracker
Event: viewport_resize
Debounced at 250ms.
| Field | Type | Description |
|---|---|---|
width, height | number (px) | Viewport dimensions |
orientation | string | "landscape" | "portrait" |
Event: viewport_boundary
Fires once when user scrolls to within 50px of the page top or bottom.
| Field | Type | Description |
|---|---|---|
boundary | string | "top" | "bottom" |
scrollDepth | number | 0 (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.
| Field | Type | Description |
|---|---|---|
edge | string | "top" |
distance | number (px) | Distance from top edge |
velocity | number (px/s) | Cursor speed magnitude |
vector.vx, vector.vy | number (px/s) | Velocity components |
Thresholds: distance < 100px, upward velocity > 400 px/s
3.7 Tab Tracker
Event: tab_switch
| Field | Type | Description |
|---|---|---|
action | string | "away" | "return" |
awayDuration | number (ms) | Time spent away (on return) |
activeTime | number (ms) | Time spent active (on away) |
totalSwitches | number | Cumulative 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.
| Field | Type | Description |
|---|---|---|
awayDuration | number (ms) | Time away (>30,000ms) |
sessionTime | number (ms) | Total session time |
3.8 Form Tracker
Event: form_focus
| Field | Type | Description |
|---|---|---|
type | string | Field type (text, email, select, etc.) |
name | string | Field name attribute |
id | string | Field ID attribute |
Event: form_blur
| Field | Type | Description |
|---|---|---|
type | string | Field type |
name | string | Field name attribute |
duration | number (ms) | Time spent focused |
hasValue | boolean | Whether 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
| Field | Type | Description |
|---|---|---|
id | string | Form ID |
action | string | Form action URL |
method | string | GET | POST |
3.9 Selection Tracker
Event: text_selection
Emitted on non-empty text selection. Text is PII-sanitized before transmission.
| Field | Type | Description |
|---|---|---|
text | string | Sanitized text (first 100 chars) |
length | number | Full selection length |
hasPrice | boolean | Selection matches price pattern |
Event: text_selection_with_price
Emitted additionally when the selected text contains a price pattern ($NNN.NN).
| Field | Type | Description |
|---|---|---|
text | string | Raw text (first 100 chars) |
price | string | Matched price string |
length | number | Full selection length |
PII Sanitization Patterns
Producers must replace the following patterns with [REDACTED] before transmission:
| Pattern | Regex |
|---|---|
[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:
| Field | Description | Limits |
|---|---|---|
pageTitle | Document title | — |
h1 | First H1 element text | — |
headings | H2 element texts | Max 8 |
tables | Table headers and row data | Max 3 tables, 15 rows each |
structuredData | JSON-LD data (Product, Vehicle, Offer, ItemList, FAQPage) | — |
visibleContent | Paragraph text near viewport center | Max 5 paragraphs |
meta | Description 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
| Command | Direction | Format |
|---|---|---|
PUB | Client → Bridge | PUB <subject> <size>\r\n<payload>\r\n |
SUB | Client → Bridge | SUB <subject> <sid>\r\n |
MSG | Bridge → Client | MSG <subject> <sid> <size>\r\n<payload>\r\n |
PING | Both | PING\r\n |
PONG | Both | PONG\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:
| Subject | Direction | Payload |
|---|---|---|
telemetry.raw | Producer → Bridge | Telemetry batch (Section 4.3) |
emotions.{tenantId}.detected.{sessionId} | Engine → Persistence | Emotion event |
emotions.{tenantId}.{sessionId} | Engine → Consumer | Emotional profile for chat context |
seer.{tenantId}.intervention.request.{sessionId} | Engine → Consumer | EITP v1.1 packet (Section 5) |
bot.{tenantId}.detection.{sessionId} | Engine → Analytics | Bot 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
| Parameter | Default | Description |
|---|---|---|
| Flush interval | 3000ms | Timer-based flush |
| Batch size | 50 events | Maximum events per batch |
| Priority threshold | 40 events | Early flush for priority events |
| Max buffer | 500 events | Hard 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:
| Parameter | Value |
|---|---|
| Base delay | 1,000ms |
| Backoff factor | 2 |
| Maximum delay | 30,000ms |
| Jitter | Random 0–1,000ms |
| Maximum attempts | 5 |
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:
| Limit | Value |
|---|---|
| Maximum message size | 50,000 bytes |
| Maximum events per second (producer) | 500 |
| Maximum events per type per second | 100 |
5. The EITP v1.1 Packet Normative
The EITP v1.1 packet is the core data structure of the protocol. It is a JSON object with eight dimensions that together describe the user's emotional state, behavioral context, and the content they are engaging with. 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 */ }
}
| Field | Type | Required | Description |
|---|---|---|---|
sessionId | string | Yes | Unique session identifier |
tenantId | string | Yes | Tenant/organization identifier |
timestamp | number | Yes | Epoch milliseconds at packet creation |
5.2 Dimension 1: Emotion
{
"primary": "decision_paralysis",
"confidence": 0.82,
"intensity": 0.65,
"trajectory": "intensifying"
}
| Field | Type | Required | Description |
|---|---|---|---|
primary | string | Yes | One of the 22 canonical emotions (Section 6) |
confidence | number (0.0–1.0) | Yes | Inference engine's certainty in this classification |
intensity | number (0.0–1.0) | Yes | Strength of the emotional signal |
trajectory | string | Yes | "intensifying" | "stable" | "cooling" |
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"
}
| Field | Type | Required | Description |
|---|---|---|---|
currentSection | string | Yes | DOM section ID the user is currently viewing |
visitCount | number | Yes | How many times the user has visited this section |
trigger | string | null | No | Spatial 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
}
| Field | Type | Required | Description |
|---|---|---|---|
sessionDuration | number (ms) | Yes | Time since session start |
timeSinceLastEmotion | number (ms) | Yes | Time since last emotion classification |
5.5 Dimension 4: Behavioral
{
"scrollDepth": 72,
"clickCount": 4
}
| Field | Type | Required | Description |
|---|---|---|---|
scrollDepth | number (0–100) | Yes | Maximum scroll depth in current batch |
clickCount | number | Yes | Click events in current batch |
5.6 Dimension 5: Patterns
{
"detected": [
"extended_dwelling_on_pricing",
"comparison_shopping_tab_pattern"
]
}
| Field | Type | Required | Description |
|---|---|---|---|
detected | string[] | Yes | Behavioral 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
}
| Field | Type | Required | Description |
|---|---|---|---|
level | string | Yes | Intent strength (e.g., "high", "medium", "low") |
action | string | Yes | Inferred action (e.g., "comparison", "purchase", "exit") |
confidence | number (0.0–1.0) | Yes | Confidence 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"
}
}
| Field | Type | Required |
|---|---|---|
pageTitle | string | null | No |
h1 | string | null | No |
headings | string[] | No |
tables | array of {headers, rows} | No |
structuredData | array of objects | No |
visibleContent | string | null | No |
meta | object | No |
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 Optional
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
}
| Field | Type | Description |
|---|---|---|
evi | number | Emotional Volatility Index (aggregate across sessions) |
trend | string | Current trend direction |
percentile | number | Percentile rank against historical baselines |
isAnomaly | boolean | Whether current conditions are anomalous |
predictedEvi | number | 30-minute EVI prediction |
contagion | object | null | Emotional 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 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.
6. The 22-Emotion Taxonomy Normative
A conformant Inference Engine must classify emotions into exactly
these 22 canonical values. The taxonomy is closed — implementations may
use additional internal labels but must map to a canonical value when
producing EITP packets. The value "unknown" is explicitly prohibited.
Cognitive States
| Value | Description |
|---|---|
uncertainty | Ambiguous intent, insufficient signal to classify further |
decision_paralysis | Hovering over multiple options without committing. Repeated section revisits, dwell on comparison elements. |
analysis_paralysis | Over-researching, unable to synthesize. Deep scrolling, tab switching, extended sessions. |
cognitive_load | Processing too much information simultaneously. Slowed mouse, erratic scroll, section bouncing. |
confusion | Misunderstanding interface or content. Circular mouse motion, rage clicks on non-interactive elements. |
deliberation | Active weighing of options — not stuck. Methodical section visits, steady pace. |
ambivalence | Equal pull toward multiple options. Alternating between items without deepening on either. |
Negative States
| Value | Description |
|---|---|
frustration | Repeated failed interactions. Rage clicks, high jerk, erratic velocity patterns. |
overwhelm | Volume of choices or information exceeds processing capacity. Rapid shallow scrolling, short dwell times. |
anxiety | General tension in interaction pattern. Hesitant mouse, frequent pauses, incomplete actions. |
payment_anxiety | Specific tension around pricing or checkout. Dwelling on price elements, approaching and retreating from purchase CTAs. |
disengagement | Declining interaction, imminent abandonment. Decreasing events, exit intent signals, long inactivity. |
Positive States
| Value | Description |
|---|---|
curiosity | Active exploration, increasing engagement. Accelerating scroll depth, section discovery, click-throughs. |
exploratory_engagement | Broad browsing without a specific target. Wide section coverage, moderate pace, no repeated revisits. |
purchase_intent | Behavioral signals of imminent conversion. CTA proximity, form interaction, pricing focus. |
urgency | Time-pressured decision making. High velocity, direct navigation, minimal browsing. |
trust_building | Seeking validation signals. Focus on reviews, credentials, testimonials, about pages. |
validation_seeking | Confirming a tentatively made decision. Returning to a previously viewed item, checking details again. |
satisfaction | Positive outcome signal. Smooth navigation post-action, decreased urgency metrics. |
Mixed States
| Value | Description |
|---|---|
hesitation | Interest combined with reluctance. Approaching then retreating from CTAs, dwell near conversion points. |
price_sensitivity | Focused attention on pricing elements. Price text selection, pricing tier comparison, payment calculator interaction. |
comparison_shopping | Active comparison behavior. Tab switching (especially long returns), multi-item viewing, pricing comparison events. |
Production Evidence
| Emotion | Conversions | Avg Session | Avg Events |
|---|---|---|---|
decision_paralysis | 16 | 38.9 min | 25.1 |
overwhelm | 10 | 19.2 min | 45.6 |
cognitive_load | 9 | 126.5 min | 17.3 |
frustration | 6 | 42.0 min | 50.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 emotion labels for internal use
(e.g., vertical-specific states like "trade_in_anxiety" or "spouse_approval_seeking").
However, when producing EITP v1.1 packets, the emotion.primary field
must contain one of the 22 canonical values. Internal labels
may be included in the patterns.detected array.
7. Inference Pipeline Informative
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.
7.1 Pipeline Architecture
7.2 Buffering
Raw telemetry is accumulated for 10 seconds per session before processing. This reduces API calls by ~50% compared to 5-second windows while maintaining sufficient temporal resolution for emotional classification.
7.3 Two-Tier AI Inference
The reference implementation uses a two-tier LLM approach for cost optimization:
| Tier | Model | Token Budget | Temperature | Purpose |
|---|---|---|---|---|
| Triage | Claude Haiku | 800 | 0.3 | Fast classification + gate |
| Deep | Claude Sonnet | 800 | 0.5 | Final classification + intervention decision |
The triage tier classifies the emotion and returns a needsSonnet boolean. When
false, the emotion is recorded for dashboards but no intervention is triggered,
saving the cost of a Sonnet call. In practice, ~60–70% of batches are resolved at
the triage tier.
7.4 Knowledge Injection
The inference engine injects proven patterns from a knowledge store into the LLM prompt. Patterns are filtered by: tenant match, vertical match, confidence ≥ 70, and sample size ≥ 5. This gives the LLM awareness of what has worked before for similar behavioral patterns.
7.5 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.6 Feedback Loop
A 60-second aggregation cycle processes emotional events and produces pattern intelligence:
- Multi-dimensional grouping: emotion + section + geography + vertical
- Wilson Score confidence: sample-size-aware confidence intervals
- Spike detection: recent 24h count / 7-day baseline > 1.5x
- Anomaly detection: Z-score > 2.0
- Trend direction: increasing (>1.2x), decreasing (<0.8x), stable
Validated patterns (sample size ≥ 10) are injected back into inference prompts, creating a closed loop where the system learns from its own observations.
8. Bot Filtering Normative
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.
8.1 Minimum Requirements
An Inference Engine must implement at least the following:
- Connection-only probes: Sessions producing only
connection,tab_switch,viewport_resize, orviewport_boundaryevents for >10 seconds must be classified as bots. - User-agent matching: Check user-agent strings against known crawler, headless browser, and automation tool patterns.
- Behavioral velocity: Detect impossible interaction speeds:
- Click rate > 50 per batch
- Scroll events > 100 per batch
- Consecutive event intervals < 15ms
- Timing coefficient of variation < 0.1 (robotic regularity)
8.2 Recommended Detection
Inference Engines should additionally implement:
- IP reputation: Known datacenter, proxy, and cloud provider IP ranges
- Pattern analysis: Perfect linear scrolling, instant navigation (<10ms), hover bursts (5+ in <50ms), ghost form submissions
- AI-assisted classification: A lightweight LLM call on accumulated telemetry (after 3 batches / ~30 seconds) for ambiguous cases
8.3 Detection Logging
Bot detections should be logged with:
| Field | Type | Description |
|---|---|---|
session_id | string | Session identifier |
classification | string | "human" | "bot" | "uncertain" |
confidence | number | Classification confidence |
reasoning | string | Human-readable explanation |
signals | string[] | Detection signals that fired |
event_count | number | Events analyzed |
9. Consumption Contract Normative
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:
- Spatial — where the user is on the page
- Temporal — how long they've been there
- Emotional — what they appear to be feeling
- Behavioral + Intent — what patterns are detected
- Page Content — what they're looking at
- 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:
- Must not reference mouse movements, scroll behavior, or click patterns in user-facing output
- Must not mention exit intent detection
- Must not say “I noticed you were looking at…” or equivalent surveillance language
- Must not reference dwell time, hover behavior, or proximity events
- Must use language that implies understanding, not observation
- May reference page content naturally (as a human salesperson would know what is on the shelf)
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:
| Constraint | Default | Description |
|---|---|---|
| Intervention cooldown | 60 seconds | Minimum time between proactive interventions for the same session |
| Window suppression | 120 seconds | Suppress proactive interventions when the user has the chat window open |
| Minimum session time | 10 seconds | Grace 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.
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
- IP addresses must be injected server-side by the Bridge (Section 4.5)
- IP addresses should be used only for geolocation (city/region) and bot detection
- IP addresses should not be persisted beyond the session lifetime
- IP addresses must not appear in EITP packets delivered to Consumers
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.1 Packet
A complete packet as published to seer.{tenantId}.intervention.request.{sessionId}:
{
"sessionId": "sq_1740700800000_k8f2m9x1q",
"tenantId": "org_39lXO2Ptox5W4kHBttbNUfOovN1",
"timestamp": 1740700810000,
"emotion": {
"primary": "decision_paralysis",
"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,
"predictedEvi": 0.76,
"contagion": null
}
}
12. Implementation Guidance Informative
12.1 Building a Minimal Producer
The fastest path to an EITP producer is three tracker modules with batched WebSocket delivery:
- Mouse tracker — position + velocity at 20Hz. Skip acceleration/jerk for v1.
- Click tracker — position, target element, rage click detection.
- Scroll tracker — depth and direction.
- 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 context = [
`User emotion: ${packet.emotion.primary} (${packet.emotion.trajectory})`,
`Currently viewing: ${packet.spatial.currentSection}`,
`Page: ${packet.pageContent?.h1 || packet.pageContent?.pageTitle || 'unknown'}`,
`Time on site: ${Math.round(packet.temporal.sessionDuration / 60000)} minutes`
].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:
- WebSocket server accepting connections from producers
- Message bus client (NATS, Redis Pub/Sub, Kafka, or equivalent) for internal routing
- IP injection — extract
req.socket.remoteAddress(orX-Forwarded-Forbehind a proxy) and inject into the payload before forwarding - Subject whitelist — untrusted clients can only publish to
telemetry.raw - Rate limiter — per-IP or per-session throttling
- Max message size — reject payloads exceeding 50KB
Appendix A: Complete Event Type Catalog
| Event Type | Source | Key Fields |
|---|---|---|
mouse | Mouse Tracker | x, y, vx, vy, ax, ay, jx, jy, speed, jerk |
circular_motion | Gesture Detection | circularity, radius, duration |
direction_changes | Gesture Detection | count, duration, avgSpeed |
mouse_pause | Gesture Detection | duration, x, y, viewport |
mouse_exit | Mouse Tracker | angle, velocity, edge, x, y |
iframe_exit | Mouse Tracker | x, y, iframeSrc |
click | Click Tracker | x, y, target, mouseVelocity, mouseJerk |
rage_click | Click Tracker | count, area |
scroll | Scroll Tracker | depth, maxDepth, velocity, direction |
{kind}_proximity_enter | Proximity Engine | distance, over, element_type, intent, signals |
{kind}_hover | Proximity Engine | over, element_type, meta |
{kind}_proximity | Proximity Engine | distance, element_type |
{kind}_proximity_leave | Proximity Engine | element_type |
pricing_comparison | Proximity Engine | tier_count, tiers |
viewport_resize | Viewport Tracker | width, height, orientation |
viewport_boundary | Viewport Tracker | boundary, scrollDepth |
viewport_approach | Viewport Tracker | edge, distance, velocity, vector |
tab_switch | Tab Tracker | action, awayDuration, totalSwitches |
long_tab_return | Tab Tracker | awayDuration, sessionTime |
form_focus | Form Tracker | type, name, id |
form_blur | Form Tracker | type, name, duration, hasValue |
form_submit | Form Tracker | id, action, method |
text_selection | Selection Tracker | text, length, hasPrice |
text_selection_with_price | Selection Tracker | text, 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:
| Kind | Selectors (abbreviated) |
|---|---|
price | [class*="price"], [data-price], .cost, .amount, .msrp, .sale-price |
purchase_button | button:has-text("buy"), button:has-text("add to cart"), [data-action="purchase"] |
checkout_button | button:has-text("checkout"), button:has-text("complete"), .checkout-btn |
subscribe_button | button:has-text("subscribe"), button:has-text("upgrade"), .subscribe-cta |
demo_cta | a:has-text("demo"), a:has-text("trial"), button:has-text("schedule") |
signup_cta | a:has-text("sign up"), button:has-text("register"), button:has-text("get started") |
tier_card | [class*="tier"], [class*="plan-card"], [class*="pricing-card"] |
pricing_nav | a[href*="pricing"], a:has-text("pricing"), nav a:has-text("plans") |
feature_nav | a[href*="features"], a:has-text("features") |
learn_more | a: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
| Parameter | Default | Unit | Module |
|---|---|---|---|
| Sampling rate | 20 | Hz | Mouse |
| History buffer size | 100 | samples | Mouse |
| Micro-movement threshold | 20 | px/s | Gestures (dwell) |
| Dwell threshold | 500 | ms | Gestures (dwell) |
| Circularity threshold | 0.85 | unitless | Gestures (circular) |
| Circle minimum radius | 20 | px | Gestures (circular) |
| Zigzag direction changes | >6 | count | Gestures (zigzag) |
| Zigzag minimum movement | 30 | px | Gestures (zigzag) |
| Zigzag debounce | 300 | ms | Gestures (zigzag) |
| Rage click threshold | 3 | clicks | Click |
| Rage click window | 500 | ms | Click |
| Scroll debounce | 100 | ms | Scroll |
| Proximity grid cell size | 160 | px | Proximity |
| Proximity enter radius | 140 | px | Proximity |
| Proximity spatial hysteresis | 12 | px | Proximity |
| Proximity time hysteresis | 600 | ms | Proximity |
| Viewport boundary | 100 | px | Viewport |
| Exit vector threshold | 400 | px/s | Viewport |
| Resize debounce | 250 | ms | Viewport |
| Long absence threshold | 30,000 | ms | Tab |
| Field abandonment duration | 2,000 | ms | Form |
| Inactivity threshold | 5,000 | ms | Mouse |
Transport
| Parameter | Default | Unit |
|---|---|---|
| Batch size | 50 | events |
| Flush interval | 3,000 | ms |
| Priority flush threshold | 40 | events |
| Maximum buffer | 500 | events |
| Reconnect base delay | 1,000 | ms |
| Reconnect max delay | 30,000 | ms |
| Reconnect max attempts | 5 | count |
| Keepalive interval | 30,000 | ms |
| Max message size | 50,000 | bytes |
| Max events per second | 500 | count |
Inference & Intervention
| Parameter | Default | Unit |
|---|---|---|
| Buffer flush interval | 10,000 | ms |
| Intervention cooldown | 60,000 | ms |
| Window suppression | 120,000 | ms |
| Minimum session time | 10,000 | ms |
| Bot classification wait | 3 batches | ~30s |
| EITP enrichment timeout | 1,500 | ms |
| Session timeout | 300,000 | ms (5 min) |
EITP v1.1 Specification — February 2026
Published by SentientIQ
Licensed under CC BY 4.0