API Reference
The three public endpoints the tracker uses. You can call them directly from any language.
Base URL & CORS
The production API lives at https://app.produl.tech. All three endpoints accept cross-origin requests — Access-Control-Allow-Origin: * is returned on every response.
All request bodies are application/json. All responses are 204 No Content on success. No response body is returned, even for successful writes.
Authentication
The public collection endpoints are unauthenticated by site ID alone — the tracker POSTs from the browser without any secret. The site ID (field k) is what attributes the event to your site.
For server-side tracking, include an X-Produl-Server-Key header with a secret key generated from your dashboard. Server-authenticated requests get a higher rate limit. See Server-Side Tracking.
Rate limits
| Request type | Limit |
|---|---|
| Client (browser) requests | 200 / minute / IP |
| Server-authenticated requests | 2,000 / minute / IP |
Requests over the limit return 429 Too Many Requests.
POST /api/collect
/api/collectSend a pageview or custom event.
Body
| Field | Type | Required | Description |
|---|---|---|---|
k | string | yes | Site ID (api key) |
t | "pv" | "ev" | yes | Type: pageview or event |
u | string | yes | Full URL of the page |
p | string | yes | Path (without query) |
vi | string | yes | Visitor ID |
sk | string | yes | Session key |
ti | string | no | Page title |
r | string | no | Referrer URL |
d | number | no | Duration on previous page (ms) |
sd | number | no | Scroll depth (0–100) |
sw | number | no | Screen width (px) |
sh | number | no | Screen height (px) |
l | string | no | Browser language |
n | string | if t=ev | Event name |
pr | object | no | Event properties (JSON) |
Pageview example
{
"k": "site_abc123",
"t": "pv",
"u": "https://example.com/pricing",
"p": "/pricing",
"vi": "v8abcd1lmno2",
"sk": "sess_xyz789",
"ti": "Pricing — Example",
"r": "https://google.com/",
"sw": 1920,
"sh": 1080,
"l": "en-US"
}Event example
{
"k": "site_abc123",
"t": "ev",
"u": "https://example.com/pricing",
"p": "/pricing",
"vi": "v8abcd1lmno2",
"sk": "sess_xyz789",
"n": "cta_click",
"pr": { "location": "hero", "variant": "blue" }
}Response codes
| Status | Meaning |
|---|---|
204 No Content | Accepted. (Also returned silently for invalid payloads, bot UAs, and over-limit sites.) |
429 Too Many Requests | Rate limit exceeded. |
Why 204 on invalid payloads?
POST /api/ping
/api/pingKeep the active-visitor counter fresh and backfill time-on-page + scroll depth.
Body
| Field | Type | Required | Description |
|---|---|---|---|
k | string | yes | Site ID |
sk | string | yes | Session key |
vi | string | yes | Visitor ID |
p | string | yes | Current path |
d | number | no | Page duration (ms), sent on visibility change |
sd | number | no | Scroll depth (0–100) |
Behavior
The tracker sends /api/ping on a 30-second heartbeat and again on visibilitychange. This keeps the live-visitor counter fresh — any visitor whose last ping is older than 3 minutes is treated as inactive.
POST /api/vitals
/api/vitalsSubmit Core Web Vitals measurements captured in the browser.
Body
| Field | Type | Required | Description |
|---|---|---|---|
k | string | yes | Site ID |
sk | string | yes | Session key |
p | string | yes | Path |
lcp | number | no | Largest Contentful Paint (ms) |
fcp | number | no | First Contentful Paint (ms) |
cls | number | no | Cumulative Layout Shift |
inp | number | no | Interaction to Next Paint (ms) |
ttfb | number | no | Time to First Byte (ms) |
fid | number | no | First Input Delay (ms) — deprecated in favor of INP |
Example
{
"k": "site_abc123",
"sk": "sess_xyz789",
"p": "/pricing",
"lcp": 2350,
"fcp": 1200,
"cls": 0.07,
"inp": 180,
"ttfb": 420
}Errors
With the exception of rate-limit violations, these endpoints return 204regardless of the outcome — this keeps third-party analytics from interfering with your site's normal operation. To debug an event that doesn't arrive:
- Check the browser network tab — the request should show as a
204 - Verify your site ID matches a site in the dashboard
- Enable tracker debug mode (
data-debug="1") to see an overlay of every tracked event - Check FAQ & Troubleshooting for common issues (ad blockers, CSP)