HTTP API reference
The ASP.NET Core integration exposes browser collection and reporting routes. This reference uses the default tracker prefix /_analytics and report prefix /_analytics/api.
Register routes
app.MapZoneTreeAnalytics();
app.MapZoneTreeAnalyticsApi().RequireAuthorization(); The host configures its authentication and authorization policies. Override collection paths through AnalyticsWebOptions.PathPrefix and reporting paths through MapZoneTreeAnalyticsApi.
Browser collection
| Route | Purpose |
|---|---|
| GET /_analytics/script.js | Serve the tracker |
| POST /_analytics/event | Accept an event beacon |
The script exposes zta(name, dimensions, numericValues), records the initial page view, and observes history navigation by default. Pre-installation queued calls are replayed.
| Script attribute | Effect |
|---|---|
| data-endpoint | Override the beacon URL |
| data-track-navigation="false" | Disable page views from history-state changes |
| data-hash-routing="true" | Treat hash-route changes as navigation |
| data-allow-localhost="true" | Enable collection on loopback hosts |
Automation identified through navigator.webdriver is excluded by the script. Repeated automatic page views for the same current URL are suppressed.
Beacon payload
{
"n": "purchase",
"u": "https://example.com/checkout",
"r": "https://example.com/pricing",
"p": { "plan": "pro" },
"m": { "revenue": 49.0 }
} | Field | Meaning |
|---|---|
| n | Required non-reserved event name |
| u / r | Page URL and referrer |
| p | Scalar dimensions |
| m | Numeric values |
| h | Optional true value for hash-route interpretation |
The tracker normally sends JSON as text/plain. Site and explicit visitor identity come from host resolvers, not a browser-supplied site field.
The default beacon limit is 8 KiB.
Reporting routes
All routes below are relative to /_analytics/api.
| Method and route | Result |
|---|---|
| GET /summary | Traffic and engagement totals |
| GET /timeseries | Summary metrics by interval |
| GET /breakdown | A selected dimension's rows |
| GET /pages | Page statistics |
| GET /exit-pages | Page statistics restricted to exits |
| GET /goals | Custom-event counts and conversions |
| GET /bots | Separate automated traffic |
| GET /realtime | Recent distinct visitor count |
| POST /query | General analytics query |
| POST /funnel | Ordered funnel |
List reports contain from, to, totalRows, rows, and plan. Summary reports contain summary instead of rows. General queries include grouping, metric keys, totals, and result rows.
Send a report request
These examples use HTTP-file syntax. Replace http://localhost:5000 with your reporting host and supply its authentication credentials when required. The local address matches the ASP.NET Core quick start.
### Traffic totals for the last 30 calendar days
GET http://localhost:5000/_analytics/api/summary?range=30d&tz=UTC
Accept: application/json
### Countries represented in GitHub traffic
GET http://localhost:5000/_analytics/api/breakdown?range=30d&tz=UTC&dimension=country&filter=source%3D%3DGitHub&includeSessionMetrics=false
Accept: application/json ### Daily purchase count and revenue for the shop site
POST http://localhost:5000/_analytics/api/query
Content-Type: application/json
Accept: application/json
{
"site": "shop",
"event": "purchase",
"range": "30d",
"tz": "UTC",
"interval": "day",
"metrics": ["events", "sum:revenue_usd"],
"fill": "none"
} The second GET URL encodes source==GitHub and groups the matching traffic by country. The POST uses the event fields from the product analytics guide; a different site or value name must match your own collection.
Common scope
| Parameter | Meaning |
|---|---|
| site | Site ID; defaults to the engine's default |
| range | Parsed range; defaults to 30d |
| from / to | Both required together; either two dates or two ISO 8601 date-times |
| tz | Reporting time zone |
| filter / filters | Event filter expressions |
| segment / segments | Behavioral membership expressions |
| compare | Previous period, previous year, or explicit range |
| limit / offset | Pagination |
| interval | Time-series width, such as day or 6h |
GET filters and segments can be repeated. JSON accepts the corresponding arrays; segments also accept supported objects. Use the same text forms as the .NET parsers and URL-encode GET expressions.
Breakdown requires dimension. Realtime accepts minutes, defaulting to five.
Date-only bounds include both calendar days in tz. Date-time bounds include the start and exclude the end. Explicit from and to take precedence over range; returned from and to are the resolved start and exclusive end. See time ranges.
General query
{
"range": "30d",
"groupBy": ["source"],
"metrics": ["visitors", "bounce_rate", "conversion_rate:signup"],
"filters": ["country==DE|AT"],
"having": ["visitors>10"],
"orderBy": ["-visitors"],
"limit": 10,
"compare": "previous-period"
} Post this JSON object to /query to compare source traffic and signup conversion within Germany and Austria. It assumes the corresponding page views and signup events carry matching visitor identity and geography. The having condition keeps groups with more than ten visitors; omit it to include smaller audiences.
Additional fields include event, groupBy, metrics, source, fill, having, orderBy, limitPerBucket, and onlyRowsWithBaseEvent.
Source chooses Auto, Rollups, or RawEvents. Fill chooses none, zero, previous, or linear. See the query model for calculation semantics.
Funnel
{
"range": "30d",
"windowMinutes": 60,
"steps": [
{ "name": "Pricing", "event": "pageview", "filters": ["page==/pricing"] },
{ "name": "Signup", "event": "signup" },
{ "name": "Purchase", "event": "purchase" }
]
} Each step requires an event and can supply a name and filters. Omit windowMinutes for a single-session funnel; a supplied window must be positive.
Global filters and step filters have different scopes.
Optional web metrics
includeSessionMetrics=false skips session metrics on summary, time-series, and breakdown requests. includePageFlowMetrics=false skips entrances and exits on page reports.
Both default to true. Disabled fields are null, including comparison fields. Exit-page requests require page-flow metrics.
Result interpretation
A general query returns metric-keyed objects. Here is an example response for a daily purchase report with no grouping or gap filling:
{
"from": "2026-06-16T00:00:00+00:00",
"to": "2026-07-16T00:00:00+00:00",
"timeZone": "UTC",
"interval": "day",
"groupBy": [],
"metrics": ["events", "sum:revenue_usd"],
"totalRows": 1,
"totals": {
"values": { "events": 2, "sum:revenue_usd": 98 }
},
"rows": [
{
"bucket": "2026-07-15T00:00:00+00:00",
"values": { "events": 2, "sum:revenue_usd": 98 }
}
],
"plan": {
"complete": true,
"warnings": [],
"steps": [
{
"event": "purchase",
"source": "DayRollups",
"from": "2026-06-16T00:00:00+00:00",
"to": "2026-07-16T00:00:00+00:00"
}
],
"rollupSuggestions": []
}
} | Field | How to use it |
|---|---|
| metrics | Stable keys used in every values object |
| rows[].bucket | Timestamp for the chart position; absent for an unbucketed row |
| rows[].dimensions | Grouping values; absent when no dimensions are requested |
| rows[].values | Measurements addressed by metric key |
| totals.values | Full-report aggregates before pagination |
| totalRows | Result-row count before global pagination |
| previous | Comparison object, when one is available |
| plan.complete / warnings | Historical coverage and interpretation concerns |
Numeric rates such as bounce rate and conversion rate are fractions: 0.25 means 25%. Built-in session durations are seconds. Custom numeric values retain their producer's unit, such as duration_ms or revenue_usd.
Plans include source steps, warnings, completeness, and rollup suggestions. Use them when historical coverage matters.
HTTP plans expose steps[].source and optional steps[].indexDimension. The .NET-only convenience flags such as UsedRollupIndexes are not additional fields in the JSON contract.
Non-finite .NET numeric values are serialized as null. The API adds a plan warning and marks the response incomplete. Missing pages are excluded before page-report pagination; exit-page reports additionally exclude rows without exits.
Status codes
| Status | Collection | Reporting |
|---|---|---|
| 202 | Accepted | — |
| 204 | Filtered by policy | — |
| 400 | Invalid or disallowed event | Invalid request or unsupported/bounded query |
| 403 | Host policy may deny access | AuthorizeSite denied the normalized site |
| 413 | Beacon payload too large | POST payload too large |
| 503 | Temporarily unavailable | Timeout, concurrency saturation, or response size exceeded |
Collection unavailability and reporting concurrency saturation return Retry-After: 1. A successful beacon means acceptance, not completed aggregate processing.
Reporting errors contain an error string. Keep that message with the status when diagnosing a failure; a 503 can have different causes. Retry transient admission failures with backoff, while a response-size or query-budget problem needs a narrower request. Host authentication can add its own 401 or 403 responses.
Limits and authorization
Reporting POST bodies must be JSON objects. Defaults are 64 KiB for a body, four concurrent requests, and 16 MiB for a successful serialized response.
Admission covers body reading through delivery and rejects excess requests immediately. Responses are serialized before committing success headers, so oversized output can return a complete error. Engine query budgets govern computation independently.
Protect report access with host authorization. AuthorizeSite receives the normalized executed site, including the default for an omitted or empty site. Attach rate limiting through the host when required.
Dashboard-specific routes
The dashboard adds API connection settings and Development-only sample-data tools. Those routes are not automatically installed by the library's reporting mapping.
Sample and benchmark report prefixes address separate datasets. See the dashboard guide for how readers select them.