Skip to content

Architecture

OwlEye separates high-volume analytics facts from application and control-plane metadata.

  • ClickHouse stores analytics facts such as page views, custom events, rule events, and performance records.
  • SQLite stores users, sites, teams, sessions, rules, dashboards, memberships, API keys, AI prompt allocations, and other application metadata.

This boundary keeps event-heavy queries in the store designed for them while leaving account and configuration workflows in a simple transactional database.

Browser events enter through a public SDK endpoint and are queued through a bounded in-process batch writer. ClickHouse writes use async inserts with explicit JSONEachRow columns.

The SDK excludes query strings by default. captureCampaigns is the narrow attribution opt-in: it sends only bounded utm_source, utm_medium, and utm_campaign values while arbitrary parameters remain excluded. captureQuery is the broader opt-in and exposes the full query string. The ingestion boundary extracts only those three UTM fields into campaign dimensions.

The ingestion path prefers backpressure over unbounded buffering. If the queue is full, the API returns a retryable service-unavailable response instead of silently growing memory use.

The public SDK does not create or store a browser identifier. During ingestion, the API uses the client address long enough to resolve optional GeoIP context and derive cohorts, but does not write the raw address into the analytics fact row. IPv4 addresses lose their host octet (203.0.113.42 becomes the /24 prefix 203.0.113.0); IPv6 addresses lose the interface half and retain only the /64 network prefix.

The server derives keyed, site-scoped hashes from that truncated prefix, request signals, and the operator’s private salt. The visitor cohort is stable while those inputs remain stable, so it is a pseudonymous aggregate—not a claim that one person can always be distinguished from every other person on the same network. A separate daily aggregate ID includes the UTC day, and session IDs use 30-minute time buckets. None of these values are returned to or persisted in the visitor’s browser.

Console APIs use authenticated sessions. Public SDK ingestion and public rule fetching stay separate from dashboard APIs.

Site configuration uses canonical, site-scoped API routes. This is the current management surface:

GET|POST /v1/sites
GET|PUT|DELETE /v1/sites/{siteId}
GET /v1/sites/{siteId}/events
GET|POST /v1/sites/{siteId}/members
PUT|DELETE /v1/sites/{siteId}/members/{userId}
GET|PUT /v1/sites/{siteId}/settings
GET|POST /v1/sites/{siteId}/api-keys
PUT|DELETE /v1/sites/{siteId}/api-keys/{keyId}
GET|POST /v1/sites/{siteId}/rules
GET|PUT|DELETE /v1/sites/{siteId}/rules/{ruleId}
GET|POST /v1/sites/{siteId}/dashboards
GET /v1/sites/{siteId}/dashboard-invites
GET /v1/sites/{siteId}/dashboard-invites/{dashboardId}
POST /v1/sites/{siteId}/dashboard-invites/{dashboardId}/accept
POST /v1/sites/{siteId}/dashboard-invites/{dashboardId}/dismiss
GET|PUT|DELETE /v1/sites/{siteId}/dashboards/{dashboardId}
GET|POST|DELETE /v1/sites/{siteId}/dashboards/{dashboardId}/shares
DELETE /v1/sites/{siteId}/dashboards/{dashboardId}/shares/me
DELETE /v1/sites/{siteId}/dashboards/{dashboardId}/shares/{userId}
POST /v1/sites/{siteId}/dashboards/{dashboardId}/widgets
POST /v1/sites/{siteId}/dashboards/{dashboardId}/widgets/preview
PUT|DELETE /v1/sites/{siteId}/dashboards/{dashboardId}/widgets/{widgetId}

Every request resolves the site from the path and verifies organization membership. API-key management and rule mutations require an owner or administrator role; settings mutations are owner-only. Event exploration is read-only. API-key creation returns the secret once; OwlEye stores the hash and non-sensitive lookup metadata, so the secret cannot be recovered by a later read. These routes describe the API contract used by both the authenticated console and direct automation. Console roles and pages and Pro View document the role and dashboard behavior in more detail.

Pro View sharing stores pending, accepted, dismissed, and revoked recipient state in SQLite. Only the dashboard creator manages recipients. A pending recipient can preview and then accept or dismiss an invitation; accepted dashboards appear as read-only views. A recipient can remove only their own copy, while the creator can revoke one recipient, revoke every shared copy while retaining the canonical dashboard, or delete the canonical dashboard for everyone. Each route verifies both current app membership and the capability required for that transition.

AI access is a separate, owner-managed control-plane permission with fluid, equal, or custom prompt allocation. The current prompt handler validates and accounts for allowance but returns no generated content and makes no model-provider call. See AI mode and prompt allocation for the current-phase boundary.

This repository runs one product: the OwlEye-managed hosted service. Local loopback HTTP and logged OTP delivery exist only for development. Every non-loopback API deployment fails closed unless it has canonical HTTPS origins, secure cookies, SMTP delivery, and a strong deployment root secret. Hosted retention is stamped at ingestion and its workers run in every service deployment. Hosted launch status documents the remaining operational gates.