Documentation menu

Goals

Conversion goals. A `pageview` goal converts when a visitor loads a pathname; an `event` goal converts when a named custom event fires.

5 endpoints, all relative to https://analytics.appfor.you. Shared rules live in Conventions, Rate limits and Error codes.

List goals

GET/api/v2/sites/{siteId}/goalsscope: read

Each goal carries the number of unique converting sessions for the window. Available to the site owner and to accepted team members of any role.

  • The resolved window is echoed as a `range` OBJECT — `{ preset, since, until }` — and only when `includeConversions` is not disabled. The earlier flat `range`/`since`/`until` fields no longer exist.
  • Conversion counts for the whole page are computed with at most two aggregations regardless of `limit`, so requesting `limit=500` costs the same as `limit=10`.
  • An unusable window (unparseable `from`/`to`, or a window that ends before it starts) returns 400 rather than silently reporting zero conversions. `GET /goals/{goalId}` and `GET /funnels/{funnelId}/stats` now behave identically.
  • Date-only `from`/`to` cover WHOLE days: `to=2025-03-21` runs through `2025-03-21T23:59:59.999Z`, so `from=X&to=X` is a full 24-hour day. It previously produced an empty window that always reported zero.

Path parameters

siteIdstringThe Mongo _id returned as `siteId` by GET /api/v2/sites, or the public `trackingId` embedded in the tracking snippet. Both are accepted everywhere.

Query parameters

NameTypeDescription
rangestringRelative window: `24h`, `7d`, `30d`, `90d` or `365d`. Default `30d`. Overridden by `from`/`to`.
fromstring (ISO-8601 or YYYY-MM-DD)Explicit window start, overriding `range`. A date-only `YYYY-MM-DD` value means that day from `T00:00:00.000Z`; a value carrying a time is an instant and is used verbatim. Supplying only `from` gives `[from, now]`. An unparseable value, or a window that ends before it starts, returns 400.
tostring (ISO-8601 or YYYY-MM-DD)Explicit window end, overriding `range`. A date-only `YYYY-MM-DD` value covers the WHOLE day, through `T23:59:59.999Z` — the final day is included, and `from=X&to=X` is a full 24 hours rather than the zero-width window it used to be. A value carrying a time is used verbatim. An end in the future is clamped to now, except where clamping would invert the window. Supplying only `to` gives `[to - range, to]`. An unparseable value, or a window that ends before it starts, returns 400.
includeConversionsbooleanSet to `false` or `0` to skip the conversion aggregation (much faster). Any other value, and omitting it, counts as true.
limitintegerRows to return. Default 50, minimum 1, maximum 500.
offsetintegerRows to skip, for paging. Default 0.

Example request

curl -H "Authorization: Bearer $ANALYTICS_API_KEY" \
  "https://analytics.appfor.you/api/v2/sites/6507f1f77bcf86cd799439011/goals?range=30d"

Example response

{
  "goals": [
    {
      "goalId": "6512aa01bcf86cd7994390a1",
      "siteId": "6507f1f77bcf86cd799439011",
      "name": "Signup completed",
      "type": "pageview",
      "target": "/welcome",
      "conversions": 213,
      "createdAt": "2025-02-01T08:00:00.000Z",
      "updatedAt": "2025-02-01T08:00:00.000Z"
    }
  ],
  "total": 1,
  "limit": 50,
  "offset": 0,
  "range": {
    "preset": "30d",
    "since": "2025-02-19T00:00:00.000Z",
    "until": "2025-03-21T00:00:00.000Z"
  }
}

Create a goal

POST/api/v2/sites/{siteId}/goalsscope: write

Type `pageview` matches a PageView whose pathname equals `target`; type `event` matches an Event whose name equals `target`. Call the events endpoint first if you need to discover valid event names.

  • Team members with the `viewer` role receive 403.

Path parameters

siteIdstringThe Mongo _id returned as `siteId` by GET /api/v2/sites, or the public `trackingId` embedded in the tracking snippet. Both are accepted everywhere.

Request body

FieldTypeRequiredDescription
namestringYesDisplay name. Non-empty after trimming.
type'pageview' | 'event'YesWhat kind of activity converts this goal.
targetstringYesPathname (type=pageview) or custom event name (type=event). Non-empty after trimming.

Example request

curl -X POST "https://analytics.appfor.you/api/v2/sites/6507f1f77bcf86cd799439011/goals" \
  -H "Authorization: Bearer $ANALYTICS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Signup completed", "type": "pageview", "target": "/welcome" }'

Example response (201)

{
  "goalId": "6512aa01bcf86cd7994390a1",
  "siteId": "6507f1f77bcf86cd799439011",
  "name": "Signup completed",
  "type": "pageview",
  "target": "/welcome",
  "createdAt": "2025-03-21T09:00:00.000Z",
  "updatedAt": "2025-03-21T09:00:00.000Z"
}

Get a goal

GET/api/v2/sites/{siteId}/goals/{goalId}scope: read

Accepts the same window parameters as the list endpoint.

  • Returns 404 "Goal not found" when the id is malformed or belongs to another site.
  • Unlike the list endpoint, this one echoes a FLAT `range` string alongside top-level `since` and `until` rather than a `range` object. Those three fields, and `conversions`, are omitted entirely when `includeConversions` is disabled.
  • An unparseable or inverted `from`/`to` returns 400 here too, matching the list endpoint; it is no longer silently downgraded to the `range` preset. Date-only values cover whole days, so `from=X&to=X` is a full 24-hour day rather than an empty window.

Path parameters

siteIdstringThe Mongo _id returned as `siteId` by GET /api/v2/sites, or the public `trackingId` embedded in the tracking snippet. Both are accepted everywhere.
goalIdstringIdentifier of the goal.

Query parameters

NameTypeDescription
rangestringRelative window: `24h`, `7d`, `30d`, `90d` or `365d`. Default `30d`. Overridden by `from`/`to`.
fromstring (ISO-8601 or YYYY-MM-DD)Explicit window start, overriding `range`. A date-only `YYYY-MM-DD` value means that day from `T00:00:00.000Z`; a value carrying a time is an instant and is used verbatim. Supplying only `from` gives `[from, now]`. An unparseable value, or a window that ends before it starts, returns 400.
tostring (ISO-8601 or YYYY-MM-DD)Explicit window end, overriding `range`. A date-only `YYYY-MM-DD` value covers the WHOLE day, through `T23:59:59.999Z` — the final day is included, and `from=X&to=X` is a full 24 hours rather than the zero-width window it used to be. A value carrying a time is used verbatim. An end in the future is clamped to now, except where clamping would invert the window. Supplying only `to` gives `[to - range, to]`. An unparseable value, or a window that ends before it starts, returns 400.
includeConversionsbooleanSet to `false` or `0` to skip the conversion aggregation (much faster). Any other value, and omitting it, counts as true.

Example request

curl -H "Authorization: Bearer $ANALYTICS_API_KEY" \
  "https://analytics.appfor.you/api/v2/sites/6507f1f77bcf86cd799439011/goals/6512aa01bcf86cd7994390a1"

Example response

{
  "goalId": "6512aa01bcf86cd7994390a1",
  "siteId": "6507f1f77bcf86cd799439011",
  "name": "Signup completed",
  "type": "pageview",
  "target": "/welcome",
  "conversions": 213,
  "createdAt": "2025-02-01T08:00:00.000Z",
  "updatedAt": "2025-02-01T08:00:00.000Z",
  "range": "30d",
  "since": "2025-02-19T00:00:00.000Z",
  "until": "2025-03-21T00:00:00.000Z"
}

Update a goal

PATCH/api/v2/sites/{siteId}/goals/{goalId}scope: write

At least one field is required. Mongoose validators run on update; the updated goal is returned.

  • Viewers receive 403.

Path parameters

siteIdstringThe Mongo _id returned as `siteId` by GET /api/v2/sites, or the public `trackingId` embedded in the tracking snippet. Both are accepted everywhere.
goalIdstringIdentifier of the goal.

Request body

Every field is optional, but at least one must be supplied.

FieldTypeRequiredDescription
namestringNoNew display name.
type'pageview' | 'event'NoNew goal type.
targetstringNoNew pathname or event name.

Example request

curl -X PATCH "https://analytics.appfor.you/api/v2/sites/6507f1f77bcf86cd799439011/goals/6512aa01bcf86cd7994390a1" \
  -H "Authorization: Bearer $ANALYTICS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "target": "/thank-you" }'

Example response

{
  "goalId": "6512aa01bcf86cd7994390a1",
  "siteId": "6507f1f77bcf86cd799439011",
  "name": "Signup completed",
  "type": "pageview",
  "target": "/thank-you",
  "createdAt": "2025-02-01T08:00:00.000Z",
  "updatedAt": "2025-03-21T09:20:00.000Z"
}

Delete a goal

DELETE/api/v2/sites/{siteId}/goals/{goalId}scope: adminDestructive

Deleting a goal destroys the definition and every conversion report built on it. Pass `confirm=<goalId>` as a query parameter or as a `confirm` field in the JSON body — it must equal the 24-character goal id from the URL, not the goal name.

Irreversible. Requires the admin scope and confirm={goalId} — see Destructive operations.

  • Viewers receive 403; an unknown id returns 404.
  • The confirmation is checked AFTER the scope and site-access checks but BEFORE the id is validated, so a wrong `confirm` with a non-existent id returns 400, never a 404 — a missing confirmation never reveals whether the goal exists.

Path parameters

siteIdstringThe Mongo _id returned as `siteId` by GET /api/v2/sites, or the public `trackingId` embedded in the tracking snippet. Both are accepted everywhere.
goalIdstringIdentifier of the goal.

Query parameters

NameTypeDescription
confirmstringDestructive-operation confirmation. Must exactly equal the `goalId` in the URL. May be sent as a `confirm` field in the JSON body instead.

Request body

Optional — send `{ "confirm": "<goalId>" }` instead of the query parameter if you prefer.

FieldTypeRequiredDescription
confirmstringNoMust equal the goalId in the URL.

Example request

curl -X DELETE "https://analytics.appfor.you/api/v2/sites/6507f1f77bcf86cd799439011/goals/6512aa01bcf86cd7994390a1?confirm=6512aa01bcf86cd7994390a1" \
  -H "Authorization: Bearer $ANALYTICS_API_KEY"

Example response

{
  "deleted": true,
  "goalId": "6512aa01bcf86cd7994390a1"
}