diff --git a/apps/code/src/renderer/features/billing/components/SidebarUsageBar.tsx b/apps/code/src/renderer/features/billing/components/SidebarUsageBar.tsx
index e2dfdcb60..ec1f27bfb 100644
--- a/apps/code/src/renderer/features/billing/components/SidebarUsageBar.tsx
+++ b/apps/code/src/renderer/features/billing/components/SidebarUsageBar.tsx
@@ -4,6 +4,8 @@ import { useSettingsDialogStore } from "@features/settings/stores/settingsDialog
import { useFeatureFlag } from "@hooks/useFeatureFlag";
import { Circle } from "@phosphor-icons/react";
import { BILLING_FLAG } from "@shared/constants";
+import { ANALYTICS_EVENTS } from "@shared/types/analytics";
+import { track } from "@utils/analytics";
export function SidebarUsageBar() {
const billingEnabled = useFeatureFlag(BILLING_FLAG);
@@ -12,6 +14,7 @@ export function SidebarUsageBar() {
if (!billingEnabled) return null;
const handleUpgrade = () => {
+ track(ANALYTICS_EVENTS.UPGRADE_PROMPT_CLICKED, { surface: "sidebar" });
useSettingsDialogStore.getState().open("plan-usage");
};
diff --git a/apps/code/src/renderer/features/billing/components/UsageLimitModal.tsx b/apps/code/src/renderer/features/billing/components/UsageLimitModal.tsx
index 386687dc5..5022542a5 100644
--- a/apps/code/src/renderer/features/billing/components/UsageLimitModal.tsx
+++ b/apps/code/src/renderer/features/billing/components/UsageLimitModal.tsx
@@ -2,12 +2,26 @@ import { useUsageLimitStore } from "@features/billing/stores/usageLimitStore";
import { useSettingsDialogStore } from "@features/settings/stores/settingsDialogStore";
import { WarningCircle } from "@phosphor-icons/react";
import { Button, Dialog, Flex, Text } from "@radix-ui/themes";
+import { ANALYTICS_EVENTS } from "@shared/types/analytics";
+import { track } from "@utils/analytics";
+import { useEffect } from "react";
export function UsageLimitModal() {
const isOpen = useUsageLimitStore((s) => s.isOpen);
const hide = useUsageLimitStore((s) => s.hide);
+ useEffect(() => {
+ if (isOpen) {
+ track(ANALYTICS_EVENTS.UPGRADE_PROMPT_SHOWN, {
+ surface: "usage_limit_modal",
+ });
+ }
+ }, [isOpen]);
+
const handleUpgrade = () => {
+ track(ANALYTICS_EVENTS.UPGRADE_PROMPT_CLICKED, {
+ surface: "usage_limit_modal",
+ });
hide();
useSettingsDialogStore.getState().open("plan-usage");
};
@@ -22,12 +36,14 @@ export function UsageLimitModal() {
- Usage limit reached
+
+ You're out of usage for this month
+
- You've reached your free plan usage limit. Upgrade to Pro for
- unlimited usage.
+ You've hit your Free usage limit. Upgrade to Pro for 20× more
+ usage.
@@ -35,7 +51,7 @@ export function UsageLimitModal() {
Not now
diff --git a/apps/code/src/renderer/features/settings/components/sections/PlanUsageSettings.tsx b/apps/code/src/renderer/features/settings/components/sections/PlanUsageSettings.tsx
index b3001f596..9046e271b 100644
--- a/apps/code/src/renderer/features/settings/components/sections/PlanUsageSettings.tsx
+++ b/apps/code/src/renderer/features/settings/components/sections/PlanUsageSettings.tsx
@@ -9,12 +9,12 @@ import { useSeat } from "@hooks/useSeat";
import type { UsageBucket } from "@main/services/llm-gateway/schemas";
import {
ArrowSquareOut,
- Check,
CreditCard,
Info,
WarningCircle,
} from "@phosphor-icons/react";
import {
+ Badge,
Button,
Callout,
Dialog,
@@ -23,8 +23,9 @@ import {
Spinner,
Text,
} from "@radix-ui/themes";
-import { Tooltip } from "@renderer/components/ui/Tooltip";
+import { ANALYTICS_EVENTS } from "@shared/types/analytics";
import { PLAN_PRO_ALPHA } from "@shared/types/seat";
+import { track } from "@utils/analytics";
import { logger } from "@utils/logger";
import { getBillingUrl, getPostHogUrl } from "@utils/urls";
import { useEffect, useState } from "react";
@@ -86,6 +87,14 @@ export function PlanUsageSettings() {
void refetchUsage();
}, [fetchSeat, refetchUsage]);
+ useEffect(() => {
+ if (showUpgradeDialog) {
+ track(ANALYTICS_EVENTS.UPGRADE_PROMPT_SHOWN, {
+ surface: "upgrade_dialog",
+ });
+ }
+ }, [showUpgradeDialog]);
+
const formattedActiveUntil = activeUntil
? activeUntil.toLocaleDateString(undefined, {
month: "short",
@@ -183,22 +192,13 @@ export function PlanUsageSettings() {
name="Free"
price="$0"
period="/mo"
- features={[
- "Limited usage",
- "Local and cloud execution",
- "All Claude and Codex models",
- ]}
isCurrent={!isOrgPro}
/>
setShowUpgradeDialog(true)}
+ onClick={() => {
+ track(ANALYTICS_EVENTS.UPGRADE_PROMPT_CLICKED, {
+ surface: "plan_page_card",
+ });
+ setShowUpgradeDialog(true);
+ }}
disabled={isLoading}
className="self-start"
>
@@ -351,28 +356,16 @@ export function PlanUsageSettings() {
Upgrade to Pro
+ Pro is for teams using Code as part of their daily development
+ workflow: longer cloud runs, repeated agent iterations, and fewer
+ stops as work scales.{" "}
{seat?.organization_name ? (
{seat.organization_name}
) : (
"Your organization"
)}{" "}
- will be charged $200/month using the payment method on file in
- PostHog.
+ will be charged $200/month for 20× the Free usage limit.
-
-
-
- Higher usage limits
-
-
-
- Local and cloud execution
-
-
-
- All Claude and Codex models
-
-
{
+ track(ANALYTICS_EVENTS.UPGRADE_PROMPT_CLICKED, {
+ surface: "upgrade_dialog",
+ });
setShowUpgradeDialog(false);
await upgradeToPro();
}}
@@ -450,9 +446,9 @@ interface PlanCardProps {
name: string;
price: string;
period: string;
- features: string[];
isCurrent: boolean;
resetLabel?: string;
+ badge?: string;
action?: React.ReactNode;
}
@@ -460,9 +456,9 @@ function PlanCard({
name,
price,
period,
- features,
isCurrent,
resetLabel,
+ badge,
action,
}: PlanCardProps) {
return (
@@ -477,8 +473,13 @@ function PlanCard({
: "1px solid var(--gray-5)",
opacity: isCurrent ? 1 : 0.7,
}}
- className="flex-1 rounded-(--radius-3)"
+ className="relative flex-1 rounded-(--radius-3)"
>
+ {badge && (
+
+ {badge}
+
+ )}
{resetLabel}
)}
-
- {features.map((feature) => (
-
-
-
- {feature.endsWith("*") ? (
- <>
- {feature.slice(0, -1)}
-
- *
-
- >
- ) : (
- feature
- )}
-
-
- ))}
-
{action}
diff --git a/apps/code/src/shared/types/analytics.ts b/apps/code/src/shared/types/analytics.ts
index 58d12542e..3bb504aae 100644
--- a/apps/code/src/shared/types/analytics.ts
+++ b/apps/code/src/shared/types/analytics.ts
@@ -594,6 +594,23 @@ export interface SignalSourceConnectedProperties {
}
// Subscription / billing events
+
+export type UpgradePromptShownSurface = "usage_limit_modal" | "upgrade_dialog";
+
+export type UpgradePromptClickedSurface =
+ | "usage_limit_modal"
+ | "sidebar"
+ | "plan_page_card"
+ | "upgrade_dialog";
+
+export interface UpgradePromptShownProperties {
+ surface: UpgradePromptShownSurface;
+}
+
+export interface UpgradePromptClickedProperties {
+ surface: UpgradePromptClickedSurface;
+}
+
export interface SubscriptionStartedProperties {
plan_key: string;
previous_plan_key?: string;
@@ -722,6 +739,8 @@ export const ANALYTICS_EVENTS = {
PROMPT_HISTORY_SELECTED: "Prompt history selected",
// Subscription events
+ UPGRADE_PROMPT_SHOWN: "Upgrade prompt shown",
+ UPGRADE_PROMPT_CLICKED: "Upgrade prompt clicked",
SUBSCRIPTION_STARTED: "Subscription started",
SUBSCRIPTION_CANCELLED: "Subscription cancelled",
} as const;
@@ -838,6 +857,8 @@ export type EventPropertyMap = {
[ANALYTICS_EVENTS.PROMPT_HISTORY_SELECTED]: PromptHistorySelectedProperties;
// Subscription events
+ [ANALYTICS_EVENTS.UPGRADE_PROMPT_SHOWN]: UpgradePromptShownProperties;
+ [ANALYTICS_EVENTS.UPGRADE_PROMPT_CLICKED]: UpgradePromptClickedProperties;
[ANALYTICS_EVENTS.SUBSCRIPTION_STARTED]: SubscriptionStartedProperties;
[ANALYTICS_EVENTS.SUBSCRIPTION_CANCELLED]: SubscriptionCancelledProperties;
};