Metrics
Aggregated metrics, breakdowns and timeseries across any dimension, with the attribution model you choose. Endpoints, parameters, and schemas.
| Endpoint | Method | Path | Permission |
|---|---|---|---|
| Get metrics Aggregate metrics, breakdowns and timeseries | GET | /v1/metrics | metrics:read |
Base URL https://app.sourceloop.ai/api/v1
Get metrics
Aggregate metrics, breakdowns and timeseries
GET /v1/metrics
Requires metrics:read
Omit `group_by` for a single total. Add it for one row per dimension value, which also returns the window totals so the share each row represents is visible. Add `granularity` for a timeseries.
Note that a total and a timeseries are different queries: unique visitors cannot be summed across days without counting returning people twice, so the aggregate is computed once across the whole window.
curl -s -X GET "https://app.sourceloop.ai/api/v1/metrics?website=acme.com&period=last%2030%20days" \
-H "Authorization: Bearer $SOURCELOOP_API_KEY" const res = await fetch(
"https://app.sourceloop.ai/api/v1/metrics?website=acme.com&period=last%2030%20days",
{
method: "GET",
headers: {
Authorization: `Bearer ${process.env.SOURCELOOP_API_KEY}`,
},
},
);
const data = await res.json(); import os, requests
res = requests.get(
"https://app.sourceloop.ai/api/v1/metrics?website=acme.com&period=last%2030%20days",
headers={"Authorization": f"Bearer {os.environ['SOURCELOOP_API_KEY']}"},
)
data = res.json() Query parameters
websitestringWebsite domain, e.g. acme.com. Required only when the key covers more than one.
periodstringPlain-language period: "last 30 days", "yesterday", "July 2026", or "2026-07-01..2026-07-31". Ignored when from/to are given.
Example
last 30 daysfromstring (date-time)tostring (date-time)metricsstringrequiredComma-separated.
Allowed values22
visitorssessionspageviewseventsconversionsrevenuelifetime_valuecustomersavg_ltvrepeat_rateavg_orderscohort_mrrrevenue_per_customerconversion_ratepageviews_per_sessionrevenue_per_visitorspendimpressionsclicksroascacltv_cac
Example
visitors,conversions,conversion_rategroup_bystringSplit by one dimension, or up to four comma-separated for a nested breakdown such as channel,source. Omit for a single total.
Allowed values25
channelsourcemediumcampaignutm_termutm_contentreferrer_domainpagelanding_pagehostnamepage_titlecountryregioncitydevice_typebrowseroperating_systemresolutionplatformad_campaignad_setadad_platformkeywordcohort
Three of those are answered by a different store and behave differently:
- platform and ad_campaign join ad SPEND to the campaign that acquired each customer, which is what makes cac and ltv_cac available. They take one dimension at a time and cannot be crossed with traffic dimensions.
- resolution splits outcomes by WHY they had no journey (unmatched, predates tracking, imported contact) and is only available alongside credited metrics.
- cohort returns a retention curve instead of a ranking: rows are (cohort, period_index) and the window chooses which cohorts appear, never which payments count.
filterstring[]Repeatable, ANDed. Form: dimension:operator:value.
Operators6
eqneinnincontainsnot_contains
Filterable dimensions32
channelsourcemediumcampaignutm_termutm_contentreferrer_domainpagelanding_pagehostnamepage_titlecountryregioncitydevice_typebrowseroperating_systemresolutionevent_nameevent_typeidentifiedplatformad_campaignad_setadad_platformkeywordcampaign_typematch_typecompany_domaincrm_stagecrm_account_stage
Example
channel:in:paid_search,paid_socialgranularitystringReturn a daily time series instead of a single total. Only day is supported: the underlying store buckets by calendar day in the website timezone, so hour, week and month are rejected rather than silently returning days under another label.
Allowed values 1
day
attributionstringCredit conversions to a touchpoint using an attribution model instead of counting the event where the conversion fired. One of first_touch, last_touch, linear, u_shaped, time_decay, or up to five comma-separated to compare them in one response, which guarantees every model saw the same window and filters. Requires group_by, and only conversions and revenue can be attributed: a visitor has one channel at a time. When several models are given, each row nests one object per model; a null metric means that model truncated before reaching this value (see meta.truncated_models), which is not the same as zero.
Example
first_touch,last_touchoutcomestringWHAT is being counted, which is the question "what do you consider a conversion?" made explicit. Defaults to conversions, the tracked events your script recorded. The rest count a different KIND of object: contact_stage counts PEOPLE reaching a CRM stage, deal_status counts DEALS with the money on them, subscription_status counts subscriptions with MRR, payment_revenue counts individual payments, and revenue counts every money movement from the deduplicated ledger. One request counts ONE kind: 2 MQLs is not a slice of 39 conversions, it is a different object, so the two are never blended in one response. GET /v1/schema describes each with where its numbers come from; GET /v1/outcomes lists this workspace own stage keys.
Allowed values 7
conversionsconversion_typecontact_stagedeal_statussubscription_statuspayment_revenuerevenue
Example
contact_stageoutcome_valuesstringNarrows an outcome to specific stages or types, comma separated, using the keys from GET /v1/outcomes. Omit to count every value of that kind, which is what someone asking for their funnel means. Ignored for outcomes that are not workspace-defined.
Example
mql,sqlgrainstringWHO an outcome is counted over. A single B2C signup and a six-person B2B buying committee are the same shape in the data and different questions in the business. Only contact_stage offers companies, and the company view is SMALLER than the contact view rather than a slice of it: a company sits at the stage of its most advanced contact.
Allowed values 2
contactscompanies
stagesstringSuperseded by outcome and outcome_values, which say the same thing in words a caller can discover: this parameter never appeared in GET /v1/schema, so nobody could learn it existed. Still honoured, and outcome wins when both are sent.
Example
deal_wonconjunctionstringHow repeated filters combine. Default and.
Allowed values 2
andor
only_paidbooleanRestrict to paid traffic: a paid medium, or the presence of an ad click id.
limitintegerDefault
50
Responses
-
200Rows plus meta -
400Something was wrong with the request or the credential. -
429Too many requests for this workspace in the current minute. Wait Retry-After seconds and repeat the request unchanged.