AnalyticsBundle API
Read aggregate analytics, manage saved funnels and settings, inspect opportunities, and generate AnalyticsBundles through the REST API.
Analytics read and management routes require a Browser Session or Member Token. Project tokens cannot read analytics. They may submit events and, for an explicitly configured site/app pair, issue or receive a write-only visit handoff from its allowed browser origin.
curl https://api.debugbundle.com/v1/analytics/summary?project_id=<id>&last=7d \
-H "Authorization: Bearer dbundle_mem_..."Routes
| Method | Path | Purpose |
|---|---|---|
GET | /v1/projects/{id}/analytics-settings | Read availability, access mode, and project settings |
PATCH | /v1/projects/{id}/analytics-settings | Update settings as owner/admin |
GET | /v1/projects/{id}/analytics/saved-funnels | List active saved funnel definitions |
POST | /v1/projects/{id}/analytics/saved-funnels | Create/reactivate a definition as owner/admin |
PATCH | /v1/projects/{id}/analytics/saved-funnels/{funnelKey} | Update name or ordered steps |
DELETE | /v1/projects/{id}/analytics/saved-funnels/{funnelKey} | Soft-archive a definition |
GET | /v1/analytics/summary | Sessions, visitors, pageviews, exits, and conversions |
GET | /v1/analytics/routes | Route usage and incident-linked sessions |
GET | /v1/analytics/devices | Device/browser/OS/language segments |
GET | /v1/analytics/referrers | Referrer and UTM segments |
GET | /v1/analytics/actions | Actions, conversions, and markers |
GET | /v1/analytics/funnels | Funnel conversion summaries |
GET | /v1/analytics/funnels/{key} | Step-level funnel analysis |
GET | /v1/analytics/journey-patterns | Aggregate route transitions and sample references |
GET | /v1/analytics/journey-samples | List retained redacted sample metadata |
GET | /v1/analytics/journey-samples/{id} | Read one retained redacted timeline |
GET | /v1/analytics/incidents/{id}/impact | Correlation-backed aggregate incident impact |
GET | /v1/analytics/opportunities | List stored opportunities |
GET | /v1/analytics/opportunities/{id} | Read one opportunity |
GET | /v1/analytics/bundles | List generation records |
POST | /v1/analytics/bundles | Request deterministic bundle generation |
GET | /v1/analytics/bundles/{id} | Read pending/failed status or completed artifact |
Metric Query Scope
Metric routes require project_id. Common optional parameters include from, to,
last, granularity, service, environment, and limit.
Only opportunity and bundle list routes support organization inventory reads without
project_id. Omission returns accessible projects in the authenticated member's
organization with stable cursor pagination. Detail, generation, settings, samples, and
metrics remain project-scoped.
Public acquisition and activation flows
Flows are a project feature for your own products. Use them for main site → blog, site → auth → app, onboarding, or another ordered acquisition/activation workflow. They do not depend on DebugBundle accounts, incidents, GitHub login, or operator settings.
Create a named flow in Project → Analytics → Flows, or use the API/CLI/MCP. Each flow has 2–8 ordered steps, each with a key, name, and exact HTTPS origin (HTTP localhost is allowed). Several steps may use the same origin. All participating sites use the same flow analytics project and a public write-only project token whose origin allowlist includes those sites. They may use separate projects for debug capture. Configure separate products under their own project flows.
| Method | Path | Permission |
|---|---|---|
GET | /v1/projects/{id}/analytics/flows | Project reader |
PUT | /v1/projects/{id}/analytics/flows/{key} | Owner/admin; create or replace |
DELETE | /v1/projects/{id}/analytics/flows/{key} | Owner/admin; archive |
GET | /v1/projects/{id}/analytics/flows/{key}/report?window=30d | Project reader |
POST | /v1/analytics/flows/{id}/{key}/{start,step,handoff,arrive,withdraw} | Project token and allowed Origin |
Example definition (PUT body; path key must match):
{
"flow_key": "onboarding",
"display_name": "Site to signed-in app",
"kind": "acquisition",
"timeout_minutes": 60,
"steps": [
{"step_key":"visit","display_name":"Site visit","origin":"https://www.example.com"},
{"step_key":"auth","display_name":"Auth page","origin":"https://auth.example.com"},
{"step_key":"login","display_name":"Login completed","origin":"https://auth.example.com"},
{"step_key":"app","display_name":"App opened","origin":"https://app.example.com"}
]
}Keys use lowercase letters, numbers, dots, underscores and hyphens, starting with a letter (maximum 64 characters). Names are at most 120 characters. Expiry is 10–1440 minutes, default 60. Active definition limits follow the project's saved-funnel tier scale, with at most 100 retained definitions per project. Identical saves are idempotent; edits or reactivation start a new version. Reports use only the current version.
Browser SDK integration
The public createAnalyticsFlowClient helper is available in Browser SDK 3.1.0 and later.
Enable project analytics first. This separate helper uses direct API transport with a
public project token; it does not inherit another SDK instance's consent or relay.
import { createAnalyticsFlowClient } from '@debugbundle/sdk-browser';
const flow = createAnalyticsFlowClient({
endpoint: 'https://api.debugbundle.com',
projectId: '<flow-project-uuid>',
projectToken: 'dbundle_proj_...',
flowKey: 'onboarding',
enabled: true,
consentRequired: true
});
// Apply your integration's current capture policy programmatically.
flow.setConsent(captureAllowed);The helper supplies no checkbox, popup, or banner. enabled defaults to false and
consentRequired defaults to true. If the integration sets consentRequired: false,
it may start automatically; a server project setting that requires consent still
rejects requests without setConsent(true). Connect policy changes to this helper
as well as your regular analytics client. setConsent(false) immediately stops queued
work, aborts active requests, clears local continuity, and attempts server withdrawal.
await flow.withdraw() performs the same cleanup. Previously accepted aggregate
observations remain. Network failure can delay physical server cleanup until expiry.
On the main site:
await flow.start('visit', { source: 'newsletter', campaign: 'launch' });
const linkedUrl = await flow.handoff('auth', 'https://auth.example.com/login');
// Navigate only when your application would normally navigate; retain a fallback.
window.location.assign(linkedUrl ?? 'https://auth.example.com/login');On the dedicated auth origin, initialize the same project/flow client and apply the current capture policy, then:
const linked = await flow.arrive();
if (!linked) await flow.start('auth'); // explicitly unlinked, never a linked conversion
// Your normal OAuth flow may now leave this origin and return to it.
// Mark the next step only after your application confirms authentication succeeded.
if (loginSucceeded) {
await flow.step('login');
const linkedUrl = await flow.handoff('app', 'https://app.example.com/welcome');
window.location.assign(linkedUrl ?? 'https://app.example.com/welcome');
}On the app origin, call arrive() after applying the current capture policy; use
start('app') if you want to count a missing link as an unlinked app observation.
For a main-site → blog flow, define only those two steps and use exactly the same
start → handoff → arrive sequence. For same-origin custom steps, call step(key)
after the relevant action succeeds. The API accepts explicit observations; it does
not independently verify business outcomes or infer login success from redirects.
Continuity uses expiring sessionStorage, scoped to the tab, project and flow.
It is not a cross-site localStorage identity. Auth context can survive a same-tab
external OAuth round trip back to the auth origin. The helper does not change OAuth
state or send a handoff to the identity provider. Different tabs/devices are not
stitched automatically. If an intermediary is uninstrumented, your integration must
preserve the final destination's decorated URL inside its own validated return URL;
do not forward analytics tokens as arbitrary provider parameters.
The handoff uses a dbflow fragment parameter, removed from browser history by
arrive() before transmission. Existing query parameters and other fragment segments
are preserved. Hash routers must arrange for arrival processing before consuming this
parameter. Tokens are random, hashed at rest, bound to the next configured origin and
step, and redeemable once within ten minutes or the flow expiry. The receiver context
rotates. Same-receiver retries are idempotent; another receiver cannot replay it.
There is one outstanding handoff per next step; requesting another replaces it.
Blocked tab storage fails closed. Delivery is best effort with a bounded timeout,
32 pending operations, a 4 KiB response limit, and no persistent event queue. Helpers return false/null
on failure and never make application navigation or authentication depend on success.
Call start() again only after the current context expires or is withdrawn; an active
context represents one run. Keep source/campaign labels categorical, at most 100
characters from letters, numbers, ., _, ~, +, -; never pass personal data.
An omitted source is unknown; campaign defaults to an empty string. Unknown attribution fields and values rejected by the existing telemetry privacy policy (including DebugBundle credentials and recognized card numbers) are rejected before capture.
Direct capture API
Send JSON, Authorization: Bearer dbundle_proj_..., and the configured Origin.
Browser calls omit credentials. Context and token values are independently generated
32-byte random values encoded as 43-character unpadded base64url strings.
| Operation | JSON body (all also accept optional boolean consent) | Success body |
|---|---|---|
start | context, step_key, optional source, campaign | expires_at |
step | context, step_key | recorded: true |
handoff | context, step_key, token | next origin, expires_at |
arrive | new receiver context, token | run expires_at |
withdraw | current context | withdrawn: true |
Unknown fields are rejected. Project-token origin restrictions and the flow step origin
both apply. Withdrawal remains available when analytics is disabled. Replays,
out-of-order steps and expired contexts return 409; wrong origins/settings/consent
return 403; invalid project credentials return 401; malformed input returns 400.
Start claims one analytics session and event; each other capture operation except
withdrawal claims an event. Stable retries reuse quota claims. Rate/allowance exhaustion
returns 429. Existing debug ingestion is independent.
HTTP callers can use the same contract, including backend code that deliberately supplies the configured Origin and context. Backend SDKs do not yet include a flow helper. A browser observation must not be described as a server-verified conversion.
Reading reports
window=7d|30d|90d (default 30d) uses full UTC days and an equal previous period.
Counts are grouped by the start date of the run. A later step completed after midnight
still belongs to that starting cohort. Results include linked starts/completions,
per-step reached/previous/drop-off/unlinked counts, average seconds from the previous
step, and at most 50 source/campaign pairs with a truncation flag. A run starting at a
later step is unlinked for its entire lifetime and excluded from linked conversions.
Missing observation is unknown, not proof that an action did not occur. Today's starts
appear after the UTC day closes; recent cohorts may still complete until expiry.
Reports read aggregate counters, not raw events or individual journeys. Operational state expires within 24 hours; rollups follow project aggregate retention. Bounded worker cleanup continues while progress remains. Project deletion cascades. No global visitor identity, account identifiers, emails, raw URLs or form content is stored by this feature.
Update Settings
curl -X PATCH https://api.debugbundle.com/v1/projects/<id>/analytics-settings \
-H "Authorization: Bearer dbundle_mem_..." \
-H "Content-Type: application/json" \
-d '{
"enabled": true,
"privacy_mode": "strict",
"consent_required": true,
"journey_sample_rate": 0.1,
"raw_retention_days": 7,
"sample_retention_days": 30,
"aggregate_retention_months": 24
}'The response includes access_mode (manage or preview), analytics_available, and the
effective settings. Controlled custom dimensions cannot exceed the fixed project/tier cap:
1 on Free, 3 on Solo, 8 on Team, or 20 on self-host.
Browser Session mutations use the session CSRF token. Bearer member-token calls do not use browser CSRF headers.
Create A Saved Funnel
curl -X POST https://api.debugbundle.com/v1/projects/<id>/analytics/saved-funnels \
-H "Authorization: Bearer dbundle_mem_..." \
-H "Content-Type: application/json" \
-d '{
"funnel_key": "signup",
"display_name": "Signup",
"steps": [
{"step_key": "landing", "display_name": "Landing"},
{"step_key": "complete", "display_name": "Complete"}
]
}'Keys start with a letter and use letters, numbers, dots, colons, underscores, or hyphens.
Definitions require 2-20 unique ordered steps. The API returns 409 when the key is active
or the active-definition limit is reached.
Generate An AnalyticsBundle
curl -X POST https://api.debugbundle.com/v1/analytics/bundles \
-H "Authorization: Bearer dbundle_mem_..." \
-H "Content-Type: application/json" \
-d '{
"project_id": "<id>",
"analysis_kind": "funnel_dropoff",
"last": "30d",
"funnel": "signup",
"filters": {"service": "web", "environment": "production"}
}'Generation is asynchronous and idempotently reserved from a deterministic input
fingerprint. The response is either a completed artifact or explicit pending/failed state.
The additive X-DebugBundle-Generation-Id response header identifies the
generation record when available.
Error Semantics
| Status | Example error | Meaning |
|---|---|---|
400 | invalid_payload | Body or query failed schema validation. |
401 | invalid_member_token | Authentication failed. |
403 | forbidden | The member lacks management access. |
403 | upgrade_required | Hosted tier does not include the capability. |
404 | analytics_metrics_not_available | Scope has no readable analytics result. |
409 | analytics_saved_funnel_limit_reached | Active saved-funnel cap was reached. |
429 | analytics_quota_exceeded | Analytics-specific allowance was exhausted; inspect Retry-After. |
Analytics quota errors do not consume or reject otherwise-valid debug events in a mixed ingestion batch unless the shared request-level ingestion limit is exceeded.
Next Steps
- Generated API reference - OpenAPI-derived schemas.
- AnalyticsBundle CLI - Human and agent command workflows.
- Privacy and retention - Data boundaries.