Clicktag docs
Goals and funnels
Clicktag goals count the visitors who view a page or fire a custom event, and funnels chain 2 to 6 steps completed in order on the same UTC day, with conversion by referrer, entry page or country. A site can have up to 20 goals and funnels combined.
Base URL: https://clicktag.io. Read this page as Markdown.
Create a goal
Open a site, choose the Goals tab and click New goal. A site without goals suggests its top events and pages; pick one to start from it.
Every step matches either:
- Page: pageviews by path.
ismatches the path with or without a trailing slash,starts withmatches the path and every path below it (/blogmatches/blog/postbut not/blogging, and/matches every page),containsmatches anywhere in the path. - Event: a custom event by its exact name.
Add filters to narrow a step by page, source, country, device, browser, OS or UTM source, medium and campaign. Filters on different fields must all match. Two filters on the same field match either value. A step takes up to 6 filters, and a site up to 20 goals and funnels combined.
Page values start with /, contain no ? or #, and drop trailing slashes, so /pricing/ is saved as /pricing. Event names use letters, digits and _. In a funnel, a page step with no filters matches any pageview.
What the numbers mean
| Number | Meaning |
|---|---|
| Visitors | Unique visitors per day: someone active on 3 days counts 3 times |
| Converted visitors | Visitors with at least one matching pageview or event that day |
| Conversions | Every matching pageview or event |
| Conversion rate | Converted visitors divided by visitors, never above 100% |
| Funnel step | Visitors who completed this step after all earlier steps, in order, on the same UTC day |
| Time to convert | Median and 90th percentile time between two consecutive funnel steps |
Dashboard filters apply to goals too: they narrow the pageviews and events that goals are counted over. Funnel bars show each step as a share of step 1, with the drop-off from the step before.
Click a goal to break it down by referrer, entry page, country, device, browser, OS or UTM parameter. Each visitor is counted under the value of their first pageview that day.
Coverage
Goals need a visitor identity on every pageview. The collector derives one from each request; imported data has none. When less than 99% of the pageviews in a range carry an identity, the Goals tab says so:
Goals cover 72% of pageviews in this range (older imported data has no visitor identity).
Changes against the previous period only show when at least 99% of that period's pageviews carry an identity too. A range without any identified pageviews shows No visitor data in this range.
Events sent from your server with POST /events get an identity built from your server's IP address, not the visitor's, so they can't follow the visitor's pageviews in a funnel or inherit their referrer and entry page.
Access
Goal routes need the site owner's Firebase ID token or a management key, with read for GET and manage for changes, even for public sites. Every route, reads included, needs a verified site. Sites you don't own return 404 unknown site. See Authentication.
| Method | Route | Result |
|---|---|---|
| GET | /api/sites/{hostname}/goals |
List goals, oldest first |
| POST | /api/sites/{hostname}/goals |
Create a goal (201) |
| GET | /api/sites/{hostname}/goals/stats |
Numbers for every goal in a date range |
| GET | /api/sites/{hostname}/goals/{id} |
Read one goal |
| PUT | /api/sites/{hostname}/goals/{id} |
Replace a goal |
| DELETE | /api/sites/{hostname}/goals/{id} |
Delete a goal |
| GET | /api/sites/{hostname}/goals/{id}/stats |
Breakdown and funnel timing for one goal |
Goal object
{
"id": "0b7c3e52-6a0e-4f0d-9d51-3f1f5c2a9e10",
"name": "Pricing to signup",
"kind": "funnel",
"steps": [
{
"name": "Pricing",
"match": "pageview",
"filters": [{ "key": "page", "op": "eq", "value": "/pricing" }]
},
{
"name": "Signup completed",
"match": "event",
"filters": [{ "key": "event", "op": "eq", "value": "signup_completed" }]
}
],
"created_at": "2026-09-30T09:12:44.000Z",
"updated_at": "2026-09-30T09:12:44.000Z"
}| Field | Rules |
|---|---|
name |
1 to 80 characters |
kind |
goal (exactly 1 step) or funnel (2 to 6 steps) |
steps[].name |
Optional, up to 40 characters; stats call an unnamed step Step n |
steps[].match |
pageview or event |
filters[].key |
page, referrer, country, device, browser, os, utm_source, utm_medium, utm_campaign, event |
filters[].op |
eq; prefix and contains only with page |
filters[].value |
Page paths start with /; event names match ^[A-Za-z0-9_]{1,256}$ |
An event step has exactly one event filter with op: "eq"; a pageview step cannot use the event key. A goal step needs at least one filter. Two identical steps in a row, or the same filter twice in a step, are rejected.
A goal that no longer passes validation is listed with "invalid": true and left out of stats until it is saved again.
Create and change goals
curl -X POST https://clicktag.io/api/sites/example.com/goals \
-H "Authorization: Bearer $TT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Signup completed","kind":"goal","steps":[{"match":"event","filters":[{"key":"event","op":"eq","value":"signup_completed"}]}]}'POST returns the new goal with 201. PUT takes the same body, replaces the whole goal and returns it. DELETE returns {"deleted": "<id>"}. Goals are computed at query time, so a new or changed goal applies to past data too.
Goal stats
GET /api/sites/{hostname}/goals/stats?from=1790208000&to=1790812800&tz=Europe/Amsterdam
from and to are unix seconds with the same defaults and limits as the statistics API, tz sets the chart buckets and the previous period, and f takes the same filters.
{
"granularity": "day",
"visitors": 2016,
"previous_visitors": 1874,
"coverage": {
"pageviews": 5230,
"identified": 5230,
"previous": { "pageviews": 4870, "identified": 4870 }
},
"goals": [
{
"id": "7d2a8c1e-3b4f-4e6a-8c9d-0e1f2a3b4c5d",
"name": "Signup completed",
"kind": "goal",
"conversions": 143,
"converting_visitors": 118,
"rate": 0.0585,
"previous": { "conversions": 126, "converting_visitors": 104, "rate": 0.0555 },
"series": [
{ "t": 1790208000, "conversions": 19 },
{ "t": 1790294400, "conversions": 23 }
]
}
],
"funnels": [
{
"id": "0b7c3e52-6a0e-4f0d-9d51-3f1f5c2a9e10",
"name": "Pricing to signup",
"kind": "funnel",
"steps": [
{ "name": "Pricing", "visitors": 412 },
{ "name": "Signup completed", "visitors": 61 }
],
"previous": [388, 52]
}
],
"invalid": []
}rateis a fraction from 0 to 1, ornullwhen the range has no visitors.serieshas one entry per hour for ranges up to 4 days, otherwise one per day, zero-filled. Funnels have no series.- The previous period is the range moved back by as many calendar days as it covers in
tz, likeprevious_rangein the overview.previous_visitorsand everypreviousarenullwhen less than 99% of its pageviews carry an identity, or none do.
Goal breakdown
GET /api/sites/{hostname}/goals/{id}/stats?from=1790208000&to=1790812800&dim=referrers&limit=10
dim is one of referrers, pages (entry page), countries, devices, browsers, os, utm_sources, utm_mediums or utm_campaigns. limit is 1 to 100, default 10. from, to and f work as in goal stats. Rows are sorted by visitors, most first.
{
"dim": "referrers",
"breakdown": [
{ "name": "google.com", "visitors": 880, "steps": [170, 46] },
{ "name": "Direct / none", "visitors": 640, "steps": [131, 22] }
],
"timing": [{ "p50_s": 204, "p90_s": 3310, "n": 61 }]
}visitors counts the visitors whose first pageview that day had this value, and steps how many of them reached each step. timing has one entry per step transition, in seconds, and is null for goals; p50_s and p90_s are null when n is 0.
Errors
| Status | Error |
|---|---|
| 400 | invalid json, invalid range, invalid filter, unknown dimension, this goal has too many filters to measure, remove some or a validation message such as step 2 filter 1: unknown key |
| 401 | sign in required, or invalid or revoked management key |
| 403 | Install your tracking script to verify this site first; a management key without the needed scope gets scope read required or scope manage required |
| 404 | unknown site, unknown goal |
| 429 | too many goals for this site; a management key sending changes too fast gets rate limited, retry in <n>s with Retry-After |
| 504 | date range too large for goals, narrow it |