Analytics Vllnt
Generic, configurable analytics component for Bijection — any event, any dimension, any domain; rollup-on-write with funnels, retention, uniques
git clone https://github.com/bijectionhq/analytics-vllnt.git
cd analytics-vllnt
git checkout d545d7c7238f2318b5d163cea8709645b90a6ef1
cd packages/convex-analyticsBijection repository access is required. Request access.
Description
Generic, configurable analytics component for Bijection — any event, any dimension, any domain; rollup-on-write with funnels, retention, uniques
Explore the package README for API concepts, configuration, and examples. Check the Bijection source for adaptation-specific setup.
Review the source and its dependencies before adopting this package. Source availability does not establish npm publication or runtime qualification.
Getting started
- Get the source at the revision above and read its package documentation.
- Check the required Bijection SDK version, dependencies, and external service credentials.
- Follow the package setup instructions and the guide to using components.
- Exercise the component in your deployment according to your project’s verification rules.
Open source
Maintained source: bijectionhq/analytics-vllnt. Based on vllnt/convex-analytics. License: MIT. Consult the repository for license terms, notices, and contributor attribution.
From the upstream publisher
Generic, configurable analytics component for Convex — any event, any dimension, any domain; rollup-on-write with funnels, retention, uniques
Explore the demo ↗Upstream overview
From the upstream package documentation.
@vllnt/convex-analytics stores events and exposes analytical queries inside your Convex backend. Event names, subject references, properties, and dimensions are supplied by your application rather than imposed by a web-only schema.
Track typed event properties and choose the dimensions to aggregate. Query metrics, breakdowns, timeseries, funnels, retention, or raw events. Rollups support aggregate reads; an optional web preset adds web-specific helpers and an optional React entry supports reactive displays.
The host defines event meaning, identity, consent, and access rules. Sampling, retention, and selected dimensions affect interpretation and coverage. This component does not automatically instrument every client or establish causation from a funnel; validate the events your product sends.
Maintained by bntvllnt at VLLNT. Find the author on GitHub and X.
Use cases
From the upstream package documentation.
- SaaS onboarding: follow the steps between signup and first useful action.
- Mobile products: compare activity and return behavior across features.
- Games and learning: analyze session events, completion steps, and repeat usage.
- AI applications: measure feature adoption or host-reported task outcomes by model or workflow dimension.
How it works
From the upstream package documentation.
Track typed event properties and choose the dimensions to aggregate. Query metrics, breakdowns, timeseries, funnels, retention, or raw events. Rollups support aggregate reads; an optional web preset adds web-specific helpers and an optional React entry supports reactive displays.
The host defines event meaning, identity, consent, and access rules. Sampling, retention, and selected dimensions affect interpretation and coverage. This component does not automatically instrument every client or establish causation from a funnel; validate the events your product sends.
Upstream package FAQ
How does @vllnt/convex-analytics keep aggregate reads fast as event volume grows?
@vllnt/convex-analytics uses a rollup-on-write strategy: every call to analytics.track() immediately increments counters per dimension value and time bucket, backed by @convex-dev/aggregate and @convex-dev/sharded-counter. The metric(), top(), and timeseries() queries read those pre-aggregated counters, so their cost is O(1) regardless of how many raw events have been ingested.
What analytics queries does @vllnt/convex-analytics support?
@vllnt/convex-analytics provides metric (total count over a range), top (dimension breakdowns), timeseries (bucketed counts), uniques (DAU/WAU/MAU), funnel (ordered step conversion by subjectRef), retention (cohort return rates), distribution (histogram of a numeric measure), and list (paginated raw events). metric, top, and timeseries read pre-aggregated rollups kept forever; funnel, retention, and distribution read TTL-pruned raw events via indexes.
Can I use @vllnt/convex-analytics for non-web use cases like mobile or backend product events?
The core of @vllnt/convex-analytics is domain-neutral and has no hardcoded web fields. You declare your own prop keys as dimensions, pass an optional propsValidator to type them at the boundary, and the component rolls up on whatever keys you specify. Web-specific dimensions and helpers are isolated in the opt-in @vllnt/convex-analytics/web preset.
How does @vllnt/convex-analytics handle auth and multi-tenancy?
@vllnt/convex-analytics is auth-agnostic: the host application gates access and passes opaque subjectRef and sessionRef values into track(). Tables are sandboxed so the host reaches them only through exported functions. Multi-tenancy is handled with the scope config option, which partitions one tenant's data from another without any additional schema work.
What happens to raw events over time and can rollup data be lost?
Raw events are pruned after a configurable retentionDays period (default 90 days), enforced by a cron configured via analytics.configure(). Rollup counters for metric(), top(), and timeseries() are kept indefinitely and are not affected by raw event pruning. Queries like funnel() and retention() that rely on raw events are bounded by the retention window.
Use with agents and CLI
Give your coding agent the component’s source identity and setup guidance.
Help me integrate Analytics Vllnt with Bijection.
Read: https://bijection.com/components/analytics-vllnt/SKILL.md
Check SDK compatibility and dependency availability.
Follow this project's execution and verification rules.Upstream README.md
View repository ↗Documentation from vllnt/convex-analytics, recorded October 23, 2026. APIs and setup may differ in the Bijection adaptation.
@vllnt/convex-analytics
A generic, configurable, embedded analytics component for Convex — any event, any dimension, any domain — with rollup-on-write so reads stay O(1).
import { AnalyticsClient } from "@vllnt/convex-analytics";
import { components } from "./_generated/api";
const analytics = new AnalyticsClient(components.analytics, {
dimensions: ["plan", "country"], // prop keys to roll up on
});
await analytics.track(ctx, "signup", { subjectRef: userId, props: { plan: "pro", country: "FR" } });
const byPlan = await analytics.top(ctx, "signup", "plan"); // [{ value: "pro", count: 1 }]
Features
- Generic events — free-string event name, opaque
subjectRef/sessionRef, host-typedprops. - Host-declared dimensions — you pass the prop keys to roll up on; nothing is hardcoded.
- Rollup-on-write — counts are incremented as events land, so
metric/top/timeseriesread in O(1) (backed by@convex-dev/aggregate+@convex-dev/sharded-counter). - Rich verb set —
metric,top,timeseries,uniques,funnel,retention,distribution, plus paginated rawlist. - Configurable —
scope,dimensions,granularities,retentionDays,sampleRate,propsValidator; sensible defaults, zero config required. - Per-session rate limiting + dedupe + sampling built into
track. - Opt-in web preset —
@vllnt/convex-analytics/webadds web dimensions + UA/geo helpers when you want them. - Optional React hooks —
@vllnt/convex-analytics/reactfor reactive aggregate reads. - Zero hardcoded domain — no
v.any(), no baked-in web fields; the host owns meaning and auth.
Generic core vs web preset
The core is domain-neutral: it knows nothing about web, mobile, or any vertical.
Web analytics — pageview dimensions (path, referrer, device, browser, os,
country, UTM) plus parseUserAgent / geoFromHeaders / trackPageview helpers —
lives in the opt-in @vllnt/convex-analytics/web preset. You turn it on by passing
webDimensions to the client's dimensions config; otherwise the core ships no web
fields. See docs/web-preset.md.
Installation
npm install @vllnt/convex-analytics
Usage
// convex/convex.config.ts
import { defineApp } from "convex/server";
import analytics from "@vllnt/convex-analytics/convex.config";
const app = defineApp();
app.use(analytics);
export default app;
// convex/analytics.ts — track + read, server-side
import { AnalyticsClient } from "@vllnt/convex-analytics";
import { components } from "./_generated/api";
type MyProps = { plan?: string; country?: string };
const analytics = new AnalyticsClient<MyProps>(components.analytics, {
dimensions: ["plan", "country"],
granularities: ["day"],
});
await analytics.track(ctx, "signup", { subjectRef: userId, props: { plan: "pro" } });
const total = await analytics.metric(ctx, "signup");
Config
Passed to the AnalyticsClient constructor. All optional — the defaults work with zero config.
| Option | Type | Default | Purpose |
|---|---|---|---|
scope | string | "default" | Multi-tenant partition; isolates one tenant's data. |
dimensions | string[] | [] | Prop keys to roll up on (drives rollup-on-write). Empty = count by event name only. |
granularities | ("minute" | "hour" | "day")[] | ["day"] | Rollup bucket sizes (minute for short live windows). |
retentionDays | number | 90 | Raw-event TTL in days (rollups are kept forever). Applied via configure. |
sampleRate | number | 1 | Fraction 0..1 of events to keep at ingest. |
sessionIdleMs | number | 1800000 | Idle timeout before a session is closed. Applied via configure. |
propsValidator | Convex validator | typed scalar record | Optional host validator narrowing props at the boundary. |
scope, dimensions, granularities, and sampleRate apply per call from the client.
retentionDays, sampleRate, and sessionIdleMs are persisted for the prune/close-sessions
crons by calling analytics.configure(ctx, { ... }) once.
API
| Verb | Kind | Purpose |
|---|---|---|
track(ctx, name, opts) | mutation | Ingest an event; rollup-on-write + raw event + counter. Returns "tracked" | "dropped" | "duplicate". |
metric(ctx, name, opts) | query | Total count over a range, optionally filtered by a dimension value. |
top(ctx, name, dimension, opts) | query | Top values of a dimension (breakdown). |
timeseries(ctx, name, opts) | query | Bucketed counts over a range. |
uniques(ctx, opts) | query | DAU / WAU / MAU from subjects. |
funnel(ctx, steps, opts) | query | Ordered step conversion, keyed by subjectRef. |
retention(ctx, opts) | query | Cohort return rates by first-seen period. |
distribution(ctx, name, measure, opts) | query | Histogram of a numeric measure over declared buckets + overflow (with count / sum). |
list(ctx, name, paginationOpts, opts) | query | Paginated raw events, newest first. |
configure(ctx, opts) | mutation | Persist cron-relevant config (retention / sampling / idle). |
Full reference: docs/client-sdk.md. REST surface: docs/api-reference.md.
What it serves
The Convex-native, authoritative in-app aggregate layer — predefined-dimension rollups served
reactively in O(1). It complements a product-analytics warehouse; it doesn't replace one.
Declare the dimensions and measures you'll query and the rollups answer instantly; ad-hoc or
retroactive questions over non-declared dimensions, or beyond the raw-event retention window,
are an export concern. metric / top / timeseries read pre-aggregated rollups (kept forever);
funnel / retention / distribution read raw events in range (index-backed, bounded, TTL-pruned).
Web preset
import { AnalyticsClient } from "@vllnt/convex-analytics";
import { webDimensions, trackPageview } from "@vllnt/convex-analytics/web";
const analytics = new AnalyticsClient(components.analytics, { dimensions: webDimensions });
await trackPageview(analytics, ctx, {
path: "/pricing",
ua: request.headers.get("user-agent") ?? undefined,
headers: request.headers,
});
webDimensions opts the rollups into path / referrer / device / browser / os /
country / UTM; parseUserAgent and geoFromHeaders build those props from a request.
See docs/web-preset.md.
React
import { useMetric, useTop } from "@vllnt/convex-analytics/react";
import { api } from "../convex/_generated/api";
const signups = useMetric(api.analytics.metric, { name: "signup" });
const byPlan = useTop(api.analytics.top, { name: "signup", dimension: "plan" });
Thin reactive wrappers over the host's re-exported query refs (metric, top, timeseries,
uniques). react + convex are optional peer deps; backend-only consumers pull no React.
MCP (Claude Code)
claude mcp add convex-analytics-mcp \
--env CONVEX_URL=https://your-deployment.convex.cloud \
--env ANALYTICS_API_KEY=your-key
7 tools: track, get_metric, get_top, get_timeseries, get_uniques, detect_anomalies,
query_analytics (NL router). See docs/mcp-tools.md.
Security
- Auth-agnostic mount — the host gates access and passes opaque
subjectRef/sessionRefin. - Tables are sandboxed; the host reaches them only through the exported functions.
- REST endpoints require an
x-api-keyheader, compared timing-safe.
See docs/architecture.md.
Testing
pnpm test
import analyticsTest from "@vllnt/convex-analytics/test";
import { convexTest } from "convex-test";
const t = convexTest(hostSchema, hostModules);
analyticsTest.register(t);
Documentation
Schema · Client SDK · REST API ·
Web Preset · Multi-Product ·
Architecture · MCP Tools. For AI agents:
llms.txt · llms-full.txt.
Contributing
See CONTRIBUTING.md.
Author
Built by bntvllnt · bntvllnt.com · X @bntvllnt
Part of the @vllnt Convex component fleet — vllnt.com
If this is useful, sponsor the work.
License
MIT — see LICENSE.