Home· Features· Search Analytics
📊 Search Analytics

Every query, every click, every AI rescue.

An append-only event table feeds seven dashboard tabs, a live activity feed, a latency histogram with real percentiles, and the AI Coach that turns the data into one-click fixes.

Starter Growth Scale Enterprise
Live activity · last 30 s
"wireless headphones" hybrid 18 ms
"laptop for editing" semantic 62 ms
"trainers" 0 hits
"sneekers" → "sneakers" typo_fix 14 ms
What gets captured

One row per search. No PII, ever.

Every query writes one row to search_events — an append-only table. Skryx never stores IPs, user agents, or user IDs; the data is aggregated at query time, not pre-hashed. Click signal arrives as a nullable update on the same row.

// search_events row
{
  "tenant_id":           42,
  "index_id":            7,
  "query":               "wireless headphones",
  "results_count":       142,
  "clicked_doc_id":      "sku-001",
  "clicked_position":    2,
  "search_mode":         "hybrid",
  "ai_enhanced":         true,
  "ai_interventions":    {
    "typo_fix":     false,
    "query_rewrite":false,
    "synonym_used": true
  },
  "response_time_ms":    18,
  "embed_time_ms":       3,
  "dwell_time_ms":       8200,
  "quality_score":       0.87,
  "occurred_at":         "2026-05-25T17:14:02Z"
}

Twelve columns.
Designed for triage, not surveillance.

The shape is deliberately small: query text + result count + click position + mode + AI intervention flags + latency. Anything beyond that isn't worth storing. Click events are not a separate table — they arrive as a post-fact update on the original search row, so query and outcome stay correlated without a join.

  • Append-only: UPDATED_AT is null on the model — clicks update via explicit UPDATE, not Eloquent magic
  • Indexed: on (tenant, occurred_at), (index, results_count), (tenant, ai_enhanced, occurred_at), (tenant, search_mode)
  • No IP, no UA, no user ID — aggregation happens at SQL GROUP BY time
The dashboard

Seven tabs. Each one tells a different story.

📊 Overview

The four numbers your boss asks for.

Total searches, zero-result count, average latency, AI-enhanced count. Plus a volume timeseries chart, granularity auto-picked: hourly for ranges ≤ 24h, daily for longer. No pre-computed rollups — Skryx aggregates on demand, so the data is always current.

  • Range presets: 24h / 7d / 30d / 90d
  • JSON API endpoint: /api/dashboard/timeseries
// Last 24h
Searches: 412,118
Zero-result: 3,202 (0.78%)
Avg latency: 18 ms
AI-enhanced: 31,640 (7.7%)
⚡ Performance

Real p50 / p75 / p95 / p99.
Histogram with 10ms buckets.

Latency percentiles computed from the actual response_time_ms column at query time — no sampling, no approximation. Histogram covers 0–500 ms in 10 ms buckets plus a tail bucket for everything above 500 ms. Slowest queries listed separately with their query text for inspection.

  • p50, p75, p95, p99 + mean latency
  • 50-bucket histogram (0–500 ms) + tail_500ms_plus count
  • Top 20 slowest queries with average latency and last-seen timestamp
// /api/analytics/latency-histogram
p50: 11 ms
p75: 22 ms
p95: 38 ms
p99: 48 ms
tail (>500ms): 14
🔍 Queries

Sortable, paginated, drillable.

Paginated table (25/page) of unique queries: volume, average results, average latency, CTR clicks, last seen. Sort by any column. Click into any query to see the result set Skryx returned during the period. Plus a day-of-week × hour heatmap (7 × 24) so you can spot traffic patterns at a glance.

  • Sort: count / latency / zero-results / recent
  • Heatmap: weekly traffic shape, 168 cells
  • JSON: /api/analytics/queries, /api/analytics/heatmap
Query · Vol · Hits · CTR · Avg ms
sneakers 1,420 142 42% 17
headphones 982 214 38% 21
smartwatch 671 88 21% 19
laptop bag 418 62 19% 16
desk lamp 302 74 44% 14
🤖 AI Impact

Skryx AI's contribution, quantified.

A dedicated tab counts every AI intervention by family: typo_fix, synonym_used, query_rewrite, semantic_dispatched, hybrid_dispatched. The headline metric — queries rescued from zero results — counts every search where keyword would have returned nothing but the AI pipeline produced hits.

  • Per-intervention breakdown (5 families)
  • AI-rescued zero-results count
  • JSON: /api/analytics/ai
// AI interventions · last 7d
typo_fix: 1,204
synonym_used: 8,941
query_rewrite: 312
semantic_dispatched: 4,108
hybrid_dispatched: 22,317
─────────────────
Rescued from 0 hits: 847
🕳️ Zero Results

The queries you're losing customers on.

Volume-sorted list of zero-result queries with AI-rescued count split out. This is the table AI Coach reads to suggest synonyms and catalog gaps — so every recommendation has a direct link back to the underlying queries.

  • Zero-result rate (%) + count
  • AI-rescued count (how many became non-zero via Skryx AI)
  • One-click jump to "Add synonym" with the query pre-filled
Zero-result · last 7 days
"trainers" 24
"smartwatch bands" 11
"4k webcam" 8
"vegan leather" 6
─────────────────
AI rescued 312 of 3,202 (9.7%)
🎨 Visual Curator metrics

Curated rules + their impressions / CTR.

Every Visual Curator rule (pin / replace / hide) records impressions, clicks, and which trigger fired. A separate tab in the analytics surface shows per-rule CTR plus last-fired timestamps so editorial decisions stay accountable to traffic data.

  • Per-rule: impressions, clicks, CTR, last fired, active flag
  • Built-in A/B comparison for rule variants
  • Same data via the per-rule analytics API endpoint
// Pin rule · "sneakers"
impressions: 1,420
clicks: 682
CTR: 48%
last fired: 2 min ago
status: active
Detection details

Two clever bits worth calling out.

📏 Levenshtein-based typo detection

Distinguishes typos from rewrites.

If the engine's final query differs from the original, Skryx checks Levenshtein distance. ≤ 2 edits and not already marked as an LLM rewrite → flagged as typo_fix with from/to recorded. Anything farther afield is a query_rewrite. That separation makes the AI Impact tab honest about what's helping.

{
  "original_query": "sneekers",
  "final_query":    "sneakers",
  "levenshtein":    1,
  "ai_interventions": {
    "typo_fix": {
      "from": "sneekers",
      "to":   "sneakers"
    }
  }
}
📤 JSON-first APIs

Every chart is a queryable endpoint.

Five endpoints cover the dashboard: timeseries, latency histogram, queries, heatmap, AI breakdown. All return JSON, all accept a period parameter. Pipe them into Metabase, Looker, or a homegrown report — Skryx doesn't try to be your BI tool.

  • /api/dashboard/timeseries
  • /api/analytics/latency-histogram
  • /api/analytics/queries (paginated)
  • /api/analytics/heatmap (7 × 24)
  • /api/analytics/ai
GET /api/analytics/queries
    ?period=7d&page=1&sort=count

{ "rows": [
    { "q": "sneakers",
      "vol": 1420,
      "hits": 142,
      "ctr": 0.42,
      "avg_ms": 17,
      "last_seen": "2026-05-25T17:12Z" },
    …
  ],
  "page": 1,
  "per_page": 25 }
Privacy & data residency

EU-hosted. No PII. No third-party trackers.

Storage in Frankfurt. No IP, user-agent, or user-id captured. Click data arrives as a nullable update on the existing row, not a separate event broadcast. Aggregation happens at SQL GROUP BY time, so individual searches never appear in dashboard counters.

7 tabs
Overview, Performance, Queries, AI Impact, Zero Results, User Journeys, Curator
5 APIs
JSON endpoints under /api/analytics/* for every dashboard view
All plans
Analytics itself is unlimited; AI Coach (which reads it) is Growth+
Keep exploring

Other things Skryx does

Try it on your own catalog.

Free tier, no credit card. EU-hosted from day one.