Coletor do app (pageviews, etapas do funil e heartbeat)
POST/api/analytics/events
- Auth
- Public
- Clé d’API:
- reports:write
- X-CommunityId
X-CommunityIdEnvoyez le X-CommunityId de la communauté où l’opération a lieu.
**Público**: visitante deslogado também envia. Com `Authorization`, os eventos levam o perfil; no primeiro lote logado de uma sessão, os eventos anônimos dessa mesma sessão (mesma aba) passam a ser desse perfil, marcados `wasAnonymous`.
Lote de 1 a 50 eventos de uma sessão.
**A sessão é emitida pelo servidor.** Mande em `sessionId` o `sessionToken` da resposta anterior (guarde no `sessionStorage` da aba). Sem ele, ou com um valor que não foi emitido por este servidor para esta comunidade (id inventado pelo cliente, adulterado, de outra comunidade ou com mais de 24 h), o lote abre **uma sessão nova** e é gravado nela; a resposta traz o `sessionToken` novo. Cada IP abre no máximo 60 sessões por minuto (o resto é descartado e contado). Só eventos de uma sessão emitida para a própria aba passam ao perfil no login. `type`: `page_view`, `funnel_step` ou `heartbeat` (a cada 60 s com a aba visível; alimenta só o "online agora" e o "tempo real", não é gravado). `funnelStep` aceito do app: `catalog`, `product`, `checkout_identify`, `checkout_payment` (enviado e pago vêm dos pedidos). Nunca envie dado digitado.
**Métricas de leitura do post.** O `page_view` da página do post leva `contentId` (o post aberto: conta como **leitura**). Dois tipos só de post, ambos com `contentId` obrigatório: `post_expand` (o "…ver mais" foi aberto) e `post_link_click` (clique num link do corpo ou num cartão de link; manda o `href` ou o domínio em `linkHost`). Do link, o servidor guarda **só o domínio** (minúsculo, sem `www.`), nunca o endereço, a query ou a posição; link que não é `http(s)` (mailto:, tel:) é descartado. `contentId` só vale para um post **não apagado da comunidade do lote que quem envia pode ler** (a mesma regra do detalhe do post: sem login, só post público e publicado): `post_expand` e `post_link_click` com outro id (ou sem id) são descartados (contam em `dropped`) sem recusar o lote; o `page_view` com outro id é gravado sem o `contentId` (continua contando como página). Os números de páginas e visitas não mudam com esses eventos.
O servidor guarda só a rota (sem query string; segmentos com cara de token ou e-mail são trocados), o host do `referrer`, as UTMs, device/navegador/sistema e o país (derivado do IP, que não é gravado). Robô ruim (UA vazio, `curl`, `python-requests`, headless) e o que passar de 120 eventos/min por sessão (600/min por IP, somados entre os servidores) são descartados e só contados; buscadores e LLMs são contados pelo servidor do app. Responde **202** mesmo quando descarta (`dropped`), com `sessionToken` sempre que o lote é de navegador (não de robô). Aceita `text/plain` com o JSON no corpo (para `navigator.sendBeacon`, que não manda cabeçalho: aí a comunidade vai em `communityId` no corpo).
En-têtes
| Nom | Type | Description |
|---|---|---|
X-CommunityIdfacultatif | string (uuid) | Comunidade. Sem o cabeçalho (sendBeacon), use `communityId` no corpo. |
Corps de la requête application/json
| Nom | Type | Description |
|---|---|---|
communityIdfacultatif | string (uuid) | Só quando não há o cabeçalho X-CommunityId. |
sessionIdfacultatif | string | O `sessionToken` da resposta anterior (53 caracteres). Opcional: sem ele, uma sessão nova. |
eventsobligatoire | object[] | |
events[].typeobligatoire | page_view | funnel_step | heartbeat | post_expand | post_link_click | |
events[].pathobligatoire | string | Rota canônica do app. |
events[].spaceIdfacultatif | string (uuid) | |
events[].modulefacultatif | string | |
events[].funnelStepfacultatif | catalog | product | checkout_identify | checkout_payment | |
events[].productIdfacultatif | string (uuid) | |
events[].planIdfacultatif | string (uuid) | |
events[].contentIdfacultatif | string (uuid) | O post. Opcional no `page_view` da página do post; obrigatório em `post_expand` e `post_link_click`. |
events[].linkHostfacultatif | string | Só em `post_link_click` (obrigatório): o `href` clicado ou o domínio; só o domínio é guardado. |
events[].referrerfacultatif | string | URL de origem; só o host é guardado. |
events[].utmSourcefacultatif | string | |
events[].utmMediumfacultatif | string | |
events[].utmCampaignfacultatif | string | |
events[].occurredAtfacultatif | string (date-time) | Ajustado para no máximo 1 h no passado e nunca no futuro. |
Réponses
| Statut | Description |
|---|---|
202 | Lote recebido. |
400 | Requisição inválida — falha de validação. |
404 | Recurso não encontrado. |
Exemple curl
curl -X POST "https://api.memberfy.net/api/analytics/events" \
-H "X-CommunityId: $COMMUNITY_ID" \
-H "Content-Type: application/json" \
-d '{"events":[{}]}'