Docs·Web analytics

GET/api/v1/event/analytics/web-analytics/timeseries/:metric

Get a timeseries

One Overview metric over time: a point for every bucket of the range, oldest first, with 0 in buckets that had nothing. A bucket is one interval of the chosen granularity. The last part of the path picks the metric, and each point has date plus the fields listed here:

  • visitors-sessions: uniqueVisitors, sessionCount, returningVisitors, pageViews and topSources.
  • bounce-rate: uniqueVisitors and bounceRate.
  • new-vs-returning: uniqueVisitors, newVisitors and returningVisitors.
  • avg-session-duration: avgSessionDuration.
  • revenue: revenue, refundedRevenue and topSources. Only this path takes model and window.
  • conversion-rate: conversionRate.
  • revenue-per-visitor: revenuePerVisitor.

Sessions and their visitors count in the bucket the session started in; page views and payments count in the bucket they happened in. A visitor active in three buckets counts in each of them, so adding up the buckets gives more than the range's visitor total.

Keys: an account key. Getting started explains both kinds.

Paths

Path
/analytics/web-analytics/timeseries/avg-session-duration
/analytics/web-analytics/timeseries/bounce-rate
/analytics/web-analytics/timeseries/conversion-rate
/analytics/web-analytics/timeseries/new-vs-returning
/analytics/web-analytics/timeseries/revenue
/analytics/web-analytics/timeseries/revenue-per-visitor
/analytics/web-analytics/timeseries/visitors-sessions

Parameters

PropInTypeNotes
contactListIdquerystringThe id of the audience (the tracked site) to read, a UUID: anything else returns a 400. You must be a member of the workspace the audience belongs to, or the call returns a 401. An id that matches no audience is not an error: the call returns no data.
startDatequerystringStart of the date range, read as UTC: a date such as 2026-09-01 (from midnight), or an exact time such as 2026-09-01T09:30:00Z. Use one of these two forms.
endDatequerystringEnd of the date range, read as UTC. A date such as 2026-09-30 includes that whole day; an exact time such as 2026-09-30T18:00:00Z ends the range right before that moment. If the workspace has gone past its plan's event allowance this billing period, the range is cut short at the moment the allowance ran out.
granularityqueryGranularityBucket size: minute, hour, day, week or month, in UTC. A bucket is one such interval; weeks start on Monday and months on the 1st. minute needs a range of 25 hours or less and hour one of 8 days or less, or the call returns a 400.
filter?querystringNarrows the results: a URL-encoded JSON array of conditions, each [key, values, operator], where a missing operator means is. Example: [["country",["US","GB"]],["page",["/pricing"],"startsWith"]] keeps visits from the US or the UK that viewed a page starting with /pricing. Every condition must match, and each key can appear once (a second condition on the same key replaces the first). A condition matches any of its values, except that isNot, notContains and notRegex rule out all of them. Operators: is and isNot (exact), contains, notContains, startsWith and endsWith (ignoring case), regex and notRegex (RE2 syntax, so no lookarounds; a pattern that does not compile returns a 400), and isNull and isNotNull (the value is not set, or is set; send [] as the values). Keys: channel, referrer_source, referrer, utm_source, utm_medium, utm_campaign, utm_term, utm_content, country (a two-letter code), region, city, browser, browser_version, os, os_version, screen_size (Desktop, Mobile or Tablet), hostname, entry_page, exit_page, page and event_name (visits that viewed such a page or sent such an event), identified (["true"] or ["false"]), goal_id (people who completed the goal in the range) and cohort_id (members of a segment). The last two take ids and only is or isNot. Unknown keys, and a filter that is not valid JSON, are ignored rather than refused.
model?querystringrevenue only. How a payment is credited to the visits that led to it: last_touch gives all of it to the buyer's last non-direct visit before paying, linear splits it evenly among all their non-direct visits in the lookback window (see window). Direct visits never take credit. Left out, the audience's choice in Settings → Revenue applies (last-touch unless someone changed it). Any other value returns a 400. It changes how topSources is split, never the bucket's revenue.
window?querynumberrevenue only. Lookback window in days: how long before a payment a visit can be and still take credit. A whole number from 1 to 90; anything else returns a 400. Left out, the audience's setting in Settings → Revenue applies (30 days unless someone changed it).

Response

An array of objects.

PropTypeNotes
datestringStart of the bucket: YYYY-MM-DD for day, week and month buckets, or YYYY-MM-DD HH:MM:SS in UTC for minute and hour buckets.
avgSessionDurationnumberAverage length of the bucket's sessions in milliseconds, as a whole number. Sessions that have not ended yet count as 0.
uniqueVisitorsnumberDistinct visitors with a session that started in the bucket.
bounceRatenumberBounced sessions as a percentage of the bucket's sessions: 0 to 100, two decimals.
conversionRatenumberVisitors who made a payment in the bucket, divided by its uniqueVisitors: a fraction from 0 to 1 with four decimals.
newVisitorsnumberThose visitors whose first session ever started in this bucket.
returningVisitorsnumberThose visitors whose first session ever started in an earlier bucket.
revenuenumberNet revenue in the bucket (refunds subtracted), in the reporting currency, two decimals. model and window do not change it.
refundedRevenuenumberRefunds recorded in the bucket, as a positive amount. revenue plus refundedRevenue is what was sold in the bucket before refunds.
topSourcesDimensionTopSource[]visitors-sessions and revenue only, as { name, uniqueVisitors, revenue }. On visitors-sessions: the bucket's visitors per source (the referring site, such as Google), most first, then a Direct entry for the rest; at most 8 entries, each with revenue 0. On revenue: the bucket's revenue split by source under model and window, largest first, then a Direct entry for revenue no visit could take, so the entries add up to revenue; each has uniqueVisitors 0. That split is worked out for the whole audience, so filter does not narrow the per-source amounts.
revenuePerVisitornumberThe bucket's net revenue divided by its uniqueVisitors, two decimals.
sessionCountnumberSessions that started in the bucket.
pageViewsnumberPage views in the bucket.

Request

curl 'https://app.spreelytics.com/api/v1/event/analytics/web-analytics/timeseries/visitors-sessions?contactListId=…&startDate=…&endDate=…&granularity=…' \
  -H 'Authorization: Bearer YOUR_API_KEY'
const url = new URL('https://app.spreelytics.com/api/v1/event/analytics/web-analytics/timeseries/visitors-sessions');
url.searchParams.set('contactListId', '…');
url.searchParams.set('startDate', '…');
url.searchParams.set('endDate', '…');
url.searchParams.set('granularity', '…');

const res = await fetch(url, {
  headers: { Authorization: 'Bearer YOUR_API_KEY' },
});
const data = await res.json();
import requests

res = requests.get(
    "https://app.spreelytics.com/api/v1/event/analytics/web-analytics/timeseries/visitors-sessions",
    headers={"Authorization": "Bearer YOUR_API_KEY"},
    params={"contactListId": "…", "startDate": "…", "endDate": "…", "granularity": "…"},
)
data = res.json()

Response

[
  {
    "date": "string",
    "uniqueVisitors": 0,
    "sessionCount": 0,
    "returningVisitors": 0,
    "pageViews": 0,
    "topSources": [
      {
        "revenue": 0,
        "uniqueVisitors": 0,
        "name": "string"
      }
    ]
  }
]

See your own numbers today.

Free up to 100k events a month · no credit card

Contact

Tell us what you need.

A real person reads these. We usually reply within one working day.

Or email us directly at contact@spreelytics.com.