diff --git a/apps/mobile/src/features/inbox/components/FilterSheet.tsx b/apps/mobile/src/features/inbox/components/FilterSheet.tsx
index 5243c67648..f9109ac16a 100644
--- a/apps/mobile/src/features/inbox/components/FilterSheet.tsx
+++ b/apps/mobile/src/features/inbox/components/FilterSheet.tsx
@@ -77,6 +77,7 @@ const SOURCE_PRODUCT_OPTIONS: { value: SourceProduct; label: string }[] = [
{ value: "zendesk", label: "Zendesk" },
{ value: "conversations", label: "Conversations" },
{ value: "signals_scout", label: "Scout" },
+ { value: "health_checks", label: "Health checks" },
];
function SectionHeader({ title }: { title: string }) {
diff --git a/apps/mobile/src/features/inbox/components/SignalCard.tsx b/apps/mobile/src/features/inbox/components/SignalCard.tsx
index a32ff002d1..2027494bcb 100644
--- a/apps/mobile/src/features/inbox/components/SignalCard.tsx
+++ b/apps/mobile/src/features/inbox/components/SignalCard.tsx
@@ -9,6 +9,7 @@ import {
Code,
Compass,
GithubLogo,
+ Heartbeat,
LinkSimple,
Question,
Robot,
@@ -53,6 +54,8 @@ function sourceLine(signal: Signal): string {
)
return "Scout · Cross-source issue";
if (source_product === "signals_scout") return "Scout";
+ if (source_product === "health_checks" && source_type === "health_issue")
+ return "Health checks · Issue";
const product = source_product.replace(/_/g, " ");
const type = source_type.replace(/_/g, " ");
return `${product} · ${type}`;
@@ -82,6 +85,8 @@ function SourceIcon({
return ;
case "signals_scout":
return ;
+ case "health_checks":
+ return ;
default:
return ;
}
diff --git a/apps/mobile/src/features/inbox/stores/inboxFilterStore.ts b/apps/mobile/src/features/inbox/stores/inboxFilterStore.ts
index ea363b4e42..ed4bd36da7 100644
--- a/apps/mobile/src/features/inbox/stores/inboxFilterStore.ts
+++ b/apps/mobile/src/features/inbox/stores/inboxFilterStore.ts
@@ -22,7 +22,8 @@ export type SourceProduct =
| "linear"
| "zendesk"
| "conversations"
- | "signals_scout";
+ | "signals_scout"
+ | "health_checks";
export const DEFAULT_STATUS_FILTER: SignalReportStatus[] = [
"ready",
diff --git a/packages/api-client/src/posthog-client.ts b/packages/api-client/src/posthog-client.ts
index e4e76e63eb..4ea049d8c7 100644
--- a/packages/api-client/src/posthog-client.ts
+++ b/packages/api-client/src/posthog-client.ts
@@ -201,7 +201,8 @@ export interface SignalSourceConfig {
| "conversations"
| "error_tracking"
| "pganalyze"
- | "signals_scout";
+ | "signals_scout"
+ | "health_checks";
source_type:
| "session_analysis_cluster"
| "evaluation"
@@ -210,7 +211,8 @@ export interface SignalSourceConfig {
| "issue_created"
| "issue_reopened"
| "issue_spiking"
- | "cross_source_issue";
+ | "cross_source_issue"
+ | "health_issue";
enabled: boolean;
config: Record;
created_at: string;
diff --git a/packages/core/src/inbox/signalSourceService.test.ts b/packages/core/src/inbox/signalSourceService.test.ts
index ff06734571..0844cdf2d7 100644
--- a/packages/core/src/inbox/signalSourceService.test.ts
+++ b/packages/core/src/inbox/signalSourceService.test.ts
@@ -60,6 +60,13 @@ describe("computeSourceValues", () => {
const values = computeSourceValues([config("github", "issue", true)]);
expect(values.github).toBe(true);
});
+
+ it("enables health_checks when its config is enabled", () => {
+ const values = computeSourceValues([
+ config("health_checks", "health_issue", true),
+ ]);
+ expect(values.health_checks).toBe(true);
+ });
});
describe("deriveSourceStates", () => {
@@ -106,6 +113,17 @@ describe("SignalSourceService.toggleSource", () => {
expect(client.createSignalSourceConfig).toHaveBeenCalledTimes(1);
});
+ it("creates a health_checks config with the health_issue source type", async () => {
+ const client = fakeClient();
+ const service = new SignalSourceService();
+ await service.toggleSource(client, 1, "health_checks", true, [], []);
+ expect(client.createSignalSourceConfig).toHaveBeenCalledWith(1, {
+ source_product: "health_checks",
+ source_type: "health_issue",
+ enabled: true,
+ });
+ });
+
it("ensures the issues table syncs with full_refresh for github before enabling", async () => {
const client = fakeClient();
const service = new SignalSourceService();
diff --git a/packages/core/src/inbox/signalSourceService.ts b/packages/core/src/inbox/signalSourceService.ts
index 7b180808fb..26e39b358a 100644
--- a/packages/core/src/inbox/signalSourceService.ts
+++ b/packages/core/src/inbox/signalSourceService.ts
@@ -15,6 +15,7 @@ export interface SignalSourceValues {
zendesk: boolean;
conversations: boolean;
pganalyze: boolean;
+ health_checks: boolean;
}
export type SignalSourceProduct = keyof SignalSourceValues;
@@ -48,6 +49,7 @@ const SOURCE_TYPE_MAP: Record<
zendesk: "ticket",
conversations: "ticket",
pganalyze: "issue",
+ health_checks: "health_issue",
};
const ERROR_TRACKING_SOURCE_TYPES: SourceType[] = [
@@ -74,6 +76,7 @@ const ALL_SOURCE_PRODUCTS: SignalSourceProduct[] = [
"zendesk",
"conversations",
"pganalyze",
+ "health_checks",
];
function isWarehouseSource(
@@ -109,6 +112,7 @@ export function computeSourceValues(
zendesk: false,
conversations: false,
pganalyze: false,
+ health_checks: false,
};
if (!configs?.length) {
return result;
diff --git a/packages/shared/src/analytics-events.ts b/packages/shared/src/analytics-events.ts
index c1e875f563..e7f61903da 100644
--- a/packages/shared/src/analytics-events.ts
+++ b/packages/shared/src/analytics-events.ts
@@ -731,7 +731,8 @@ export interface SignalSourceConnectedProperties {
| "zendesk"
| "conversations"
| "pganalyze"
- | "llm_analytics";
+ | "llm_analytics"
+ | "health_checks";
/** True when this is a brand-new createSignalSourceConfig, false for re-enable of an existing config. */
is_first_connection: boolean;
/** True when the connection went through the DataSourceSetup wizard (warehouse OAuth path). */
diff --git a/packages/shared/src/inbox-types.ts b/packages/shared/src/inbox-types.ts
index 578c1b2eb9..1a8a959268 100644
--- a/packages/shared/src/inbox-types.ts
+++ b/packages/shared/src/inbox-types.ts
@@ -14,4 +14,5 @@ export type SourceProduct =
| "zendesk"
| "conversations"
| "pganalyze"
- | "signals_scout";
+ | "signals_scout"
+ | "health_checks";
diff --git a/packages/ui/src/features/inbox/components/SignalSourceToggles.tsx b/packages/ui/src/features/inbox/components/SignalSourceToggles.tsx
index ad20f2904f..15b9e86e03 100644
--- a/packages/ui/src/features/inbox/components/SignalSourceToggles.tsx
+++ b/packages/ui/src/features/inbox/components/SignalSourceToggles.tsx
@@ -6,6 +6,7 @@ import {
CircleNotchIcon,
CompassIcon,
GithubLogoIcon,
+ HeartbeatIcon,
KanbanIcon,
TicketIcon,
VideoIcon,
@@ -26,6 +27,7 @@ export interface SignalSourceValues {
zendesk: boolean;
conversations: boolean;
pganalyze: boolean;
+ health_checks: boolean;
}
interface SignalSourceToggleCardProps {
@@ -300,6 +302,10 @@ export function SignalSourceToggles({
(checked: boolean) => onToggle("conversations", checked),
[onToggle],
);
+ const toggleHealthChecks = useCallback(
+ (checked: boolean) => onToggle("health_checks", checked),
+ [onToggle],
+ );
const toggleScouts = useCallback(
(checked: boolean) => onToggle("signals_scout", checked),
[onToggle],
@@ -332,6 +338,17 @@ export function SignalSourceToggles({
docsUrl="https://posthog.com/docs/error-tracking"
docsLabel="Error Tracking"
/>
+ }
+ label="Health checks"
+ description="Recommended — detects problems with your PostHog integration (missing events, proxy gaps, outdated SDKs) and automatically suggests fixes."
+ checked={value.health_checks}
+ onCheckedChange={toggleHealthChecks}
+ disabled={disabled}
+ syncStatus={sourceStates?.health_checks?.syncStatus}
+ docsUrl="https://posthog.com/docs/sdk-health"
+ docsLabel="Health checks"
+ />
}
label="Support"
diff --git a/packages/ui/src/features/inbox/components/detail/SignalCard.tsx b/packages/ui/src/features/inbox/components/detail/SignalCard.tsx
index 9ee7609100..4b34728209 100644
--- a/packages/ui/src/features/inbox/components/detail/SignalCard.tsx
+++ b/packages/ui/src/features/inbox/components/detail/SignalCard.tsx
@@ -86,6 +86,9 @@ function signalCardSourceLine(signal: {
if (source_product === "pganalyze" && source_type === "issue") {
return "pganalyze · Issue";
}
+ if (source_product === "health_checks" && source_type === "health_issue") {
+ return "Health checks · Issue";
+ }
if (
source_product === "signals_scout" &&
source_type === "cross_source_issue"
diff --git a/packages/ui/src/features/inbox/components/responderAgentMeta.ts b/packages/ui/src/features/inbox/components/responderAgentMeta.ts
index bddd18fbf5..5db40cf6cd 100644
--- a/packages/ui/src/features/inbox/components/responderAgentMeta.ts
+++ b/packages/ui/src/features/inbox/components/responderAgentMeta.ts
@@ -30,6 +30,15 @@ export const RESPONDER_AGENT_GROUPS: ResponderAgentGroup[] = [
docsUrl: "https://posthog.com/docs/error-tracking",
docsLabel: "Error Tracking",
},
+ {
+ source: "health_checks",
+ sourceProduct: "health_checks",
+ label: "Health checks",
+ description:
+ "Recommended — detects problems with your PostHog integration and suggests fixes automatically.",
+ docsUrl: "https://posthog.com/docs/sdk-health",
+ docsLabel: "Health checks",
+ },
{
source: "conversations",
sourceProduct: "conversations",
diff --git a/packages/ui/src/features/inbox/components/utils/source-product-icons.tsx b/packages/ui/src/features/inbox/components/utils/source-product-icons.tsx
index 248ef1d926..ff768c6c2e 100644
--- a/packages/ui/src/features/inbox/components/utils/source-product-icons.tsx
+++ b/packages/ui/src/features/inbox/components/utils/source-product-icons.tsx
@@ -4,6 +4,7 @@ import {
BugIcon,
CompassIcon,
GithubLogoIcon,
+ HeartbeatIcon,
KanbanIcon,
LifebuoyIcon,
TicketIcon,
@@ -95,4 +96,9 @@ export const SOURCE_PRODUCT_META: Partial<
color: "var(--iris-9)",
label: "Scout",
},
+ health_checks: {
+ Icon: HeartbeatIcon,
+ color: "var(--crimson-9)",
+ label: "Health checks",
+ },
};
diff --git a/packages/ui/src/features/inbox/filterOptions.tsx b/packages/ui/src/features/inbox/filterOptions.tsx
index 691169be53..363b3c12dc 100644
--- a/packages/ui/src/features/inbox/filterOptions.tsx
+++ b/packages/ui/src/features/inbox/filterOptions.tsx
@@ -5,6 +5,7 @@ import {
Clock,
CompassIcon,
GithubLogoIcon,
+ HeartbeatIcon,
KanbanIcon,
LifebuoyIcon,
ListNumbers,
@@ -101,6 +102,11 @@ export const INBOX_SOURCE_OPTIONS: {
},
{ value: "pganalyze", label: "pganalyze", icon: },
{ value: "signals_scout", label: "Scouts", icon: },
+ {
+ value: "health_checks",
+ label: "Health checks",
+ icon: ,
+ },
];
export function inboxSortOptionKey(
diff --git a/packages/ui/src/features/inbox/hooks/useSignalSourceToggles.ts b/packages/ui/src/features/inbox/hooks/useSignalSourceToggles.ts
index 9ea49ee860..06594c83c0 100644
--- a/packages/ui/src/features/inbox/hooks/useSignalSourceToggles.ts
+++ b/packages/ui/src/features/inbox/hooks/useSignalSourceToggles.ts
@@ -25,6 +25,7 @@ const SOURCE_TYPE_MAP: Record<
zendesk: "ticket",
conversations: "ticket",
pganalyze: "issue",
+ health_checks: "health_issue",
};
const ERROR_TRACKING_SOURCE_TYPES: SourceType[] = [
@@ -42,6 +43,7 @@ const SOURCE_LABELS: Record = {
zendesk: "Zendesk Tickets",
conversations: "PostHog Support",
pganalyze: "pganalyze",
+ health_checks: "Health checks",
};
const DATA_WAREHOUSE_SOURCES: Record<
@@ -63,6 +65,7 @@ const ALL_SOURCE_PRODUCTS: (keyof SignalSourceValues)[] = [
"zendesk",
"conversations",
"pganalyze",
+ "health_checks",
];
function isSetupSourceProduct(
@@ -83,6 +86,7 @@ function computeValues(
zendesk: false,
conversations: false,
pganalyze: false,
+ health_checks: false,
};
if (!configs?.length) return result;
for (const product of ALL_SOURCE_PRODUCTS) {