Skip to main content

Event Ingestion Guide

This guide shows how to send analytics events to BreakGround via the POST /api/sdk/events endpoint. It covers the full integration lifecycle, event schema, and realistic payload examples for common event types.

Integration Lifecycle

The recommended order for SDK integration:

  1. Fetch configGET /api/sdk/config to get company settings and feature flags
  2. Identify userPOST /api/sdk/identify to register or update the end user
  3. Start sessionPOST /api/sdk/session to create a tracking session
  4. Send eventsPOST /api/sdk/events to submit batched analytics events

Full TypeScript Example

const API_KEY = "wfx_your_api_key_here";
const BASE = "https://api.breakground.io/api/sdk";

const headers = {
"Content-Type": "application/json",
"X-API-Key": API_KEY,
};

// 1. Fetch company config
const config = await fetch(`${BASE}/config`, { headers }).then((r) => r.json());
console.log("Company:", config.data.name, "Plan:", config.data.plan);

// 2. Identify the user
const identity = await fetch(`${BASE}/identify`, {
method: "POST",
headers,
body: JSON.stringify({
userId: "user-42",
traits: { name: "Jane Doe", plan: "professional" },
}),
}).then((r) => r.json());
console.log("Internal ID:", identity.data.id);

// 3. Send events
const result = await fetch(`${BASE}/events`, {
method: "POST",
headers,
body: JSON.stringify({
events: [
{
type: "PAGE_VIEW",
userId: "user-42",
url: "https://app.example.com/dashboard",
timestamp: new Date().toISOString(),
properties: {
title: "Dashboard",
referrer: "https://app.example.com/login",
},
},
],
}),
}).then((r) => r.json());
console.log("Accepted:", result.data.accepted); // 1

Event Schema

Each event in the events array has the following fields:

FieldTypeRequiredDescription
typestringYesEvent type (see Event Types below)
namestringNoHuman-readable name (e.g., "feature_activated" for CUSTOM events)
propertiesobjectNoArbitrary key-value data specific to this event
timestampstringNoISO 8601 timestamp. Defaults to server time if omitted
userIdstringNoExternal user ID (as passed to POST /api/sdk/identify)
urlstringNoPage URL where the event occurred
metadataobjectNoAdditional context (device info, SDK version, etc.)

Request Format

{
"events": [
{ "type": "PAGE_VIEW", "userId": "user-42", "url": "..." },
{
"type": "CLICK",
"userId": "user-42",
"properties": { "selector": "#btn" }
}
]
}

Response Format (HTTP 202)

{
"data": {
"accepted": 2,
"correlationId": "req-abc123"
}
}

The correlationId can be used to trace events through the processing pipeline.

Event Types

Page and Interaction Events

TypeDescription
PAGE_VIEWUser navigated to a page
CLICKUser clicked an element
ELEMENT_INTERACTIONUser interacted with a specific UI element
FORM_INTERACTIONUser submitted or interacted with a form
SCROLL_DEPTHUser scrolled to a specific depth on a page

UX Quality Events

TypeDescription
RAGE_CLICKUser clicked rapidly on the same element (frustration signal)
DEAD_CLICKUser clicked an element that produced no response

Flow Lifecycle Events

TypeDescription
FLOW_STARTEDUser entered a guided flow
STEP_VIEWEDA flow step was displayed to the user
STEP_COMPLETEDUser advanced past a flow step
FLOW_COMPLETEDUser finished all steps in a flow
FLOW_SKIPPEDUser skipped a flow
FLOW_DISMISSEDUser closed/dismissed a flow before completing it

Content Lifecycle Events

TypeDescription
CONTENT_LOADEDContent was fetched from the API
CONTENT_AUDIENCE_MATCHEDUser matched the audience targeting rules
CONTENT_RENDEREDContent widget was displayed to the user
CONTENT_RENDER_FAILEDContent widget failed to render
CONTENT_SUBMISSION_PERSISTEDA survey or NPS response was saved

Journey Events

TypeDescription
JOURNEY_STARTEDUser began a multi-step journey
JOURNEY_COMPLETEDUser finished all journey steps

Feedback Events

TypeDescription
SURVEY_RESPONSEUser submitted a survey response
NPS_RESPONSEUser submitted an NPS score

Experiment Events

TypeDescription
EXPERIMENT_CONVERSIONUser completed a conversion goal in an experiment

System Events

TypeDescription
SDK_INITSDK was initialized
SELECTOR_NOT_FOUNDA CSS selector referenced by content could not be found on the page
ERRORAn error occurred in the SDK
NETWORKA network request was made or failed
IDENTIFYUser identification event

Custom Events

TypeDescription
CUSTOMCustom event defined by the integrator. Use the name field to specify the event name

Payload Examples

Page View

curl -X POST https://api.breakground.io/api/sdk/events \
-H "Content-Type: application/json" \
-H "X-API-Key: wfx_your_api_key_here" \
-d @- << 'EOF'
{
"events": [
{
"type": "PAGE_VIEW",
"userId": "user-42",

"url": "https://app.example.com/dashboard",
"timestamp": "2026-03-18T14:30:00.000Z",
"properties": {
"title": "Main Dashboard",
"path": "/dashboard",
"referrer": "https://app.example.com/login"
}
}
]
}
EOF

Click Event

{
"events": [
{
"type": "CLICK",
"userId": "user-42",

"url": "https://app.example.com/dashboard",
"timestamp": "2026-03-18T14:30:12.456Z",
"properties": {
"tagName": "BUTTON",
"id": "create-report-btn",
"className": "btn btn-primary",
"text": "Create Report",
"x": 450,
"y": 320
}
}
]
}

Flow Lifecycle (Batched)

A typical flow generates multiple events. Send them together in a single batch:

{
"events": [
{
"type": "FLOW_STARTED",
"userId": "user-42",

"timestamp": "2026-03-18T14:31:00.000Z",
"properties": {
"flowId": "550e8400-e29b-41d4-a716-446655440000",
"flowName": "New User Onboarding"
}
},
{
"type": "STEP_VIEWED",
"userId": "user-42",

"timestamp": "2026-03-18T14:31:00.100Z",
"properties": {
"flowId": "550e8400-e29b-41d4-a716-446655440000",
"stepIndex": 0,
"stepType": "TOOLTIP"
}
},
{
"type": "STEP_COMPLETED",
"userId": "user-42",

"timestamp": "2026-03-18T14:31:15.000Z",
"properties": {
"flowId": "550e8400-e29b-41d4-a716-446655440000",
"stepIndex": 0
}
},
{
"type": "FLOW_COMPLETED",
"userId": "user-42",

"timestamp": "2026-03-18T14:31:45.000Z",
"properties": {
"flowId": "550e8400-e29b-41d4-a716-446655440000",
"flowName": "New User Onboarding",
"duration": 45000,
"stepsCompleted": 3,
"totalSteps": 3
}
}
]
}

Custom Event

Use CUSTOM type with a descriptive name field for application-specific events:

{
"events": [
{
"type": "CUSTOM",
"name": "feature_activated",
"userId": "user-42",

"timestamp": "2026-03-18T14:32:00.000Z",
"properties": {
"featureName": "advanced-search",
"plan": "professional",
"source": "onboarding-tour"
}
}
]
}

Survey Response

{
"events": [
{
"type": "SURVEY_RESPONSE",
"userId": "user-42",

"timestamp": "2026-03-18T14:33:00.000Z",
"properties": {
"surveyId": "770e8400-e29b-41d4-a716-446655440000",
"answers": {
"satisfaction": 4,
"feedback": "The onboarding was very helpful"
}
}
}
]
}

UX Quality (Rage Click)

{
"events": [
{
"type": "RAGE_CLICK",
"userId": "user-42",

"url": "https://app.example.com/settings",
"timestamp": "2026-03-18T14:34:00.000Z",
"properties": {
"selector": "#save-button",
"clickCount": 7,
"timeSpanMs": 2100
}
}
]
}

Error Event

{
"events": [
{
"type": "ERROR",
"userId": "user-42",
"url": "https://app.example.com/reports",
"timestamp": "2026-03-18T14:35:00.000Z",
"properties": {
"message": "Failed to load resource: net::ERR_CONNECTION_REFUSED",
"source": "sdk",
"stack": "TypeError: Failed to fetch\n at SDKApiClient.request (api.js:42)"
}
}
]
}

Error Handling

Validation Error (400)

Returned when the event payload fails schema validation:

{
"error": {
"message": "Validation failed",
"statusCode": 400,
"code": "VALIDATION_ERROR",
"category": "VALIDATION",
"details": [
{
"path": "events.0.type",
"message": "Invalid enum value. Expected 'PAGE_VIEW' | 'CLICK' | ... | 'JOURNEY_COMPLETED', received 'INVALID_TYPE'"
}
]
}
}

Authentication Error (401)

{
"error": {
"message": "Unauthorized: Invalid API key",
"statusCode": 401,
"code": "AUTH_FAILED",
"category": "AUTH"
}
}

Rate Limit Error (429)

{
"error": {
"message": "Rate limit exceeded",
"statusCode": 429,
"code": "RATE_LIMITED",
"category": "RATE_LIMIT"
}
}

Check the Retry-After response header for when to retry.

See Error Codes for the full error reference.

Best Practices

  • Batch events — Send multiple events in a single request to reduce HTTP overhead and stay within the 600 req/min rate limit. The BreakGround SDK batches up to 50 events per request by default.
  • Include userId — Events without this field cannot be attributed to users in analytics.
  • Use ISO 8601 timestamps — The timestamp field accepts ISO 8601 strings (e.g., 2026-03-18T14:30:00.000Z). If omitted, the server uses the current time.
  • Handle page unload — Use navigator.sendBeacon() with the _apiKey body field to flush remaining events when the page is closing, since custom headers are not supported by sendBeacon.
  • Retry with backoff — On 429 or 5xx errors, retry with exponential backoff (e.g., 1s, 2s, 4s) up to a maximum of 60 seconds. Respect the Retry-After header on 429 responses.