Source: https://datafa.st/docs/api/website/goals/properties
Markdown source: https://datafa.st/docs/api/website/goals/properties.md
Description: Discover a custom goal's parameters and compare completions by parameter value.

# Custom goal properties

`GET https://datafa.st/api/v1/analytics/goals/properties`

Answer questions such as “Which plan did people choose when signing up?” using the same recorded event properties shown when you expand a goal in the dashboard.

## Two steps

1. Send `eventName=signup` to discover the recorded property names, such as `plan` or `button_location`.
2. Add `propertyName=plan` to get the completion and unique-visitor counts for each value, such as `free` and `pro`.

Use the exact goal name returned by [Analyze goals](/docs/api/website/goals/analyze). The original goals endpoint continues to return totals per goal. This endpoint covers custom goals only, including properties sent with `data-fast-goal-{property}`, the JavaScript SDK, or server-side goal `metadata`. Payment and subscription lifecycle events are excluded.

## Authentication and access

Use the standard `Authorization: Bearer` header:

- A website API key (`df_`) selects its own website automatically.
- An account token (`dft_`) requires `websiteId`, `analytics:read`, and access to that website. The current account and website access checks apply on every request.

This uses the same API access entitlement as other analytics endpoints, with no additional plan upgrade or property-specific quota. The normal API limit is 60 requests per minute per credential. Public dashboard access does not grant API access. Custom properties may contain data you deliberately recorded; only share a credential with an integration that should read that website's analytics. [Authentication and scopes](/docs/api/authentication).

## Query parameters

| Parameter | Required | Description |
|---|---|---|
| `eventName` | Yes | Exact custom goal name, 1–64 lowercase letters, digits, underscores, hyphens, or colons. Example: `signup`. |
| `propertyName` | No | Exact property name. Omit to list available properties; supply it to list values. Case-sensitive, 1–200 characters. |
| `websiteId` | With `dft_` | Website ID. With `df_`, omit it or supply that key's website ID. |
| `startAt` / `endAt` | No | Supply both or neither. Inclusive ISO timestamps with Z/offset, or YYYY-MM-DD dates. Omit both for all recorded history. |
| `timezone` | No | IANA timezone; defaults to the website timezone. Date-only bounds include the full local day. Explicit timestamp offsets are respected. |
| `limit` | No | Number of rows, 1–1000; default 100. |
| `offset` | No | Number of rows to skip, 0–4294967295; default 0. |
| `fields` | No | Comma-separated response fields. Property discovery: `property,completions,visitors`. Value breakdown: `value,completions,visitors`. Omit for all three. |

Unknown or duplicate query parameters are rejected. Reserved event fields `eventName`, `eventType`, and `isServer` are not custom properties.

## Filters

Supported event filters are `filter_country`, `filter_region`, `filter_city`, `filter_browser`, `filter_os`, `filter_device`, `filter_referrer`, `filter_ref`, `filter_source`, `filter_via`, `filter_utm_source`, `filter_utm_medium`, `filter_utm_campaign`, `filter_utm_term`, `filter_utm_content`, and `filter_page`.

Use `is:value` or `is_not:value`; comma-separated values match any value. Page also accepts `contains:value` and `does_not_contain:value`. Example: `filter_device=is:mobile`. Website country exclusions apply. These filters describe the event that recorded the property. Entry-page, hostname, visit-count, channel, and goal filters are not supported here and return 400; `eventName` selects the goal.

## Response and counting

- `property` is a property name when discovering keys. `value` is the recorded value when requesting a specific property; values are returned as strings, including numbers, booleans, and JSON values stored by older integrations.
- `completions` counts goal events containing that property or value. Repeated completions by the same visitor are counted separately.
- `visitors` counts unique visitors within each row. A visitor can occur in multiple rows, so adding visitor counts does not produce a deduplicated goal total.
- Missing properties, nulls, and empty strings are excluded; zero and false are retained. A goal's property counts can therefore be lower than its total completions. Listing properties is not a mutually exclusive breakdown: one event can have several properties.
- Rows sort by completions descending, then property name/value ascending. `pagination.total` counts matching distinct names or values. `hasMore` indicates another page. An unknown goal/property or a page beyond the end returns an empty `data` array. Pagination can change as new events arrive; use fixed dates for exports.
- `meta` returns the goal, selected property (null for discovery), timezone, and resolved UTC bounds (null for all history). Upstream failures return an error rather than an empty successful result.

## MCP

Use `datafast_analytics_goal_properties` with `eventName`, optional `propertyName`, and the same date, pagination, and field controls. The `filters` object uses names without the `filter_` prefix. Example: `{"eventName":"signup","propertyName":"plan","filters":{"device":"is:mobile"}}`. Account tokens also require `websiteId`. [Connect your agent](/docs/mcp-introduction).

[Try goal properties in the API playground](/docs/api/playground?endpoint=goal-properties).

## Errors

The standard error envelope is `{"status":"error","error":{"code":400,"message":"..."}}`.

| Status | Meaning |
|---|---|
| 400 | Missing goal name, invalid dates, fields, filters, or pagination. |
| 401 | Missing or invalid API credential. |
| 403 | Inactive account, missing permission, or website outside credential access. |
| 404 | Website does not exist. |
| 429 | Standard API rate limit reached. |
| 502 | Property data could not be loaded; retry shortly. |

## Code examples

### Compare signup plans

```bash
curl --get "https://datafa.st/api/v1/analytics/goals/properties" \
  -H "Authorization: Bearer df_xxx" \
  --data-urlencode "eventName=signup" \
  --data-urlencode "propertyName=plan" \
  --data-urlencode "startAt=2026-09-01" \
  --data-urlencode "endAt=2026-09-05" \
  --data-urlencode "timezone=UTC"
```

### Example response

```json
{
  "status": "success",
  "data": [
    {
      "value": "free",
      "completions": 80,
      "visitors": 73
    },
    {
      "value": "pro",
      "completions": 25,
      "visitors": 24
    }
  ],
  "pagination": {
    "limit": 100,
    "offset": 0,
    "total": 2,
    "hasMore": false
  },
  "meta": {
    "eventName": "signup",
    "propertyName": "plan",
    "timezone": "UTC",
    "startAt": "2026-09-01T00:00:00.000Z",
    "endAt": "2026-09-05T23:59:59.999Z"
  }
}
```
