API reference

Access your analytics data programmatically with the Glyphex REST API.

Authentication

All API requests require a Bearer token. Create an API key in your site settings under API keys.

curl https://glyphex.io/api/v1/stats/overview?range=30d \
  -H "Authorization: Bearer glx_your_api_key_here"

Your full API key is shown only once when you create it. Store it securely.

Base URL

https://glyphex.io/api/v1

Rate limits

Rate limits are applied per API key in a fixed 1-hour window that starts at your first request and resets one hour later.

PlanRequests per hour
Starter1,000
Growth2,000
Scale3,000
Agency5,000

Responses that pass authentication include rate limit headers: X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset (Unix timestamp). Authentication failures (401, and 403 plan_required) do not include them.

Response format

All successful responses return JSON with this structure:

{
  "data": { ... },
  "meta": {
    "site_id": "your-site-id",
    "range": "30d",
    "generated_at": "2026-02-18T12:00:00.000Z"
  }
}

Errors return a similar structure with an error object:

{
  "error": {
    "code": "unauthorized",
    "message": "Missing or invalid Authorization header. Use: Bearer glx_..."
  }
}

Query parameters

All endpoints accept these query parameters:

ParameterDefaultDescription
range30dTime range: 24h, 7d, 30d, 90d, 12m, or custom
start-Start date for custom range (ISO 8601)
end-End date for custom range (ISO 8601)
limit10Number of results (1-100). Applies to pages, referrers, devices, geo, events, utm
country-Filter by country code (e.g. US, DE)
device-Filter by device type (desktop, mobile, tablet)
hostname-Filter by hostname
utm_source-Filter by UTM source

Country exclusions

If you have configured excluded countries in your site settings, those exclusions are automatically applied to all API responses. You do not need to pass any additional parameters. The API uses the same exclusion list as the dashboard and email reports.

Endpoints

GET/api/v1/stats/overview

Aggregated stats for the selected period with comparison to the previous period.

Change values are percentages. A null change value means the previous period had zero.

{
  "data": {
    "current": {
      "visitors": 1240,
      "pageviews": 3891,
      "sessions": 1580,
      "bounce_rate": 42,
      "avg_duration": 127
    },
    "previous": {
      "visitors": 1100,
      "pageviews": 3200,
      "sessions": 1400,
      "bounce_rate": 45,
      "avg_duration": 115
    },
    "change": {
      "visitors": 13,
      "pageviews": 22,
      "sessions": 13,
      "bounce_rate": -7,
      "avg_duration": 10
    }
  },
  "meta": { "site_id": "...", "range": "30d", "generated_at": "..." }
}
GET/api/v1/stats/timeseries

Daily visitor and pageview counts for the selected period.

{
  "data": [
    { "date": "2026-02-01", "visitors": 42, "pageviews": 128 },
    { "date": "2026-02-02", "visitors": 38, "pageviews": 104 }
  ],
  "meta": { "site_id": "...", "range": "30d", "generated_at": "..." }
}
GET/api/v1/stats/pages

Most visited pages ranked by views.

{
  "data": [
    { "pathname": "/", "title": "Home", "views": 520, "visitors": 380 },
    { "pathname": "/pricing", "title": "Pricing", "views": 210, "visitors": 180 }
  ],
  "meta": { "site_id": "...", "range": "30d", "limit": 10, "generated_at": "..." }
}
GET/api/v1/stats/referrers

Top traffic sources by referrer domain.

{
  "data": [
    { "referrer": "google.com", "views": 320, "visitors": 280 },
    { "referrer": "twitter.com", "views": 85, "visitors": 72 }
  ],
  "meta": { "site_id": "...", "range": "30d", "limit": 10, "generated_at": "..." }
}
GET/api/v1/stats/channels

Visitor breakdown by traffic channel (direct, organic, social, referral, etc.).

{
  "data": [
    { "channel": "Organic", "visitors": 580, "percentage": 47 },
    { "channel": "Direct", "visitors": 340, "percentage": 27 },
    { "channel": "Social", "visitors": 200, "percentage": 16 }
  ],
  "meta": { "site_id": "...", "range": "30d", "generated_at": "..." }
}
GET/api/v1/stats/devices

Visitor breakdown by device type.

{
  "data": [
    { "name": "Desktop", "visitors": 820 },
    { "name": "Mobile", "visitors": 350 },
    { "name": "Tablet", "visitors": 70 }
  ],
  "meta": { "site_id": "...", "range": "30d", "limit": 10, "generated_at": "..." }
}
GET/api/v1/stats/geo

Visitor breakdown by country.

{
  "data": [
    { "name": "United States", "visitors": 480 },
    { "name": "Germany", "visitors": 220 },
    { "name": "United Kingdom", "visitors": 180 }
  ],
  "meta": { "site_id": "...", "range": "30d", "limit": 10, "generated_at": "..." }
}
GET/api/v1/stats/events

Custom event counts and unique visitors.

{
  "data": [
    { "name": "signup_click", "count": 142, "visitors": 130 },
    { "name": "download_pdf", "count": 87, "visitors": 65 }
  ],
  "meta": { "site_id": "...", "range": "30d", "limit": 10, "generated_at": "..." }
}
GET/api/v1/stats/utm

Visitor breakdown by UTM source.

{
  "data": [
    { "name": "google", "visitors": 320 },
    { "name": "newsletter", "visitors": 85 }
  ],
  "meta": { "site_id": "...", "range": "30d", "limit": 10, "generated_at": "..." }
}

Error codes

StatusCodeDescription
401unauthorizedMissing or invalid Authorization header
401invalid_keyAPI key not found or invalid format
401key_disabledAPI key has been disabled
401key_expiredAPI key has passed its expiry date
400site_requiredAccount key used without ?site_id=
400invalid_parameterInvalid query parameter value
400invalid_datestart or end is not a valid date
400unsupported_filterFilter (browser, os, channel) is not yet supported
403plan_requiredAPI access requires a Starter plan or higher
403forbiddenKey does not have access to that site
429rate_limit_exceededToo many requests. Check X-RateLimit-Reset header
500internal_errorServer error fetching data

CORS

All endpoints allow cross-origin requests. Responses include Access-Control-Allow-Origin: *. You can call the API from browser-side JavaScript, but be careful not to expose your API key in client-side code.

Example: fetch top pages from JavaScript

const response = await fetch(
  "https://glyphex.io/api/v1/stats/pages?range=7d&limit=5",
  {
    headers: {
      "Authorization": "Bearer glx_your_api_key_here"
    }
  }
);

const { data, meta } = await response.json();

// data = [{ pathname: "/", title: "Home", views: 520, visitors: 380 }, ...]

Need help?

If you have questions about the API, reach out via