Use the SDK for browser tracking. Use these HTTP APIs for server jobs, integrations, and trusted AI tools. The API base is https://api.owleye.dev; unlike the browser SDK, an HTTP client needs a complete URL.
Choose the right credential
Section titled “Choose the right credential”| Credential | Purpose | Where to get it | Where it belongs |
|---|---|---|---|
Public Tracking ID (owl_…) |
Browser SDK events and rules | App Overview or Settings | Browser code |
Ingestion API key, events:write |
Send server events | App API Keys | Your server or secret store |
Developer key, stats:read |
Query aggregate reports | Settings → Developer mode | Your server |
Developer key, events:read |
Read bounded event exports | Settings → Developer mode | Your server |
Developer key, ai:prompt |
Ask the OwlEye AI analyst | Settings → Developer mode | Your server or trusted tool executor |
These secret key families are separate and cannot be substituted for each other. A key is scoped to one app. Use the matching public Tracking ID in requests; a different app cannot be accessed just by changing the URL or JSON.
Send either header:
Authorization: Bearer YOUR_SECRET_KEYx-owleye-api-key: YOUR_SECRET_KEYDo not send secrets in URL query strings, browser bundles, SDK options, public notebooks, or LLM prompts. CORS is not granted on these server-to-server secret-key interfaces. Console session endpoints are internal to the console and are not an automation API.
Available endpoints
Section titled “Available endpoints”| Method | Path | Required scope | Guide |
|---|---|---|---|
| POST | /v1/events/api |
events:write |
Server ingestion |
| GET | /v1/developer/sites/{siteId}/stats |
stats:read |
Analytics queries |
| GET | /v1/developer/sites/{siteId}/events |
events:read |
Event pagination |
| POST | /v1/developer/sites/{siteId}/prompt |
ai:prompt |
AI integrations |
Browse endpoints, parameters, and response models in the OpenAPI explorer, or download the OpenAPI JSON schema. Browser SDK transport uses /v1/events and /v1/rules with its public Tracking ID; prefer the SDK over implementing that browser protocol yourself.
Access and limits
Section titled “Access and limits”Developer APIs require the app owner to enable both Developer mode and API access. Pro permits stats:read; Business and Custom permit all three developer scopes. Current plan, ownership, expiry, revocation, and toggles are checked on each request.
Developer API requests share an organization allowance of 60 requests/minute on Pro or 600 on Business/Custom, with a separate source-IP ceiling of 600/minute. These are refilling token buckets, not a promise of full burst capacity every minute. Ingestion has separate limits and consumes the app’s event allowance.
| Status | Action |
|---|---|
| 400 | Correct the request fields or bounds |
| 401 | Check key, expiry, revocation, and developer toggles |
| 403 | Check app scope, role, plan, and feature access |
| 409 | Resolve a duplicate/conflicting request; do not blindly retry |
| 413 | Reduce the request body size |
| 429 | Wait for Retry-After and reduce concurrency |
| 5xx | Retry eligible reads with bounded backoff; verify ingestion before replaying events |
Successful developer responses use Cache-Control: no-store. Keep analytics out of shared public caches. Store newly created keys immediately: their secrets are only shown once. See developer access setup.
Console request protection
Section titled “Console request protection”Console routes have a shared 120-request/minute per-IP budget checked before session-token validation, SQLite session lookup, or app-membership lookup. This covers current and legacy Console routes, including the session endpoint. Anonymous and forbidden requests consume the same budget; changing cookies, paths, query strings, or source ports does not create a new one. Only configured trusted proxies can supply a forwarded client IP.
The existing 60-request/minute per-session-and-IP limit still applies after authentication. Both are refilling token buckets: the IP bucket holds at most 120 requests and refills at two per second. Users behind one public IP share the early budget. Exhaustion returns 429 with Retry-After before database work; responses remain private, no-store. The early limiter has a separate bounded pool of 4,000 tracked IP buckets so anonymous traffic cannot consume the authenticated session limiter’s storage. CORS preflights do not access the database or consume this request budget. Limits are process-local, as with other API limits.
Public metadata caching
Section titled “Public metadata caching”Successful GET and HEAD responses from /version and /v1/openapi.json use Cache-Control: public, max-age=3600, must-revalidate. Browsers and shared caches may reuse this deployment metadata for one hour. These unversioned URLs are not marked immutable, so a deployment can remain unseen in an existing cached copy for up to one hour. Error responses, health endpoints, login configuration and authenticated data keep their existing private, no-store policy. Client caching reduces normal repeated requests; clients can ignore it, so it is not an abuse rate limit.
Health endpoints
Section titled “Health endpoints”The hosted API limits each of /health, /health/live, and /health/ready to one request per IP per endpoint every 120 seconds, with no burst allowance. GET and HEAD share the same budget; query strings do not create a new budget. Excess requests return 429 with Retry-After. Loopback probes follow the same limit. Forwarded client IPs are accepted only from configured trusted proxies.
All three endpoints share their own in-memory snapshot across clients for 60 seconds per API process. Concurrent cache misses run one probe per endpoint; disconnecting a client does not cancel the shared refresh. Failed checks are cached too and return 503. A database-backed probe has a three-second timeout. /health/live does not query a database; /health checks SQLite; /health/ready checks SQLite, ClickHouse, and hosted retention readiness.
Responses expose X-OwlEye-Health-Age in seconds. HTTP responses remain Cache-Control: private, no-store: caching happens inside the API, not in browsers or a CDN. An expired snapshot refreshes on the next eligible request; this is not a background monitor or a guarantee of detecting failures within one minute. A single monitoring IP must poll each endpoint no more often than every two minutes and obey Retry-After (use 121 seconds to allow timing margin). A process restart clears snapshots and rate buckets. Limits are process-local; multiple replicas need shared or edge enforcement.
Console login capabilities use the database-free /v1/auth/config endpoint, with its separate 60-per-minute IP budget, so health polling limits do not hide sign-in methods.