Quick start
Paste this snippet before the closing head tag of your pages. The site is identified by its domain name, so use the domain you registered in the dashboard.
<script async src="https://cdn.open-telemetry.net/t.js"
data-site="example.com"></script>
The script is about 1.2 KB gzipped, loads asynchronously and sends a single beacon when the visitor leaves the page. Data appears in the dashboard within 30 seconds.
To check what is sent without sending it, add the data-debug attribute: the payload is printed to the browser console instead of being posted.
Authentication
The collection endpoint is public by design: it only accepts the domain you registered. The query API requires a bearer token created under Settings, API tokens. Tokens are read-only by default.
curl -H "Authorization: Bearer $TOKEN" \
"https://api.open-telemetry.net/v3/sites/example.com/metrics?m=lcp&p=75&range=7d"
Keep tokens out of client-side code. Revoke a token at any time from the same settings page; revocation is immediate.
What the script collects
One JSON document per page view, posted with sendBeacon to https://api.open-telemetry.net/v3/collect. No cookies are set and nothing is stored in the browser. The script does nothing when the browser sends Do Not Track or Global Privacy Control.
| Field | Content |
|---|
| site | Domain from data-site |
| url | Origin and path, without query string or fragment |
| ref | Referrer host only |
| utm | utm_source, utm_medium, utm_campaign (80 characters max) |
| w, lang, conn | Viewport width, browser language, connection class |
| vitals | LCP, CLS and INP in milliseconds (CLS unitless) |
| nav | TTFB, DOMContentLoaded and load timings |
| ads | Per slot: name, network, visible time, viewable flag |
Payloads larger than 16 KB are rejected with 413.
Ad slots
Mark any element as a placement with data-ot-ad. The optional data-ot-network attribute names the ad network. A slot counts as viewable when at least 50 % of it is visible for one continuous second while the tab is in the foreground.
<div data-ot-ad="homepage-top" data-ot-network="my-network"></div>
Query API
GET /v3/sites/{domain}/metrics returns one metric for one site as JSON.
| Parameter | Values | Default |
|---|
| m | lcp, inp, cls, ttfb, visitors | lcp |
| p | 50, 75, 95, 99 (or p50 ... p99) | 75 |
| range | 24h, 7d, 30d | 7d |
{
"site": "example.com",
"metric": "lcp",
"percentile": 75,
"range": "7d",
"unit": "ms",
"value": 1920,
"granularity": "day",
"points": [2064, 1892, 1761, 2068, 1952, 1879, 2030],
"sample_size": 48213,
"rating": "good"
}
The rating follows the public Core Web Vitals thresholds (good, needs-improvement, poor).
Errors and limits
An unsupported parameter value returns 400 with a JSON body that names the parameter and lists the accepted values.
{"error":"invalid_parameter","parameter":"range","allowed":["24h","7d","30d"]}
| Status | Meaning |
|---|
| 200 | Success |
| 204 | CORS preflight |
| 400 | Invalid parameter |
| 413 | Collection payload above 16 KB |
Query responses are not cached (Cache-Control: no-store). The API allows cross-origin GET requests.