From 2277834d2c49944410f7dda4e8de4857e2a95d17 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 6 Apr 2026 12:33:32 -0700 Subject: [PATCH 1/4] feat(landing): add PostHog tracking for CTA clicks, demo requests, and prompt submissions --- .../components/demo-request/demo-request-modal.tsx | 4 ++++ .../app/(landing)/components/footer/footer-cta.tsx | 5 +++++ apps/sim/app/(landing)/components/hero/hero.tsx | 3 +++ .../landing-preview-home/landing-preview-home.tsx | 2 ++ .../landing-preview-panel/landing-preview-panel.tsx | 2 ++ apps/sim/app/(landing)/components/navbar/navbar.tsx | 10 +++++++--- .../app/(landing)/components/pricing/pricing.tsx | 4 ++++ apps/sim/app/(landing)/landing-analytics.tsx | 13 ++++++++++++- apps/sim/lib/posthog/events.ts | 12 ++++++++++++ 9 files changed, 51 insertions(+), 4 deletions(-) diff --git a/apps/sim/app/(landing)/components/demo-request/demo-request-modal.tsx b/apps/sim/app/(landing)/components/demo-request/demo-request-modal.tsx index 01067670a1d..c4b51a36957 100644 --- a/apps/sim/app/(landing)/components/demo-request/demo-request-modal.tsx +++ b/apps/sim/app/(landing)/components/demo-request/demo-request-modal.tsx @@ -18,6 +18,7 @@ import { type DemoRequestPayload, demoRequestSchema, } from '@/app/(landing)/components/demo-request/consts' +import { captureClientEvent } from '@/lib/posthog/client' interface DemoRequestModalProps { children: React.ReactNode @@ -163,6 +164,9 @@ export function DemoRequestModal({ children, theme = 'dark' }: DemoRequestModalP } setSubmitSuccess(true) + captureClientEvent('landing_demo_request_submitted', { + company_size: parsed.data.companySize, + }) } catch (error) { setSubmitError( error instanceof Error diff --git a/apps/sim/app/(landing)/components/footer/footer-cta.tsx b/apps/sim/app/(landing)/components/footer/footer-cta.tsx index c1c95a638da..de24ae1a51a 100644 --- a/apps/sim/app/(landing)/components/footer/footer-cta.tsx +++ b/apps/sim/app/(landing)/components/footer/footer-cta.tsx @@ -5,6 +5,8 @@ import { ArrowUp } from 'lucide-react' import Link from 'next/link' import { useLandingSubmit } from '@/app/(landing)/components/landing-preview/components/landing-preview-panel/landing-preview-panel' import { useAnimatedPlaceholder } from '@/hooks/use-animated-placeholder' +import { trackLandingCta } from '@/app/(landing)/landing-analytics' +import { captureClientEvent } from '@/lib/posthog/client' const MAX_HEIGHT = 120 @@ -21,6 +23,7 @@ export function FooterCTA() { const handleSubmit = useCallback(() => { if (isEmpty) return + captureClientEvent('landing_prompt_submitted', {}) landingSubmit(inputValue) }, [isEmpty, inputValue, landingSubmit]) @@ -94,12 +97,14 @@ export function FooterCTA() { target='_blank' rel='noopener noreferrer' className={`${CTA_BUTTON} border-[var(--landing-border-strong)] text-[var(--landing-text)] transition-colors hover:bg-[var(--landing-bg-elevated)]`} + onClick={() => trackLandingCta({ label: 'Docs', section: 'footer_cta', destination: 'https://docs.sim.ai' })} > Docs trackLandingCta({ label: 'Get started', section: 'footer_cta', destination: '/signup' })} > Get started diff --git a/apps/sim/app/(landing)/components/hero/hero.tsx b/apps/sim/app/(landing)/components/hero/hero.tsx index 775f241c337..0d07985f8a0 100644 --- a/apps/sim/app/(landing)/components/hero/hero.tsx +++ b/apps/sim/app/(landing)/components/hero/hero.tsx @@ -3,6 +3,7 @@ import dynamic from 'next/dynamic' import Link from 'next/link' import { DemoRequestModal } from '@/app/(landing)/components/demo-request/demo-request-modal' +import { trackLandingCta } from '@/app/(landing)/landing-analytics' const LandingPreview = dynamic( () => @@ -57,6 +58,7 @@ export default function Hero() { type='button' className={`${CTA_BASE} border-[var(--landing-border-strong)] bg-transparent text-[var(--landing-text)] transition-colors hover:bg-[var(--landing-bg-elevated)]`} aria-label='Get a demo' + onClick={() => trackLandingCta({ label: 'Get a demo', section: 'hero', destination: 'demo_modal' })} > Get a demo @@ -65,6 +67,7 @@ export default function Hero() { href='/signup' className={`${CTA_BASE} gap-2 border-white bg-white text-black transition-colors hover:border-[#E0E0E0] hover:bg-[#E0E0E0]`} aria-label='Get started with Sim' + onClick={() => trackLandingCta({ label: 'Get started', section: 'hero', destination: '/signup' })} > Get started diff --git a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-home/landing-preview-home.tsx b/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-home/landing-preview-home.tsx index 35cb85c1654..645ee9fb1be 100644 --- a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-home/landing-preview-home.tsx +++ b/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-home/landing-preview-home.tsx @@ -8,6 +8,7 @@ import { TypeBoolean, TypeNumber, TypeText } from '@/components/emcn/icons' import { useLandingSubmit } from '@/app/(landing)/components/landing-preview/components/landing-preview-panel/landing-preview-panel' import { EASE_OUT } from '@/app/(landing)/components/landing-preview/components/landing-preview-workflow/workflow-data' import { useAnimatedPlaceholder } from '@/hooks/use-animated-placeholder' +import { captureClientEvent } from '@/lib/posthog/client' const C = { SURFACE: '#292929', @@ -151,6 +152,7 @@ export const LandingPreviewHome = memo(function LandingPreviewHome({ const handleSubmit = useCallback(() => { if (isEmpty) return + captureClientEvent('landing_prompt_submitted', {}) landingSubmit(inputValue) }, [isEmpty, inputValue, landingSubmit]) diff --git a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-panel/landing-preview-panel.tsx b/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-panel/landing-preview-panel.tsx index 4ca06238463..782a89cee7b 100644 --- a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-panel/landing-preview-panel.tsx +++ b/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-panel/landing-preview-panel.tsx @@ -8,6 +8,7 @@ import { useRouter } from 'next/navigation' import { createPortal } from 'react-dom' import { Blimp, BubbleChatPreview, ChevronDown, MoreHorizontal, Play } from '@/components/emcn' import { AgentIcon, HubspotIcon, OpenAIIcon, SalesforceIcon } from '@/components/icons' +import { captureClientEvent } from '@/lib/posthog/client' import { LandingPromptStorage } from '@/lib/core/utils/browser-storage' import { EASE_OUT, @@ -147,6 +148,7 @@ export const LandingPreviewPanel = memo(function LandingPreviewPanel({ const handleSubmit = useCallback(() => { if (isEmpty) return + captureClientEvent('landing_prompt_submitted', {}) landingSubmit(inputValue) }, [isEmpty, inputValue, landingSubmit]) diff --git a/apps/sim/app/(landing)/components/navbar/navbar.tsx b/apps/sim/app/(landing)/components/navbar/navbar.tsx index 0cc2a8c306a..00bf5fc438e 100644 --- a/apps/sim/app/(landing)/components/navbar/navbar.tsx +++ b/apps/sim/app/(landing)/components/navbar/navbar.tsx @@ -7,6 +7,7 @@ import { useSearchParams } from 'next/navigation' import { GithubOutlineIcon } from '@/components/icons' import { useSession } from '@/lib/auth/auth-client' import { cn } from '@/lib/core/utils/cn' +import { trackLandingCta } from '@/app/(landing)/landing-analytics' import { BlogDropdown, type NavBlogPost, @@ -212,6 +213,7 @@ export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps href='/workspace' className='inline-flex h-[30px] items-center gap-[7px] rounded-[5px] border border-[var(--white)] bg-[var(--white)] px-[9px] text-[13.5px] text-black transition-colors hover:border-[#E0E0E0] hover:bg-[#E0E0E0]' aria-label='Go to app' + onClick={() => trackLandingCta({ label: 'Go to App', section: 'navbar', destination: '/workspace' })} > Go to App @@ -221,6 +223,7 @@ export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps href='/login' className='inline-flex h-[30px] items-center rounded-[5px] border border-[var(--landing-border-strong)] px-[9px] text-[13.5px] text-[var(--landing-text)] transition-colors hover:bg-[var(--landing-bg-elevated)]' aria-label='Log in' + onClick={() => trackLandingCta({ label: 'Log in', section: 'navbar', destination: '/login' })} > Log in @@ -228,6 +231,7 @@ export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps href='/signup' className='inline-flex h-[30px] items-center gap-[7px] rounded-[5px] border border-[var(--white)] bg-[var(--white)] px-2.5 text-[13.5px] text-black transition-colors hover:border-[#E0E0E0] hover:bg-[#E0E0E0]' aria-label='Get started with Sim' + onClick={() => trackLandingCta({ label: 'Get started', section: 'navbar', destination: '/signup' })} > Get started @@ -303,7 +307,7 @@ export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps setMobileMenuOpen(false)} + onClick={() => { trackLandingCta({ label: 'Go to App', section: 'navbar', destination: '/workspace' }); setMobileMenuOpen(false) }} aria-label='Go to app' > Go to App @@ -313,7 +317,7 @@ export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps setMobileMenuOpen(false)} + onClick={() => { trackLandingCta({ label: 'Log in', section: 'navbar', destination: '/login' }); setMobileMenuOpen(false) }} aria-label='Log in' > Log in @@ -321,7 +325,7 @@ export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps setMobileMenuOpen(false)} + onClick={() => { trackLandingCta({ label: 'Get started', section: 'navbar', destination: '/signup' }); setMobileMenuOpen(false) }} aria-label='Get started with Sim' > Get started diff --git a/apps/sim/app/(landing)/components/pricing/pricing.tsx b/apps/sim/app/(landing)/components/pricing/pricing.tsx index 455aea124c8..5fb7ab759e0 100644 --- a/apps/sim/app/(landing)/components/pricing/pricing.tsx +++ b/apps/sim/app/(landing)/components/pricing/pricing.tsx @@ -3,6 +3,7 @@ import Link from 'next/link' import { Badge } from '@/components/emcn' import { DemoRequestModal } from '@/app/(landing)/components/demo-request/demo-request-modal' +import { trackLandingCta } from '@/app/(landing)/landing-analytics' interface PricingTier { id: string @@ -150,6 +151,7 @@ function PricingCard({ tier }: PricingCardProps) { @@ -158,6 +160,7 @@ function PricingCard({ tier }: PricingCardProps) { trackLandingCta({ label: tier.cta.label, section: 'pricing', destination: tier.cta.href || '/signup' })} > {tier.cta.label} @@ -165,6 +168,7 @@ function PricingCard({ tier }: PricingCardProps) { trackLandingCta({ label: tier.cta.label, section: 'pricing', destination: tier.cta.href || '/signup' })} > {tier.cta.label} diff --git a/apps/sim/app/(landing)/landing-analytics.tsx b/apps/sim/app/(landing)/landing-analytics.tsx index 10be29e5edd..a061e1b7a59 100644 --- a/apps/sim/app/(landing)/landing-analytics.tsx +++ b/apps/sim/app/(landing)/landing-analytics.tsx @@ -2,7 +2,8 @@ import { useEffect } from 'react' import { usePostHog } from 'posthog-js/react' -import { captureEvent } from '@/lib/posthog/client' +import { captureClientEvent, captureEvent } from '@/lib/posthog/client' +import type { PostHogEventMap } from '@/lib/posthog/events' export function LandingAnalytics() { const posthog = usePostHog() @@ -13,3 +14,13 @@ export function LandingAnalytics() { return null } + +/** + * Fire-and-forget tracker for landing page CTA clicks. + * Uses the non-hook client so it works in any click handler without requiring a PostHog provider ref. + */ +export function trackLandingCta( + props: PostHogEventMap['landing_cta_clicked'] +): void { + captureClientEvent('landing_cta_clicked', props) +} diff --git a/apps/sim/lib/posthog/events.ts b/apps/sim/lib/posthog/events.ts index c186d82cd47..8d8a1d194b2 100644 --- a/apps/sim/lib/posthog/events.ts +++ b/apps/sim/lib/posthog/events.ts @@ -14,6 +14,18 @@ export interface PostHogEventMap { landing_page_viewed: Record + landing_cta_clicked: { + label: string + section: 'hero' | 'navbar' | 'footer_cta' | 'pricing' + destination: string + } + + landing_demo_request_submitted: { + company_size: string + } + + landing_prompt_submitted: Record + signup_page_viewed: Record subscription_created: { From b69dea6c10290e385dfd361fa88825cc2cab357c Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 6 Apr 2026 12:35:52 -0700 Subject: [PATCH 2/4] lint --- .../demo-request/demo-request-modal.tsx | 2 +- .../components/footer/footer-cta.tsx | 16 +++++-- .../app/(landing)/components/hero/hero.tsx | 8 +++- .../landing-preview-home.tsx | 2 +- .../landing-preview-panel.tsx | 2 +- .../(landing)/components/navbar/navbar.tsx | 45 ++++++++++++++++--- .../(landing)/components/pricing/pricing.tsx | 24 ++++++++-- apps/sim/app/(landing)/landing-analytics.tsx | 4 +- 8 files changed, 81 insertions(+), 22 deletions(-) diff --git a/apps/sim/app/(landing)/components/demo-request/demo-request-modal.tsx b/apps/sim/app/(landing)/components/demo-request/demo-request-modal.tsx index c4b51a36957..3ed6c53bf67 100644 --- a/apps/sim/app/(landing)/components/demo-request/demo-request-modal.tsx +++ b/apps/sim/app/(landing)/components/demo-request/demo-request-modal.tsx @@ -13,12 +13,12 @@ import { Textarea, } from '@/components/emcn' import { Check } from '@/components/emcn/icons' +import { captureClientEvent } from '@/lib/posthog/client' import { DEMO_REQUEST_COMPANY_SIZE_OPTIONS, type DemoRequestPayload, demoRequestSchema, } from '@/app/(landing)/components/demo-request/consts' -import { captureClientEvent } from '@/lib/posthog/client' interface DemoRequestModalProps { children: React.ReactNode diff --git a/apps/sim/app/(landing)/components/footer/footer-cta.tsx b/apps/sim/app/(landing)/components/footer/footer-cta.tsx index de24ae1a51a..f9af4ac4bcc 100644 --- a/apps/sim/app/(landing)/components/footer/footer-cta.tsx +++ b/apps/sim/app/(landing)/components/footer/footer-cta.tsx @@ -3,10 +3,10 @@ import { useCallback, useRef, useState } from 'react' import { ArrowUp } from 'lucide-react' import Link from 'next/link' +import { captureClientEvent } from '@/lib/posthog/client' import { useLandingSubmit } from '@/app/(landing)/components/landing-preview/components/landing-preview-panel/landing-preview-panel' -import { useAnimatedPlaceholder } from '@/hooks/use-animated-placeholder' import { trackLandingCta } from '@/app/(landing)/landing-analytics' -import { captureClientEvent } from '@/lib/posthog/client' +import { useAnimatedPlaceholder } from '@/hooks/use-animated-placeholder' const MAX_HEIGHT = 120 @@ -97,14 +97,22 @@ export function FooterCTA() { target='_blank' rel='noopener noreferrer' className={`${CTA_BUTTON} border-[var(--landing-border-strong)] text-[var(--landing-text)] transition-colors hover:bg-[var(--landing-bg-elevated)]`} - onClick={() => trackLandingCta({ label: 'Docs', section: 'footer_cta', destination: 'https://docs.sim.ai' })} + onClick={() => + trackLandingCta({ + label: 'Docs', + section: 'footer_cta', + destination: 'https://docs.sim.ai', + }) + } > Docs trackLandingCta({ label: 'Get started', section: 'footer_cta', destination: '/signup' })} + onClick={() => + trackLandingCta({ label: 'Get started', section: 'footer_cta', destination: '/signup' }) + } > Get started diff --git a/apps/sim/app/(landing)/components/hero/hero.tsx b/apps/sim/app/(landing)/components/hero/hero.tsx index 0d07985f8a0..7098c4abf71 100644 --- a/apps/sim/app/(landing)/components/hero/hero.tsx +++ b/apps/sim/app/(landing)/components/hero/hero.tsx @@ -58,7 +58,9 @@ export default function Hero() { type='button' className={`${CTA_BASE} border-[var(--landing-border-strong)] bg-transparent text-[var(--landing-text)] transition-colors hover:bg-[var(--landing-bg-elevated)]`} aria-label='Get a demo' - onClick={() => trackLandingCta({ label: 'Get a demo', section: 'hero', destination: 'demo_modal' })} + onClick={() => + trackLandingCta({ label: 'Get a demo', section: 'hero', destination: 'demo_modal' }) + } > Get a demo @@ -67,7 +69,9 @@ export default function Hero() { href='/signup' className={`${CTA_BASE} gap-2 border-white bg-white text-black transition-colors hover:border-[#E0E0E0] hover:bg-[#E0E0E0]`} aria-label='Get started with Sim' - onClick={() => trackLandingCta({ label: 'Get started', section: 'hero', destination: '/signup' })} + onClick={() => + trackLandingCta({ label: 'Get started', section: 'hero', destination: '/signup' }) + } > Get started diff --git a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-home/landing-preview-home.tsx b/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-home/landing-preview-home.tsx index 645ee9fb1be..aea260a3cb0 100644 --- a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-home/landing-preview-home.tsx +++ b/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-home/landing-preview-home.tsx @@ -5,10 +5,10 @@ import { AnimatePresence, motion } from 'framer-motion' import { ArrowUp, Table } from 'lucide-react' import { Blimp, Checkbox, ChevronDown } from '@/components/emcn' import { TypeBoolean, TypeNumber, TypeText } from '@/components/emcn/icons' +import { captureClientEvent } from '@/lib/posthog/client' import { useLandingSubmit } from '@/app/(landing)/components/landing-preview/components/landing-preview-panel/landing-preview-panel' import { EASE_OUT } from '@/app/(landing)/components/landing-preview/components/landing-preview-workflow/workflow-data' import { useAnimatedPlaceholder } from '@/hooks/use-animated-placeholder' -import { captureClientEvent } from '@/lib/posthog/client' const C = { SURFACE: '#292929', diff --git a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-panel/landing-preview-panel.tsx b/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-panel/landing-preview-panel.tsx index 782a89cee7b..ef5929963e7 100644 --- a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-panel/landing-preview-panel.tsx +++ b/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-panel/landing-preview-panel.tsx @@ -8,8 +8,8 @@ import { useRouter } from 'next/navigation' import { createPortal } from 'react-dom' import { Blimp, BubbleChatPreview, ChevronDown, MoreHorizontal, Play } from '@/components/emcn' import { AgentIcon, HubspotIcon, OpenAIIcon, SalesforceIcon } from '@/components/icons' -import { captureClientEvent } from '@/lib/posthog/client' import { LandingPromptStorage } from '@/lib/core/utils/browser-storage' +import { captureClientEvent } from '@/lib/posthog/client' import { EASE_OUT, type EditorPromptData, diff --git a/apps/sim/app/(landing)/components/navbar/navbar.tsx b/apps/sim/app/(landing)/components/navbar/navbar.tsx index 00bf5fc438e..8f595d69078 100644 --- a/apps/sim/app/(landing)/components/navbar/navbar.tsx +++ b/apps/sim/app/(landing)/components/navbar/navbar.tsx @@ -7,13 +7,13 @@ import { useSearchParams } from 'next/navigation' import { GithubOutlineIcon } from '@/components/icons' import { useSession } from '@/lib/auth/auth-client' import { cn } from '@/lib/core/utils/cn' -import { trackLandingCta } from '@/app/(landing)/landing-analytics' import { BlogDropdown, type NavBlogPost, } from '@/app/(landing)/components/navbar/components/blog-dropdown' import { DocsDropdown } from '@/app/(landing)/components/navbar/components/docs-dropdown' import { GitHubStars } from '@/app/(landing)/components/navbar/components/github-stars' +import { trackLandingCta } from '@/app/(landing)/landing-analytics' import { getBrandConfig } from '@/ee/whitelabeling' type DropdownId = 'docs' | 'blog' | null @@ -213,7 +213,13 @@ export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps href='/workspace' className='inline-flex h-[30px] items-center gap-[7px] rounded-[5px] border border-[var(--white)] bg-[var(--white)] px-[9px] text-[13.5px] text-black transition-colors hover:border-[#E0E0E0] hover:bg-[#E0E0E0]' aria-label='Go to app' - onClick={() => trackLandingCta({ label: 'Go to App', section: 'navbar', destination: '/workspace' })} + onClick={() => + trackLandingCta({ + label: 'Go to App', + section: 'navbar', + destination: '/workspace', + }) + } > Go to App @@ -223,7 +229,9 @@ export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps href='/login' className='inline-flex h-[30px] items-center rounded-[5px] border border-[var(--landing-border-strong)] px-[9px] text-[13.5px] text-[var(--landing-text)] transition-colors hover:bg-[var(--landing-bg-elevated)]' aria-label='Log in' - onClick={() => trackLandingCta({ label: 'Log in', section: 'navbar', destination: '/login' })} + onClick={() => + trackLandingCta({ label: 'Log in', section: 'navbar', destination: '/login' }) + } > Log in @@ -231,7 +239,13 @@ export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps href='/signup' className='inline-flex h-[30px] items-center gap-[7px] rounded-[5px] border border-[var(--white)] bg-[var(--white)] px-2.5 text-[13.5px] text-black transition-colors hover:border-[#E0E0E0] hover:bg-[#E0E0E0]' aria-label='Get started with Sim' - onClick={() => trackLandingCta({ label: 'Get started', section: 'navbar', destination: '/signup' })} + onClick={() => + trackLandingCta({ + label: 'Get started', + section: 'navbar', + destination: '/signup', + }) + } > Get started @@ -307,7 +321,14 @@ export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps { trackLandingCta({ label: 'Go to App', section: 'navbar', destination: '/workspace' }); setMobileMenuOpen(false) }} + onClick={() => { + trackLandingCta({ + label: 'Go to App', + section: 'navbar', + destination: '/workspace', + }) + setMobileMenuOpen(false) + }} aria-label='Go to app' > Go to App @@ -317,7 +338,10 @@ export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps { trackLandingCta({ label: 'Log in', section: 'navbar', destination: '/login' }); setMobileMenuOpen(false) }} + onClick={() => { + trackLandingCta({ label: 'Log in', section: 'navbar', destination: '/login' }) + setMobileMenuOpen(false) + }} aria-label='Log in' > Log in @@ -325,7 +349,14 @@ export default function Navbar({ logoOnly = false, blogPosts = [] }: NavbarProps { trackLandingCta({ label: 'Get started', section: 'navbar', destination: '/signup' }); setMobileMenuOpen(false) }} + onClick={() => { + trackLandingCta({ + label: 'Get started', + section: 'navbar', + destination: '/signup', + }) + setMobileMenuOpen(false) + }} aria-label='Get started with Sim' > Get started diff --git a/apps/sim/app/(landing)/components/pricing/pricing.tsx b/apps/sim/app/(landing)/components/pricing/pricing.tsx index 5fb7ab759e0..d4d0789467c 100644 --- a/apps/sim/app/(landing)/components/pricing/pricing.tsx +++ b/apps/sim/app/(landing)/components/pricing/pricing.tsx @@ -151,7 +151,13 @@ function PricingCard({ tier }: PricingCardProps) { @@ -160,7 +166,13 @@ function PricingCard({ tier }: PricingCardProps) { trackLandingCta({ label: tier.cta.label, section: 'pricing', destination: tier.cta.href || '/signup' })} + onClick={() => + trackLandingCta({ + label: tier.cta.label, + section: 'pricing', + destination: tier.cta.href || '/signup', + }) + } > {tier.cta.label} @@ -168,7 +180,13 @@ function PricingCard({ tier }: PricingCardProps) { trackLandingCta({ label: tier.cta.label, section: 'pricing', destination: tier.cta.href || '/signup' })} + onClick={() => + trackLandingCta({ + label: tier.cta.label, + section: 'pricing', + destination: tier.cta.href || '/signup', + }) + } > {tier.cta.label} diff --git a/apps/sim/app/(landing)/landing-analytics.tsx b/apps/sim/app/(landing)/landing-analytics.tsx index a061e1b7a59..d79e5faaa52 100644 --- a/apps/sim/app/(landing)/landing-analytics.tsx +++ b/apps/sim/app/(landing)/landing-analytics.tsx @@ -19,8 +19,6 @@ export function LandingAnalytics() { * Fire-and-forget tracker for landing page CTA clicks. * Uses the non-hook client so it works in any click handler without requiring a PostHog provider ref. */ -export function trackLandingCta( - props: PostHogEventMap['landing_cta_clicked'] -): void { +export function trackLandingCta(props: PostHogEventMap['landing_cta_clicked']): void { captureClientEvent('landing_cta_clicked', props) } From 7cf6ac25295f7d4cdae27cd2f7775f04c3c6c4cb Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 6 Apr 2026 12:42:25 -0700 Subject: [PATCH 3/4] fix(landing): correct import ordering per project conventions --- apps/sim/app/(landing)/components/footer/footer-cta.tsx | 2 +- .../components/landing-preview-home/landing-preview-home.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/sim/app/(landing)/components/footer/footer-cta.tsx b/apps/sim/app/(landing)/components/footer/footer-cta.tsx index f9af4ac4bcc..23c08df8f96 100644 --- a/apps/sim/app/(landing)/components/footer/footer-cta.tsx +++ b/apps/sim/app/(landing)/components/footer/footer-cta.tsx @@ -4,9 +4,9 @@ import { useCallback, useRef, useState } from 'react' import { ArrowUp } from 'lucide-react' import Link from 'next/link' import { captureClientEvent } from '@/lib/posthog/client' +import { useAnimatedPlaceholder } from '@/hooks/use-animated-placeholder' import { useLandingSubmit } from '@/app/(landing)/components/landing-preview/components/landing-preview-panel/landing-preview-panel' import { trackLandingCta } from '@/app/(landing)/landing-analytics' -import { useAnimatedPlaceholder } from '@/hooks/use-animated-placeholder' const MAX_HEIGHT = 120 diff --git a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-home/landing-preview-home.tsx b/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-home/landing-preview-home.tsx index aea260a3cb0..d1a36fc3ed5 100644 --- a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-home/landing-preview-home.tsx +++ b/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-home/landing-preview-home.tsx @@ -6,9 +6,9 @@ import { ArrowUp, Table } from 'lucide-react' import { Blimp, Checkbox, ChevronDown } from '@/components/emcn' import { TypeBoolean, TypeNumber, TypeText } from '@/components/emcn/icons' import { captureClientEvent } from '@/lib/posthog/client' +import { useAnimatedPlaceholder } from '@/hooks/use-animated-placeholder' import { useLandingSubmit } from '@/app/(landing)/components/landing-preview/components/landing-preview-panel/landing-preview-panel' import { EASE_OUT } from '@/app/(landing)/components/landing-preview/components/landing-preview-workflow/workflow-data' -import { useAnimatedPlaceholder } from '@/hooks/use-animated-placeholder' const C = { SURFACE: '#292929', From 24a2dd2201d0ce1a8d92d3b3fde29e944e59bf02 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 6 Apr 2026 12:43:03 -0700 Subject: [PATCH 4/4] chore(landing): apply linter import sorting --- apps/sim/app/(landing)/components/footer/footer-cta.tsx | 2 +- .../components/landing-preview-home/landing-preview-home.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/sim/app/(landing)/components/footer/footer-cta.tsx b/apps/sim/app/(landing)/components/footer/footer-cta.tsx index 23c08df8f96..f9af4ac4bcc 100644 --- a/apps/sim/app/(landing)/components/footer/footer-cta.tsx +++ b/apps/sim/app/(landing)/components/footer/footer-cta.tsx @@ -4,9 +4,9 @@ import { useCallback, useRef, useState } from 'react' import { ArrowUp } from 'lucide-react' import Link from 'next/link' import { captureClientEvent } from '@/lib/posthog/client' -import { useAnimatedPlaceholder } from '@/hooks/use-animated-placeholder' import { useLandingSubmit } from '@/app/(landing)/components/landing-preview/components/landing-preview-panel/landing-preview-panel' import { trackLandingCta } from '@/app/(landing)/landing-analytics' +import { useAnimatedPlaceholder } from '@/hooks/use-animated-placeholder' const MAX_HEIGHT = 120 diff --git a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-home/landing-preview-home.tsx b/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-home/landing-preview-home.tsx index d1a36fc3ed5..aea260a3cb0 100644 --- a/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-home/landing-preview-home.tsx +++ b/apps/sim/app/(landing)/components/landing-preview/components/landing-preview-home/landing-preview-home.tsx @@ -6,9 +6,9 @@ import { ArrowUp, Table } from 'lucide-react' import { Blimp, Checkbox, ChevronDown } from '@/components/emcn' import { TypeBoolean, TypeNumber, TypeText } from '@/components/emcn/icons' import { captureClientEvent } from '@/lib/posthog/client' -import { useAnimatedPlaceholder } from '@/hooks/use-animated-placeholder' import { useLandingSubmit } from '@/app/(landing)/components/landing-preview/components/landing-preview-panel/landing-preview-panel' import { EASE_OUT } from '@/app/(landing)/components/landing-preview/components/landing-preview-workflow/workflow-data' +import { useAnimatedPlaceholder } from '@/hooks/use-animated-placeholder' const C = { SURFACE: '#292929',