# Widget funnel beacon (fire-and-forget)

> Widget funnel beacon (fire-and-forget): CustomDomain™ API reference in the analytics group. Covers parameters, request body, responses and error codes.

Source: https://docs.customdomain.ai/docs/api-reference/analytics/recordConnectTelemetry

## `POST https://api.customdomain.ai/v1/telemetry:connect`

A PII-free beacon recording which step of the in-modal connect flow a user reached. It exists because server-side counters only observe connections that actually get created, and so are blind to pre-connection drop-off.
`step` and `outcome` are allow-listed server-side and anything unrecognised is folded into a fixed label. A beacon that carries a `session_id` is also stored against the calling application, which is what `GET /analytics/connect` reads; one without it is only counted. No domain is stored, and nothing the end user typed. With each stored beacon the control plane keeps the end user's IP address and country (from the request, believed only through Cloudflare), and the session it belongs to: at its first beacon the address, the region and city Cloudflare derived, and the device type, operating system and browser parsed from the User-Agent (the string itself is not stored); at every beacon the step, rail, provider and outcome. Addresses are kept for as long as the account exists, unless the deployment's `IP_RETENTION_DAYS` sets a window. It **always** answers `204`, including for an invalid token or a malformed body, so telemetry can never block or error the widget; do not branch on its response.

### Authentication

`apiKey`

### Request body (JSON)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `step` | string | no | Funnel step label (server-side allow-list). |
| `outcome` | string | no | Outcome label (server-side allow-list). |
| `session_id` | string | no | Random id per widget open, 8 to 64 of [A-Za-z0-9_-]. |
| `provider` | string | no | Detected DNS provider id. |
| `rail` | `oauth`, `domain_connect`, `manual`, `api_key`, `managed_dns`, `cloud_browser` | no |  |
| `domain_kind` | `apex`, `subdomain` | no |  |
| `error_code` | string | no | Widget error code, [A-Za-z0-9_] up to 48. |
| `connection_id` | string | no |  |
| `elapsed_ms` | integer | no | Milliseconds since the widget opened (capped at a day). |
| `client` | object | no | Optional. What the widget reports about its surroundings, recorded on the session while the session has no value for it yet. Every field is optional, and a value outside its range or alphabet is dropped; unlike the beacon's own fields an unknown field here is ignored, and an object larger than 2 KiB is ignored whole. |

### Responses

| Status | Description |
| --- | --- |
| `204` | Always. Carries no body and reports no error by design. |

The full specification is served at `GET https://api.customdomain.ai/v1/openapi.json`.
