Events & Analytics
Odyssey collects behavioral analytics through a lightweight embed script that tracks how users navigate through your journeys. This guide covers the event types, how data is collected, and how the ingest API works.
Overview
Odyssey's analytics approach is designed to be:
- Privacy-first - No PII or field values are collected
- Non-invasive - Never blocks or modifies your application
- Semantic - Tracks high-level behavior, not low-level interactions
- Reliable - Uses best-effort delivery with buffering
All analysis and modeling happens server-side. The embed script is purely for data collection.
Event types
Odyssey tracks coarse-grained, semantic events that represent meaningful user actions:
Session events
Track the beginning and end of user sessions:
- Name
session_start- Description
Fired when a user begins a new journey session. A session represents a single attempt to complete a journey.
- Name
session_end- Description
Fired when a session completes or times out. Includes completion status and duration.
Navigation events
Track user movement through pages and steps:
- Name
page_view- Description
Fired when any page loads. Includes the page URL and title.
- Name
step_view- Description
Fired when a user enters a specific journey step. Includes the step identifier (stepKey).
Interaction events
Track field-level interactions without capturing values:
- Name
field_focus- Description
Fired when a user focuses on an input field. Includes the field identifier but not the value.
- Name
field_blur- Description
Fired when a user leaves an input field. Tracks engagement duration.
- Name
field_change- Description
Fired when a field value changes. Does not include the actual value, only that a change occurred.
Validation events
Track form validation issues:
- Name
validation_error- Description
Fired when client-side validation fails. Can include the field identifier and error type, but not user input.
Submission events
Track form submissions:
- Name
submit_attempt- Description
Fired when a user attempts to submit a form. Tracks the step and timestamp.
- Name
submit_success- Description
Fired when a submission succeeds. Indicates successful completion of that step.
Analytics events
Derived signals for advanced analysis:
- Name
dropoff_signal- Description
Fired when user behavior indicates likely abandonment (e.g., rapid navigation away, window close, extended inactivity).
The embed script
The Odyssey embed script is a lightweight JavaScript file that collects events and sends them to the ingest API.
Installation
Add the script tag to your journey pages:
<script
src="https://odysseylabs.ai/embed/v1.js"
data-org="your_org_slug"
data-journey="your_journey_slug"
data-endpoint="https://odysseylabs.ai/api/ingest"
data-env="prod"
data-debug="false"
async
></script>
Configuration attributes
- Name
data-org- Type
- string
- Description
Your organization slug.
- Name
data-journey- Type
- string
- Description
The journey slug this page belongs to.
- Name
data-endpoint- Type
- string
- Description
The ingest API endpoint URL.
- Name
data-env- Type
- string
- Description
Environment:
prod,staging, ordev. Defaults toprod.
- Name
data-debug- Type
- boolean
- Description
Enable console logging. Set to
truefor development. Defaults tofalse.
How it works
When the script loads:
- Reads configuration from the script tag's data attributes
- Creates identifiers:
- Anonymous
sessionId(UUID v4, per session) - Persistent
clientId(stored in localStorage, across sessions)
- Anonymous
- Records session_start event immediately
- Buffers events in memory as they occur
- Flushes events to the API:
- When the buffer reaches a size threshold
- On
visibilitychangeorpagehideevents - Using
navigator.sendBeaconwhen available for reliability
Manual tracking (optional)
For advanced use cases, the script exposes a minimal API:
// Track a custom event
window.JourneyEmbed.track('custom_event_type', {
key: 'value'
})
// Force flush buffered events
window.JourneyEmbed.flush()
// Check embed version
console.log(window.JourneyEmbed.version)
Most applications won't need this - automatic tracking is sufficient.
The ingest API
Events are sent to the ingest endpoint in batches.
Endpoint
POST /api/ingest
Request format
Events are sent as a batch with context:
Ingest batch request
{
"schemaVersion": 1,
"context": {
"orgKey": "your-org-slug",
"journeyKey": "grant-application",
"language": "en-US",
"deviceClass": "desktop"
},
"events": [
{
"_tag": "session_start",
"schemaVersion": 1,
"id": "evt_abc123",
"ts": "2024-01-15T10:30:00.000Z",
"orgKey": "your-org-slug",
"journeyKey": "grant-application",
"sessionId": "sess_xyz789",
"clientId": "client_def456",
"url": "https://grants.example.com/apply",
"referrer": "https://google.com",
"embedVersion": "1.0.0"
},
{
"_tag": "step_view",
"schemaVersion": 1,
"id": "evt_abc124",
"ts": "2024-01-15T10:30:01.000Z",
"orgKey": "your-org-slug",
"journeyKey": "grant-application",
"sessionId": "sess_xyz789",
"clientId": "client_def456",
"url": "https://grants.example.com/apply/eligibility",
"stepKey": "eligibility-check",
"embedVersion": "1.0.0"
}
]
}
Authentication
The ingest endpoint does not require authentication for sending events, but it does:
- Validate that the organization and journey exist
- Check allowed origins (if configured)
- Apply rate limiting per organization
Rate limiting
Rate limits are applied per organization and journey:
- Default: 1,000 requests per hour
- Configurable per organization
- Unknown origins are rate-limited more aggressively (20 requests per minute)
If you exceed the rate limit, you'll receive a 429 Too Many Requests response.
Response
Success response
204 No Content
The API returns 204 with no body on success. Errors return appropriate status codes:
400 Bad Request- Invalid event data or malformed JSON404 Not Found- Organization or journey not found429 Too Many Requests- Rate limit exceeded500 Internal Server Error- Server error
Privacy and data collection
Odyssey is designed with privacy as a core principle:
What is collected
- Event types and timestamps
- Step and field identifiers
- Session and client IDs (anonymous)
- Page URLs and referrers
- Device class (mobile/desktop/tablet)
- Browser language
What is NOT collected
- Field values or user input
- Personally identifiable information (PII)
- Uploaded files or attachments
- Form content
- Cookies (except for clientId in localStorage)
The anonymous clientId allows tracking repeat users without identifying them.
CORS and allowed origins
For security, you can restrict which domains can send events:
Set allowed origins
curl -X PUT https://odysseylabs.ai/api/journeys/my-journey \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"allowedOrigins": [
"https://myapp.com",
"https://staging.myapp.com"
]
}'
Events from other origins will be rejected with a 403 error.
Debugging
Enable debug mode during development:
<script
src="https://odysseylabs.ai/embed/v1.js"
data-org="your_org_slug"
data-journey="your_journey_slug"
data-endpoint="https://odysseylabs.ai/api/ingest"
data-env="staging"
data-debug="true"
async
></script>
With debug mode enabled, the embed script logs events to the browser console:
[JourneyEmbed] session_start: sess_xyz789
[JourneyEmbed] step_view: eligibility-check
[JourneyEmbed] Flushing 5 events to API
Viewing analytics
Once events are flowing, view analytics in your dashboard:
- Journey-level metrics (completion rate, time to complete)
- Step-level metrics (drop-off rates, field interaction)
- Session recordings (coming soon)
- Cohort analysis (coming soon)