Analytics Overview

Dub Analytics is the reporting layer that helps teams understand how people interact with their short links, campaigns, and attribution workflows. In product terms, analytics turns raw click and conversion activity into dimensions such as time, geography, device, referrer, and top-performing links. In repository terms, the analytics surface is split between an API contract, dashboard components, utility exports for manipulating and exporting analytics data, and a Tinybird-backed analytics infrastructure package. This page orients developers around those pieces so they can reason about where metrics are requested, displayed, transformed, and stored.

Sources: apps/web/lib/openapi/analytics/index.ts, apps/web/lib/analytics/utils/index.ts, apps/web/ui/analytics/index.tsx, packages/tinybird/README.md

The public docs describe Dub Analytics as a high-volume analytics product for understanding audience behavior, and the code reflects that by treating analytics as both a first-class API family and a reusable UI module. The API endpoint is not limited to one link page: its summary explicitly says it can retrieve analytics for a link, a domain, or the authenticated workspace. The UI component also appears in several contexts, including workspace analytics, public stats pages, and partner program analytics. That reuse is important: contributors should avoid thinking of analytics as a single dashboard route and instead treat it as a shared reporting capability.

Sources: apps/web/lib/openapi/analytics/index.ts, apps/web/ui/analytics/index.tsx

Purpose and Scope

This page covers the source-backed shape of Dub’s analytics system: the /analytics OpenAPI path, the dashboard composition around charts and metric sections, the exported utility areas used by analytics workflows, and the Tinybird package layout that represents the analytics data backend. It is meant for developers who need to extend analytics dimensions, debug dashboard/API mismatches, or understand how a new metric category should flow from storage to API to UI. It does not document every route that may render the analytics component, because the selected source focuses on the shared component and API contract rather than page-level routing.

Sources: apps/web/lib/openapi/analytics/index.ts, apps/web/ui/analytics/index.tsx

The central concept is an analytics query. In the OpenAPI module, the retrieveAnalytics operation accepts analyticsQuerySchema as its query parameter schema. The endpoint description says the response type depends on the event and type query parameters, which means callers select both the event family being analyzed and the aggregation shape they want back. The response is modeled as a union of possible analytics payloads rather than a single fixed object, so client code must be prepared for count responses, timeseries arrays, and dimension-specific arrays.

Sources: apps/web/lib/openapi/analytics/index.ts

Relevant Source Files

  • apps/web/lib/openapi/analytics/index.ts defines the OpenAPI operation for GET /analytics, including the operation id, summary, query schema, response union, Analytics tag, and token security requirement.
  • apps/web/lib/analytics/utils/index.ts re-exports analytics helper modules for CSV conversion, query-string editing, export formatting, interval data, and plan-aware date-range validation.
  • apps/web/ui/analytics/index.tsx composes the reusable client-side analytics dashboard with provider state, toggle controls, chart rendering, and metric sections for links, referrers/UTMs, location, and devices.
  • packages/tinybird/README.md documents the Tinybird analytics package layout, including click-event datasources, link metadata datasources, endpoint pipes, and ingestion/transformation pipes.

System-to-Code Mapping

At the API boundary, analytics is represented by the exported analyticsPath object, which mounts retrieveAnalytics at GET /analytics. The operation uses operationId: "retrieveAnalytics" and a Speakeasy name override of retrieve, giving generated SDKs and API documentation a stable operation name. The endpoint is tagged as Analytics and protected by token security, so it belongs to the authenticated API surface rather than an unauthenticated public data feed. Standard OpenAPI error responses are merged into the operation, keeping analytics behavior consistent with the rest of the API reference.

Sources: apps/web/lib/openapi/analytics/index.ts

The response mapping is intentionally broad because analytics reports can be aggregated in different ways. A count request returns analyticsResponse.count, while timeseries requests return arrays of analyticsResponse.timeseries. Geographic data is represented through continent, country, region, and city response schemas. Device analytics uses device, browser, operating system, and trigger response schemas. Acquisition and link-performance views are represented by referrers, referrer URLs, top links, and top URLs. This source-level union is the best quick reference for the families of data the analytics API promises to return.

Sources: apps/web/lib/openapi/analytics/index.ts

On the frontend, the default Analytics component wraps the dashboard in AnalyticsProvider, consumes AnalyticsContext, renders AnalyticsToggle, and then places ChartSection above StatsGrid. The comment at the top of the file is especially useful because it names three runtime placements: workspace analytics at an app workspace path, public stats pages under a share path, and partner program analytics under a partners domain. That comment explains why the component accepts adminPage and optional dashboardProps rather than hard-coding assumptions about one dashboard context.

Sources: apps/web/ui/analytics/index.tsx

API Components

The compact API contract is: GET /analytics retrieves analytics for a link, a domain, or the authenticated workspace. Query parameters are validated by analyticsQuerySchema; the code does not inline those fields here, but it clearly identifies the schema as the source of truth for request parameters. The response has HTTP 200 content type application/json and can be a count object or one of several arrays, depending on the selected analytics event and type. Authentication is represented by security: [{ token: [] }], so API consumers should include the same token-based auth used by other protected endpoints.

Sources: apps/web/lib/openapi/analytics/index.ts

API elementSource-level nameBehavior
Path/analyticsMounted as the analytics retrieval endpoint.
MethodgetExecutes the retrieveAnalytics operation.
Operation idretrieveAnalyticsStable OpenAPI operation identifier.
SDK name overrideretrieveSpeakeasy override for generated naming.
Query schemaanalyticsQuerySchemaDefines accepted analytics query parameters.
Response schemaanalyticsResponse.* unionSelects count, timeseries, location, device, referrer, or link-performance shapes.
SecuritytokenRequires authenticated API access.

The analytics response families also correspond to the UI sections visible in StatsGrid. TopLinks aligns with top-link reporting, ReferrersUTMs aligns with acquisition dimensions, LocationSection aligns with geographic dimensions, and DeviceSection aligns with device-related dimensions. ChartSection sits above those cards and is the natural home for time-based reporting, while AnalyticsToggle lets the user switch analytics modes. The UI file does not expose network calls directly, but it shows the component structure that consumes analytics state from the provider and renders the report areas users recognize from the dashboard.

Sources: apps/web/ui/analytics/index.tsx

Dashboard Behavior and Plan Gating

The dashboard composition has one important access-control-like behavior at the component level: StatsGrid may hide detailed sections for certain combinations of selected tab, view, and workspace plan. It reads dashboardProps, selectedTab, and view from AnalyticsContext, and reads plan from useWorkspace. If the selected tab is leads or sales, or the view is funnel, and the plan is free or pro, the stats grid returns null. This means some advanced conversion or funnel analytics views can intentionally omit the lower metric grid for lower-tier plans.

Sources: apps/web/ui/analytics/index.tsx

The same component also adapts for embedded or scoped dashboards. When dashboardProps?.key is present, TopLinks is not rendered, which prevents a dashboard scoped to a specific key from redundantly showing a top-links section. The outer layout changes background and top padding when dashboardProps is present, and it applies legacy page-content padding rules when neither dashboardProps nor adminPage are set. These details matter when adding new cards: contributors should preserve the provider-driven layout and avoid introducing assumptions that only work on the main workspace analytics page.

Sources: apps/web/ui/analytics/index.tsx

Data Pipeline and Tinybird Layout

The Tinybird package README shows the analytics data backend organized around datasources, endpoints, and pipes. Datasources include dub_click_events.datasource, a materialized click-event datasource, dub_links_metadata.datasource, and a latest-link-metadata datasource. That split suggests the pipeline stores event facts separately from link metadata, then exposes queryable views that can combine them for reporting. The endpoint list maps closely to analytics API and dashboard dimensions: browser, city, clicks, country, device, operating system, referer, timeseries, top links, and top URLs.

Sources: packages/tinybird/README.md

Tinybird pipes are listed for click events and link metadata: dub_click_events_pipe.pipe and dub_links_metadata_pipe.pipe. In practice, developers should treat the Tinybird package as the infrastructure layer that makes high-cardinality analytics queries possible, while the web app modules provide the user-facing API and dashboard structure. If a new analytics dimension is added, it likely needs coordinated work across these layers: a Tinybird endpoint or query shape, a response schema in the web app, an OpenAPI union entry if it becomes public, and a frontend card or chart if it is displayed.

Sources: apps/web/lib/openapi/analytics/index.ts, apps/web/ui/analytics/index.tsx, packages/tinybird/README.md

Analytics Utilities and Export Workflows

The analytics utility barrel exports five helper areas: convert-to-csv, edit-query-string, format-analytics-export, get-interval-data, and valid-date-range-for-plan. Even without the implementation bodies, these names describe the recurring tasks around analytics workflows. Query-string editing supports shareable or navigable dashboard filters. Interval data supports chart bucketing and date ranges. Plan-aware date validation keeps analytics queries aligned with workspace entitlements. CSV conversion and export formatting support the product workflow described in the docs, where users download analytics data for business intelligence tools, spreadsheets, or team sharing.

Sources: apps/web/lib/analytics/utils/index.ts

These utilities are important because analytics is not just a visual dashboard. A user can inspect charts interactively, retrieve analytics through the API, and export the same families of data for external analysis. The official export flow describes downloading a zip containing CSV files for analytics types that users already know from the dashboard, and the repository exposes CSV and export-formatting utilities that fit that reader-facing workflow. When extending analytics, contributors should ask whether the new dimension needs export support in addition to API and UI support.

Sources: apps/web/lib/analytics/utils/index.ts, apps/web/ui/analytics/index.tsx

Implementation Details and Extension Guidance

When adding or changing analytics behavior, start by identifying which layer owns the change. A purely visual change belongs in the analytics UI composition or one of its imported sections. A new public aggregation type belongs in the API response contract and should appear in the OpenAPI response union. A new data dimension backed by event storage likely requires Tinybird endpoint work before the web app can reliably expose it. A workflow change such as CSV export, date-range validation, or query-string persistence belongs near the analytics utility exports and the provider-driven dashboard flow.

Sources: apps/web/lib/openapi/analytics/index.ts, apps/web/lib/analytics/utils/index.ts, apps/web/ui/analytics/index.tsx, packages/tinybird/README.md

Also be careful with geography. The product docs note that proxying a custom domain through a service such as Cloudflare can make country or city analytics appear incorrect, because click traffic reaches Dub through the proxy rather than directly from the visitor. The source-backed location dimensions are real API and dashboard concepts, but their accuracy depends on request origin data. If you are debugging city or country reports, inspect the deployment and DNS/proxy path as well as the analytics code, because the wrong public IP can contaminate otherwise correct aggregation logic.

Sources: apps/web/lib/openapi/analytics/index.ts, apps/web/ui/analytics/index.tsx

Next Steps

For API consumers, continue with the Analytics API reference to see the retrieval endpoint as a formal contract. For dashboard contributors, inspect the analytics provider and section components that are imported by apps/web/ui/analytics/index.tsx. For infrastructure work, continue with the Tinybird analytics page and the endpoint pipes listed in packages/tinybird/README.md. For product workflows, pair this overview with export and conversion-tracking documentation so you can understand how click analytics, link attribution, and downstream conversion events fit together.