Getting Started
Core Architecture
Link Engine
Analytics & Attribution
Partners & Affiliates
Third-Party Integrations
Identity & Security
Automation & Messaging
Developer Tools
The following files were used as context for generating this wiki page:
The analytics and querying system in Dub provides comprehensive traffic, conversion, and revenue tracking across workspace short links, shared public dashboards, partner program portals, and administrative consoles. It addresses the complexity of multi-dimensional event monitoring by combining robust backend REST endpoints with Zod parameter validation, workspace authorization checks, and plan-based date range restrictions.
Sources: apps/web/app/api/analytics/route.ts:1-139, apps/web/app/api/analytics/dashboard/route.ts:1-223
Design decisions prioritize client-side query string synchronization, context-based filter management via SWR data-fetching hooks, and modular visual components ranging from interactive timeseries area charts and conversion funnels to geographic bar lists and device breakdown cards.
Sources: apps/web/app/app.dub.co/dashboard/slug/ee/program/analytics/program-analytics-shell.tsx:1-40, apps/web/ui/analytics/analytics-provider.tsx:1-313, apps/web/ui/analytics/location-section.tsx:1-176
By integrating specialized enterprise partner program queries, commission tracking, and application funnels directly alongside standard link analytics, the system offers a unified architecture for monitoring digital performance and monetization metrics.
Sources: apps/web/app/app.dub.co/dashboard/slug/ee/program/analytics/applications/applications-funnel-chart.tsx:1-212, apps/web/app/ee/admin.dub.co/dashboard/commissions/page.tsx:1-228
The analytics system exposes public and internal REST API endpoints designed to ingest query parameters, validate inputs via Zod schemas, enforce workspace-level permissions, and check plan-based date restrictions. Query parameters are parsed and validated using schemas defined in apps/web/lib/zod/schemas/analytics, while administrative endpoints enforce role-based access control and invoice filtering.
Sources: apps/web/app/api/analytics/dashboard/route.ts:1-223, apps/web/app/api/analytics/route.ts:1-139, apps/web/app/ee/api/admin/payouts/route.ts:1-123
The internal analytics route (/api/analytics) executes a strict sequence of validation and authorization checks wrapped by the withWorkspace middleware with required permission analytics.read.
throwIfClicksUsageExceeded(workspace) — Verifies that the workspace has not exceeded its click usage limits.analyticsPathParamsSchema.parse(params) — Parses path parameters to extract event and endpoint types, supporting legacy routes.parseAnalyticsQuery(searchParams) — Parses URL search parameters into structured query filters.getDefaultProgramIdOrThrow(workspace) and getProgramOrThrow(...) — Validates program IDs when a partner program filter is applied.verifyFolderAccess(...) — Ensures the requesting user possesses folders.read permissions for the target folder.assertValidDateRangeForPlan(...) — Restricts queried date intervals according to the workspace plan tier.Warning
Requests referencing invalid program IDs or exceeding workspace click thresholds trigger a DubApiError with status code forbidden or bad_request, halting execution before query generation.
The public dashboard endpoint (/api/analytics/dashboard) allows unauthenticated or password-protected viewing of link and folder metrics without requiring workspace membership.
folderId or a combination of domain and key, checking demo links (DUB_DEMO_LINKS) and database entries.assertDashboardPassword verifies cookies matching dub_password_${dashboard.id} against stored dashboard passwords.analyticsDashboardCache:${JSON.stringify(parsedParams)}). Background writes use Vercel's waitUntil.Sources: apps/web/app/api/analytics/dashboard/route.ts:44-197, apps/web/app/api/analytics/dashboard/route.ts:204-222
The enterprise admin payouts route (/api/admin/payouts) is protected by withAdmin and validates queries using adminPayoutsQuerySchema.
Note
When programId is omitted, the admin payouts query automatically excludes internal test constants (ACME_PROGRAM_ID, DEMO_PROGRAM_ID) and staging slugs ending with -staging.
State management and client-side querying across Dub analytics dashboards rely on specialized React hooks, context providers, URL search parameter synchronization, and SWR caching wrappers. These utilities coordinate view selections, filter states for dimensions such as partners, countries, and referral sources, and asynchronous timeseries data fetching.
Sources: apps/web/app/app.dub.co/dashboard/slug/ee/program/analytics/applications/use-applications-analytics-filters.tsx:22-235, apps/web/ui/analytics/analytics-provider.tsx:22-235
The AnalyticsProvider component initializes dashboard state by reading URL search parameters and persisting user preferences via local storage hooks. It supplies configuration context down the component tree through AnalyticsContext.
Sources: apps/web/ui/analytics/analytics-provider.tsx:56-100, apps/web/ui/analytics/analytics-provider.tsx:128-156
export default function AnalyticsProvider({
adminPage,
dashboardProps,
children,
}: PropsWithChildren<{
adminPage?: boolean;
dashboardProps?: AnalyticsDashboardProps;
}>) {
const searchParams = useSearchParams();
const { slug: workspaceSlug, plan: workspacePlan, domains } = useWorkspace();
const [requiresUpgrade, setRequiresUpgrade] = useState(false);
// ... resolves base paths, query parameters, and SWR total events fetching
}Note
The provider automatically detects whether the current view is an admin console, workspace dashboard, partner profile page, or public stats page, dynamically mapping API base paths and event endpoints accordingly.
Client components synchronize filter states and view modes directly with URL search parameters using helper hooks such as useApplicationsAnalyticsQuery, useApplicationAnalyticsFilters, and useApiLogsTimeseries.
Sources: apps/web/app/app.dub.co/dashboard/slug/ee/program/analytics/applications/use-applications-analytics-query.ts:20-37, apps/web/app/app.dub.co/dashboard/slug/ee/program/analytics/applications/use-applications-analytics-filters.tsx:22-235, apps/web/lib/swr/use-api-logs-timeseries.ts:7-45
useApplicationsAnalyticsQuery: Parses applicationEvent parameters into typed application stages (started, submitted, approved, defaulting to visited) and view parameters into views (timeseries or funnel).useApplicationAnalyticsFilters: Manages multidimensional filtering across partnerId, country, and referralSource, providing callbacks to select, remove, toggle negative operators (prefixing values with -), and clear all active filters while updating the URL via queryParams.Sources: apps/web/app/app.dub.co/dashboard/slug/ee/program/analytics/applications/use-applications-analytics-query.ts:9-37, apps/web/app/app.dub.co/dashboard/slug/ee/program/analytics/applications/use-applications-analytics-filters.tsx:20-235
Data fetching relies on useSWR coupled with custom helper hooks that construct query strings and enforce deduplication intervals or keep previous data during transitions.
Sources: apps/web/lib/swr/use-partner-earnings-timeseries.ts:9-54, apps/web/lib/swr/use-api-logs-timeseries.ts:7-45
Sources: apps/web/lib/swr/use-partner-earnings-timeseries.ts:23-47, apps/web/lib/swr/use-api-logs-timeseries.ts:32-38
Warning
When enabled evaluates to false or required identifiers like partnerId or workspaceId are missing, SWR hooks return null keys to safely skip fetching until context is fully established.
Sources: apps/web/lib/swr/use-partner-earnings-timeseries.ts:23-26, apps/web/lib/swr/use-api-logs-timeseries.ts:32-33
The top-level analytics interface is unified across workspace dashboards, public stats pages, and enterprise admin consoles by wrapping child views in the Analytics component and supplying context via AnalyticsProvider.
Sources: apps/web/ui/analytics/index.tsx:4-31
The core shell mounts an AnalyticsProvider configured with optional adminPage and dashboardProps flags. Inside its consumer tree, it renders the sticky toolbar header (AnalyticsToggle) alongside a responsive grid containing the primary chart and StatsGrid.
export default function Analytics({
adminPage,
dashboardProps,
}: {
adminPage?: boolean;
dashboardProps?: AnalyticsDashboardProps;
}) {
return (
<AnalyticsProvider {...{ adminPage, dashboardProps }}>
<AnalyticsContext.Consumer>
{({ dashboardProps }) => {
return (
<div
className={cn("pb-10", dashboardProps && "bg-neutral-50 pt-10")}
>
<AnalyticsToggle />
<div
className={cn(
"mx-auto grid max-w-screen-xl gap-5 px-3 lg:px-10",
!dashboardProps && !adminPage && "lg:px-6",
)}
>
<ChartSection />
<StatsGrid />
</div>
</div>
);
}}
</AnalyticsContext.Consumer>
</AnalyticsProvider>
);
}Within StatsGrid, specific conversion tabs (leads, sales) or funnel views are conditionally hidden for workspaces on free or pro plans, preventing restricted metric rendering. Otherwise, it organizes top links, referrers, UTMs, locations, and device breakdowns into a responsive two-column grid.
Sources: apps/web/app/app.dub.co/dashboard/slug/links/analytics/page.tsx:7-17, apps/web/app/ee/admin.dub.co/dashboard/analytics/page.tsx:5-13, apps/web/ui/analytics/index.tsx:66-67
The AnalyticsToggle component manages sticky positioning rules and computes layout styling based on whether dashboardProps or adminPage are present. It integrates advanced filtering selectors (Filter.Select) and date range pickers (DateRangePicker) with preset validations tied to workspace plans.
export function AnalyticsToggle({
page = "analytics",
}: {
page?: "analytics" | "events";
}) {
const { slug, programSlug } = useParams();
const { plan, createdAt } = useWorkspace();
const { product } = useCurrentProduct();
const { queryParams, getQueryString } = useRouterStuff();
const {
domain,
key,
url,
adminPage,
partnerPage,
dashboardProps,
start,
end,
interval,
} = useContext(AnalyticsContext);
const scrolled = useScroll(120);
const { isMobile } = useMediaQuery();
...Note
Sticky positioning on AnalyticsToggle dynamically adjusts its top threshold depending on the context: top-14 when rendering dashboardProps and top-16 when rendering inside adminPage.
The chart visualization layer handles rendering for timeseries area charts, conversion funnels, event selection tabs, and tooltip formatting across workspace settings, enterprise program analytics, and general link analytics. The primary components powering this layer include ChartSection, AnalyticsTimeseriesChart, AnalyticsChart, and EventsTabs. These components coordinate with AnalyticsContext to fetch timeseries metrics from /api/analytics and switch between distinct view modes (timeseries and funnel).
Sources: apps/web/app/app.dub.co/dashboard/slug/ee/program/analytics/analytics-chart.tsx:13-33, apps/web/ui/analytics/chart-section.tsx:26-36
Event tabs let users toggle between tracking categories (clicks, leads, sales), updating URL parameters through onEventTabClick and resetting conflicting sort parameters (such as timestamp or saleAmount) when switching tabs. For sales analytics, a secondary toggle group allows users to switch between sales count (sales) and monetary amounts (saleAmount), formatting values via currencyFormatter or nFormatter.
Sources: apps/web/app/app.dub.co/dashboard/slug/ee/program/analytics/analytics-chart.tsx:92-113, apps/web/ui/analytics/events/events-tabs.tsx:52-75
The chart container evaluates the current view setting (timeseries or funnel) alongside workspace plan entitlements (free, pro, business) to determine whether to render the AnalyticsTimeseriesChart, AnalyticsAreaChart, or AnalyticsFunnelChart. When free or pro workspaces attempt to view conversion events or funnel views, a paywall overlay masks the chart component and prompts the user to upgrade.
Sources: apps/web/app/app.dub.co/dashboard/slug/ee/program/analytics/analytics-chart.tsx:85-91, apps/web/ui/analytics/chart-section.tsx:69-116
const TAB_COLOR: Record<string, string> = {
clicks: "text-blue-500",
leads: "text-violet-600",
sales: "text-teal-400",
};Sources: apps/web/app/app.dub.co/dashboard/slug/ee/program/analytics/analytics-timeseries-chart.tsx:7-11
Note
AnalyticsTimeseriesChart uses a composite React key built from start, end, interval, selectedTab, and saleUnit to force clean re-mounting when date filters or metric dimensions change.
Sources: apps/web/app/app.dub.co/dashboard/slug/ee/program/analytics/analytics-timeseries-chart.tsx:29-31
Interactive tooltips within AnalyticsTimeseriesChart pass tooltip date objects to formatDateTooltip(d.date, { interval, start, end }). The tooltip content layout renders a categorized breakdown row containing a color-coded indicator square matching the active tab (text-blue-500, text-violet-600, or text-teal-400) and the formatted metric value.
Sources: apps/web/app/app.dub.co/dashboard/slug/ee/program/analytics/analytics-timeseries-chart.tsx:40-67
The geographic, device, and partner segment breakdowns within the analytics dashboard are powered by dedicated section components (LocationSection, DeviceSection, and PartnerSegmentsSection) that render multi-tabbed cards encapsulating BarList visualizations. Each section retrieves analytics data via useAnalyticsFilterOption hooks, sorting items by count or sales value and synchronizing active filters directly to URL search parameters.
Sources: apps/web/ui/analytics/location-section.tsx:19-32, apps/web/ui/analytics/device-section.tsx:14-25, apps/web/ui/analytics/partner-segments-section.tsx:56-140
The LocationSection manages four discrete tabs (countries, cities, regions, continents), mapping each tab identifier to its corresponding singular endpoint name using SINGULAR_ANALYTICS_ENDPOINTS. When rendering rows, it resolves country flags, continent display icons, and region labels—handling region codes ending in -Unknown by falling back to country names. Similarly, the DeviceSection provides tabs for devices, browsers, os, and triggers, utilizing DeviceIcon and TRIGGER_DISPLAY mappings to render icons and titles.
Sources: apps/web/ui/analytics/location-section.tsx:1-119, apps/web/ui/analytics/device-section.tsx:1-102
Sources: apps/web/ui/analytics/location-section.tsx:25-79, apps/web/ui/analytics/device-section.tsx:20-71, apps/web/ui/analytics/partner-segments-section.tsx:14-54
User interactions with individual bar list items invoke toggle and apply handlers that update local selection states and modify URL query strings. The filter execution sequence follows a strict callback chain across components:
onToggleFilter(val) → updates local selectedItems array → onApplyFilterValues(values) → checks if values.length === 0 to delete the parameter via queryParams({ del: singularTabName }) or set comma-joined values via queryParams({ set: { [singularTabName]: values.join(",") } }).
Sources: apps/web/ui/analytics/location-section.tsx:41-59, apps/web/ui/analytics/device-section.tsx:33-51
Warning
Switching between category tabs within LocationSection, DeviceSection, or PartnerSegmentsSection automatically triggers an useEffect hook that clears all currently selected filter items (setSelectedItems([])), preventing stale filter identifiers from bleeding across different metric dimensions.
Sources: apps/web/ui/analytics/location-section.tsx:37-39, apps/web/ui/analytics/device-section.tsx:29-31, apps/web/ui/analytics/partner-segments-section.tsx:73-75
The PartnerSegmentsSection supports hierarchical grouping through two primary tabs (segments and links) and four nested subtabs (groups, tags, short_links, destination_urls). It resolves group color circles via GroupColorCircle, partner tags via Tag, and destination domains via LinkLogo using getApexDomain. When workspace link display preferences include title properties, short link rows prioritize rendering the link title over its short link slug.
Enterprise partner program analytics cover specialized operations such as tracking application conversion funnels, administering payouts and commission structures, and monitoring multi-tenant revenue metrics across administrative dashboards and workspace views. Querying these dimensions involves dedicated API endpoints, SWR hooks, and specialized visualization components.
Sources: apps/web/app/ee/api/program-applications/analytics/route.ts:37-40, apps/web/app/app.dub.co/dashboard/slug/ee/program/analytics/applications/applications-funnel-chart.tsx:42-48
The program applications endpoint GET /api/program-applications/analytics resolves the workspace default program identifier through getDefaultProgramIdOrThrow(workspace) and validates query parameters against applicationEventAnalyticsQuerySchema. Depending on the requested groupBy parameter, the execution flow diverges into absolute counts, grouped property queries, partner breakdowns, or timeseries aggregations.
The query execution chain follows a precise sequence:
withWorkspace() wrapper → getDefaultProgramIdOrThrow() → applicationEventAnalyticsQuerySchema.parse() → getStartEndDates() → parseFilterValue() → conditional branch on groupBy (count | referralSource | country | partnerId | timeseries).
Warning
When groupBy is set to partnerId, the API executes a two-step query: first grouping program application events by referredByPartnerId, and then performing a secondary relational lookup in prisma.partner.findMany filtered by partners associated with the active programId.
The ApplicationsFunnelChart component renders a four-stage conversion funnel mapping raw visits to final partner approvals. Each stage links to filtered query parameters and maps to specific event counts and color tokens.
Administrative consoles in admin.dub.co utilize dedicated page components to render financial timeseries, payout status metrics, and commission metrics. The RevenuePageClient component computes period-over-period percentage changes by evaluating rolling timestamp boundaries from timeseries and previousPeriodTimeseries datasets.
Sources: apps/web/app/ee/admin.dub.co/dashboard/revenue/page.tsx:47-146, apps/web/app/ee/admin.dub.co/dashboard/payouts/page.tsx:83-133
Sources: apps/web/app/ee/admin.dub.co/dashboard/revenue/page.tsx:52-61, apps/web/app/ee/admin.dub.co/dashboard/payouts/page.tsx:90-153, apps/web/app/ee/admin.dub.co/dashboard/commissions/page.tsx:46-68
Tip
Payout fees displayed in the revenue administration view are computed based on a trailing 6-month rolling average.