Skip to main content

Stats API

The Stats API provides read-only access to aggregated analytics data for your sites. All endpoints return privacy-respecting, aggregated metrics without exposing individual user data.

Endpoints Overview

The Stats API includes 13 endpoints covering all core analytics dimensions:

  • Overview: Aggregate metrics and timeseries
  • Content: Pages, entry pages, exit pages
  • Sources: Traffic sources and referrers
  • Technology: Devices, browsers, operating systems
  • Geography: Countries, regions, cities
  • Events: Custom events and conversions
  • Real-time: Current active visitors

GET /stats/overview

Retrieve aggregate metrics and timeseries data for a specified date range.

Parameters:

  • site_id (required): Site identifier
  • date_from (required): Start date (YYYY-MM-DD)
  • date_to (required): End date (YYYY-MM-DD)
  • compare (optional): Enable comparison with previous period (true/false)
  • timezone (optional): IANA timezone for date aggregation

Response:

{
"data": {
"metrics": {
"visitors": 12543,
"pageviews": 28941,
"bounce_rate": 42.3,
"visit_duration": 185
},
"timeseries": [
{ "date": "2025-01-01", "visitors": 421, "pageviews": 987 },
{ "date": "2025-01-02", "visitors": 438, "pageviews": 1024 }
]
},
"meta": {
"sampled": false,
"filtered_bot_traffic": 234
}
}

Example (cURL):

curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://api.ovyxa.com/api/v1/stats/overview?site_id=xxx&date_from=2025-01-01&date_to=2025-01-31"

Example (JavaScript):

const response = await fetch(
'https://api.ovyxa.com/api/v1/stats/overview?site_id=xxx&date_from=2025-01-01&date_to=2025-01-31',
{ headers: { 'Authorization': 'Bearer YOUR_TOKEN' } }
);
const data = await response.json();
console.log(data.data.metrics);

GET /stats/pages

Retrieve top pages with engagement metrics.

Parameters:

  • site_id (required): Site identifier
  • date_from (required): Start date (YYYY-MM-DD)
  • date_to (required): End date (YYYY-MM-DD)
  • limit (optional): Number of results (default: 100, max: 1000)
  • page (optional): Page number for pagination (default: 1)

Response:

{
"data": {
"pages": [
{
"pathname": "/pricing",
"pageviews": 4521,
"visitors": 3214,
"bounce_rate": 38.2,
"avg_time_on_page": 145
},
{
"pathname": "/features",
"pageviews": 3987,
"visitors": 2876,
"bounce_rate": 41.5,
"avg_time_on_page": 178
}
],
"pagination": {
"total": 247,
"page": 1,
"limit": 100
}
}
}

Example (cURL):

curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://api.ovyxa.com/api/v1/stats/pages?site_id=xxx&date_from=2025-01-01&date_to=2025-01-31&limit=20"

GET /stats/sources

Retrieve traffic sources classified by type (search, social, direct, referral).

Parameters:

  • site_id (required): Site identifier
  • date_from (required): Start date (YYYY-MM-DD)
  • date_to (required): End date (YYYY-MM-DD)

Response:

{
"data": {
"sources": [
{
"source": "Google",
"source_type": "search",
"visitors": 5421,
"pageviews": 12834,
"bounce_rate": 39.8
},
{
"source": "Direct / None",
"source_type": "direct",
"visitors": 3214,
"pageviews": 7891,
"bounce_rate": 45.2
},
{
"source": "twitter.com",
"source_type": "social",
"visitors": 1876,
"pageviews": 4321,
"bounce_rate": 52.3
}
]
}
}

Example (JavaScript):

const response = await fetch(
'https://api.ovyxa.com/api/v1/stats/sources?site_id=xxx&date_from=2025-01-01&date_to=2025-01-31',
{ headers: { 'Authorization': 'Bearer YOUR_TOKEN' } }
);
const { data } = await response.json();
console.log(data.sources);

GET /stats/entry-pages

Retrieve pages where visitors first land on your site.

Parameters:

  • site_id (required): Site identifier
  • date_from (required): Start date (YYYY-MM-DD)
  • date_to (required): End date (YYYY-MM-DD)

Response:

{
"data": {
"entry_pages": [
{
"pathname": "/",
"entries": 8234,
"entry_rate": 45.2,
"bounce_rate": 38.1
},
{
"pathname": "/blog/privacy-analytics",
"entries": 2156,
"entry_rate": 12.1,
"bounce_rate": 41.7
}
]
}
}

GET /stats/exit-pages

Retrieve pages where visitors exit your site.

Parameters:

  • site_id (required): Site identifier
  • date_from (required): Start date (YYYY-MM-DD)
  • date_to (required): End date (YYYY-MM-DD)

Response:

{
"data": {
"exit_pages": [
{
"pathname": "/pricing",
"exits": 3421,
"exit_rate": 75.6
},
{
"pathname": "/contact",
"exits": 2987,
"exit_rate": 82.3
}
]
}
}

GET /stats/devices

Retrieve visitor breakdown by device type.

Parameters:

  • site_id (required): Site identifier
  • date_from (required): Start date (YYYY-MM-DD)
  • date_to (required): End date (YYYY-MM-DD)

Response:

{
"data": {
"devices": [
{
"device": "Desktop",
"visitors": 7834,
"percentage": 62.4
},
{
"device": "Mobile",
"visitors": 3987,
"percentage": 31.8
},
{
"device": "Tablet",
"visitors": 722,
"percentage": 5.8
}
]
}
}

Example (cURL):

curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://api.ovyxa.com/api/v1/stats/devices?site_id=xxx&date_from=2025-01-01&date_to=2025-01-31"

GET /stats/browsers

Retrieve visitor breakdown by browser, optionally filtered by device type.

Parameters:

  • site_id (required): Site identifier
  • date_from (required): Start date (YYYY-MM-DD)
  • date_to (required): End date (YYYY-MM-DD)
  • device (optional): Filter by device type (Desktop/Mobile/Tablet)

Response:

{
"data": {
"browsers": [
{
"browser": "Chrome",
"visitors": 6543,
"percentage": 52.1
},
{
"browser": "Safari",
"visitors": 3421,
"percentage": 27.3
},
{
"browser": "Firefox",
"visitors": 1654,
"percentage": 13.2
}
]
}
}

Example (JavaScript with filter):

const response = await fetch(
'https://api.ovyxa.com/api/v1/stats/browsers?site_id=xxx&date_from=2025-01-01&date_to=2025-01-31&device=Mobile',
{ headers: { 'Authorization': 'Bearer YOUR_TOKEN' } }
);

GET /stats/operating-systems

Retrieve visitor breakdown by operating system, optionally filtered by device type.

Parameters:

  • site_id (required): Site identifier
  • date_from (required): Start date (YYYY-MM-DD)
  • date_to (required): End date (YYYY-MM-DD)
  • device (optional): Filter by device type (Desktop/Mobile/Tablet)

Response:

{
"data": {
"operating_systems": [
{
"os": "Windows",
"visitors": 5432,
"percentage": 43.2
},
{
"os": "macOS",
"visitors": 3214,
"percentage": 25.6
},
{
"os": "iOS",
"visitors": 2187,
"percentage": 17.4
},
{
"os": "Android",
"visitors": 1721,
"percentage": 13.8
}
]
}
}

GET /stats/countries

Retrieve visitor breakdown by country.

Parameters:

  • site_id (required): Site identifier
  • date_from (required): Start date (YYYY-MM-DD)
  • date_to (required): End date (YYYY-MM-DD)

Response:

{
"data": {
"countries": [
{
"country_code": "US",
"country_name": "United States",
"visitors": 4532,
"percentage": 36.1
},
{
"country_code": "GB",
"country_name": "United Kingdom",
"visitors": 2341,
"percentage": 18.7
},
{
"country_code": "FR",
"country_name": "France",
"visitors": 1876,
"percentage": 15.0
}
]
}
}

Example (cURL):

curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://api.ovyxa.com/api/v1/stats/countries?site_id=xxx&date_from=2025-01-01&date_to=2025-01-31"

GET /stats/regions

Retrieve visitor breakdown by region within a country (Phase 2 feature).

Parameters:

  • site_id (required): Site identifier
  • date_from (required): Start date (YYYY-MM-DD)
  • date_to (required): End date (YYYY-MM-DD)
  • country (required): ISO country code (e.g., "US")

Response:

{
"data": {
"regions": [
{
"region_code": "CA",
"region_name": "California",
"visitors": 1243,
"percentage": 27.4
},
{
"region_code": "NY",
"region_name": "New York",
"visitors": 876,
"percentage": 19.3
}
]
}
}

GET /stats/cities

Retrieve visitor breakdown by city within a region (Phase 2 feature).

Parameters:

  • site_id (required): Site identifier
  • date_from (required): Start date (YYYY-MM-DD)
  • date_to (required): End date (YYYY-MM-DD)
  • region (required): Region code (e.g., "CA")

Response:

{
"data": {
"cities": [
{
"city": "San Francisco",
"visitors": 432,
"percentage": 34.8
},
{
"city": "Los Angeles",
"visitors": 387,
"percentage": 31.1
}
]
}
}

GET /stats/events

Retrieve custom event statistics, optionally filtered by event name.

Parameters:

  • site_id (required): Site identifier
  • date_from (required): Start date (YYYY-MM-DD)
  • date_to (required): End date (YYYY-MM-DD)
  • event_name (optional): Filter by specific event name

Response:

{
"data": {
"events": [
{
"event_name": "signup",
"total_count": 342,
"unique_visitors": 298,
"conversion_rate": 2.4
},
{
"event_name": "purchase",
"total_count": 87,
"unique_visitors": 82,
"conversion_rate": 0.7
}
]
}
}

Example (filtered):

const response = await fetch(
'https://api.ovyxa.com/api/v1/stats/events?site_id=xxx&date_from=2025-01-01&date_to=2025-01-31&event_name=signup',
{ headers: { 'Authorization': 'Bearer YOUR_TOKEN' } }
);

GET /stats/realtime

Retrieve current active visitors and their activity (5-minute window).

Parameters:

  • site_id (required): Site identifier

Response:

{
"data": {
"active_visitors": 23,
"current_pages": [
{
"pathname": "/pricing",
"visitors": 8
},
{
"pathname": "/features",
"visitors": 6
},
{
"pathname": "/",
"visitors": 5
}
],
"current_sources": [
{
"source": "Google",
"visitors": 12
},
{
"source": "Direct / None",
"visitors": 7
}
]
},
"meta": {
"timestamp": "2025-01-15T14:32:18Z"
}
}

Example (cURL):

curl -H "Authorization: Bearer YOUR_TOKEN" \
"https://api.ovyxa.com/api/v1/stats/realtime?site_id=xxx"

Example (JavaScript with polling):

// Poll every 30 seconds for real-time updates
setInterval(async () => {
const response = await fetch(
'https://api.ovyxa.com/api/v1/stats/realtime?site_id=xxx',
{ headers: { 'Authorization': 'Bearer YOUR_TOKEN' } }
);
const { data } = await response.json();
updateDashboard(data.active_visitors, data.current_pages);
}, 30000);

Error Handling

All Stats API endpoints return standard HTTP status codes:

  • 200 OK: Request successful
  • 400 Bad Request: Invalid parameters
  • 401 Unauthorized: Invalid or missing authentication
  • 403 Forbidden: Insufficient permissions
  • 404 Not Found: Site not found
  • 429 Too Many Requests: Rate limit exceeded
  • 500 Internal Server Error: Server error

Error Response Example:

{
"error": {
"code": "invalid_date_range",
"message": "date_from must be before date_to"
}
}

Best Practices

  1. Cache responses: Stats data doesn't change frequently - cache for 5-10 minutes
  2. Use appropriate date ranges: Smaller ranges return faster
  3. Paginate large results: Use limit and page parameters
  4. Filter when possible: Use optional filters to reduce response size
  5. Handle rate limits gracefully: Implement exponential backoff