Event reference
The Skryx ingestion pipeline strictly validates every event against
the taxonomy below. Unknown event names get rejected; events with
missing required properties get rejected; type mismatches get rejected.
Validation errors don't crash the pipeline — they get counted as
invalid_24h and shown in the dashboard. The pixel + server callers
keep flowing.
# Common envelope
Every event, regardless of type, must include:
| Field |
Type |
Notes |
event_id |
string |
8–100 chars, alphanumeric + ._-. Idempotency key for dedup. |
event_name |
string |
Must match one of the names below. |
occurred_at |
ISO 8601 string |
Must be within [-7 days, +5 minutes] of server time. |
session_id |
string |
8–100 chars. Generated by the pixel; you provide your own on server-side. |
source |
enum |
pixel / server / sdk / webhook. Pixel events get forced to pixel. |
anonymous_id |
string? |
Persistent identifier — only when the visitor consented to analytics. |
user_id |
string? |
Your logical user id (after skryx.identify(…) or server-side user_id). |
properties |
object |
Event-specific payload — schema enforced per type. |
context |
object? |
Browser / device bag from the pixel; auto-filled. |
# Event taxonomy
# Search events
| Event |
Required |
Optional |
search.performed |
query: string, results_count: int |
search_mode, latency_ms, filters, sort, page, per_page, index |
search.refined |
query: string, filters: object |
previous_filters, results_count |
search.abandoned |
query: string |
dwell_ms |
# Click / interaction events
| Event |
Required |
Optional |
result.clicked |
result_id: string, position: int, query: string |
result_type, page, price |
result.viewed |
result_id: string, position: int, query: string |
page |
pagination.clicked |
from_page: int, to_page: int, query: string |
|
# Page / product
| Event |
Required |
Optional |
page.viewed |
— |
url, title, referrer, path |
product.viewed |
product_id: string |
came_from, category, price, in_stock, search_id, position |
# E-commerce
| Event |
Required |
Optional |
cart.add |
product_id: string, quantity: int |
price, cart_id, currency |
cart.remove |
product_id: string |
quantity, cart_id |
cart.viewed |
— |
cart_id, item_count, cart_value, currency |
checkout.started |
— |
cart_id, cart_value, item_count, currency |
order.completed |
order_id: string, total: int|float |
currency, products: array, tax, shipping, discount |
# Session
| Event |
Required |
Optional |
session.started |
— |
landing_page, referrer |
session.ended |
— |
duration_ms, event_count |
# Identity
| Event |
Required |
Optional |
user.identified |
user_id: string |
email_hash, traits: object |
# Validation rules
event_id must be unique within (tenant, day) — duplicates are dedup'd, not rejected.
- Numerics accept ints or floats unless the schema explicitly says
int.
- Arrays must be lists (
[…]), objects must be dicts ({…}) — the validator distinguishes.
occurred_at outside the [-7d, +5m] window is rejected — protects against clock-misset devices and stale replay attacks.
- Unknown
event_name is rejected with a clear error so client integrations can't silently spray garbage.
Invalid events show up in /tracking as invalid_24h. A response from
the server /v1/events endpoint includes per-row errors so your
integration knows exactly which row failed and why.