본문으로 건너뛰기

분석: 하나의 뷰

분석은 사용자 상태를 읽는 것입니다. 퍼널, 리텐션, 코호트는 엔진의 나머지가 작용하는 것과 동일한 실시간 투영에 대한 쿼리입니다.

At a glance

Host
https://eu.api.prodantix.com
Ingest
POST /v1/events and its rules: Ingest API
Query
analytics and events queries: GraphQL reference
  • 퍼널과 리텐션은 실시간 상태에서 계산되며, 야간 웨어하우스 롤업이 아닙니다
  • 코호트는 한 번 정의하면 이벤트가 도착하는 대로 최신 상태로 유지됩니다
  • SQL 왕복이 없음. 상태가 이미 질문에 맞게 형성되어 있습니다

작동 방식

Events land on the EU ingestion host, are buffered through Redpanda and written to ClickHouse. Queries read from ClickHouse, so a funnel over thirty days answers in the same shape whether it spans a thousand events or a billion.

Ingestion answers 202: acceptance for processing, not proof of storage. The Ingest API page carries the full contract.

접근 위치

SurfaceOperation
RESTPOST /v1/events · POST /v1/identify · POST /v1/group
GraphQLrunQuery · runFunnel · runRetention · runPaths · runStickiness · runLifecycle · events · dashboards, cohorts
MCPprodantix.analytics.runQuery

예시

curl -X POST "https://eu.api.prodantix.com/v1/events" \
  -H "Authorization: Bearer $PRODANTIX_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "events": [{
      "distinct_id": "u_8f3a",
      "event_id": "5f6b2c1e-8f4b-4c6e-9d2a-7b1e3c4d5a6f",
      "event_name": "order.completed",
      "properties": { "amount": 4200 },
      "schema_version": 1,
      "timestamp": "2026-08-31T12:00:00.000Z"
    }],
    "sent_at": "2026-08-31T12:00:01.000Z"
  }'

Querying a trend

A trend takes one or more metrics, each its own event and measure, an optional formula per letter, up to three breakdowns and a comparison against an earlier window. A single metric skips the array: event, measure and, for one breakdown, breakdown stand in for metrics and breakdowns, and the two shapes never mix in the same query.

GraphQL
query RunQuery($projectId: String!, $query: MetricsQueryInput!) {
  runQuery(projectId: $projectId, query: $query) {
    series {
      key
      metric
      breakdown
      past
      points {
        time
        value
      }
    }
  }
}

# $query
{
  "metrics": [
    { "event": "checkout.started", "measure": { "kind": "total" } },
    { "event": "checkout.completed", "measure": { "kind": "total" } }
  ],
  "formulas": [{ "expression": "B / A * 100" }],
  "breakdowns": [{ "property": "plan" }, { "column": "geo_country" }],
  "compare": { "to": "previous_period" },
  "dateRange": { "from": "2026-08-01T00:00:00Z", "to": "2026-09-01T00:00:00Z" },
  "granularity": "day"
}

Querying a funnel

GraphQL
query Funnel($projectId: String!, $query: JSON!) {
  runFunnel(projectId: $projectId, query: $query) {
    step
    event
    users
    conversionFromPrevious
    droppedOff
  }
}

# $query
{
  "steps": [{ "event": "signup.started" }, { "event": "signup.completed" }, { "event": "order.completed" }],
  "conversionWindowSeconds": 2592000,
  "dateRange": { "from": "2026-08-01T00:00:00Z", "to": "2026-09-01T00:00:00Z" }
}

Paths, stickiness and lifecycle

Three more reports take the same shape: a JSON query the server validates against the report's own parser, and a list of rows back. Paths walk one to five steps after (or before) an anchor and rank the top three, five or ten events per step; stickiness counts a period's users by their active days; lifecycle sorts a period's users into new, returning, resurrecting and dormant.

GraphQL
query Paths($projectId: String!, $query: JSON!) {
  runPaths(projectId: $projectId, query: $query) {
    step
    users
    events { event users share }
    otherEvents
    otherUsers
    droppedOff
  }
}

# $query
{
  "anchorEvent": "checkout.started",
  "direction": "after",
  "steps": 3,
  "topN": 5,
  "dateRange": { "from": "2026-08-01T00:00:00Z", "to": "2026-09-01T00:00:00Z" }
}
GraphQL
query Stickiness($projectId: String!, $query: JSON!) {
  runStickiness(projectId: $projectId, query: $query) {
    period
    users
    days { daysActive users }
  }
}

# $query
{
  "event": "session.started",
  "bucket": "week",
  "dateRange": { "from": "2026-07-06T00:00:00Z", "to": "2026-09-01T00:00:00Z" }
}
GraphQL
query Lifecycle($projectId: String!, $query: JSON!) {
  runLifecycle(projectId: $projectId, query: $query) {
    period
    new
    returning
    resurrecting
    dormant
  }
}

# $query
{
  "event": "session.started",
  "bucket": "week",
  "dateRange": { "from": "2026-07-27T00:00:00Z", "to": "2026-09-07T00:00:00Z" }
}