GrowReach PostHog Audit, Analytics Report & Implementation Guide
Summary: Audit of GrowReach’s PostHog implementation — tracking gaps, event taxonomy, and the recommended setup to make CRO analysis reliable.
Date: July 28, 2026 Author: CRO Agent (via PostHog MCP) Data Window: June 29 – July 28, 2026 (30 days) Project: GrowReach (growreach.app) — AI Engagement Automation SaaS
Table of Contents
- Executive Summary
- For the Product Manager — What’s Happening with Our Visitors & Users
- For the Development Team — Technical Issues to Fix
- For the Designer — UI/UX Improvements Needed
- PostHog Implementation Guide — Complete Setup for Dev Team
- Appendix: Raw Data Tables
1. Executive Summary
The Big Picture
Over the last 30 days, 239 unique visitors came to GrowReach. Of those:
- 16 signed up (6.7% conversion)
- 4 paid (1.7% conversion)
- 101 hit a JavaScript error (42% of all visitors)
- 44.3% bounced without viewing a second page
The #1 Problem: A TypeError Is Breaking the Site for Half Your Visitors
1,864 JavaScript exceptions hit 101 unique users in 30 days. 99% are TypeErrors. The homepage alone has 938 TypeErrors affecting 76 users — that’s ~49% of homepage visitors hitting a broken page.
This is almost certainly a null reference error in a JavaScript file (likely a WordPress theme or plugin script). The error message property ($exception_message) isn’t captured in the PostHog taxonomy, so we can’t see the exact error text from analytics — you need to open the browser console on growreach.app to find it.
Conversion Funnel at a Glance
239 visitors → 154 homepage views → 11 clicked "Start Free Trial" → 16 signed up → 4 paid
Key drop-offs:
- Homepage → CTA click: 92.9% drop-off (only 7.1% click the primary CTA)
- Pricing page: 57.1% bounce rate
- US visitors: 68.4% bounce rate (vs 41.9% for India)
- Mobile: 53.2% bounce rate (vs 38.2% desktop)
What’s Working
- Trial-to-paid conversion is healthy: 4 paid from 16 signups (25%)
- Reddit is driving real traffic: 31 users from Reddit (web + app)
- AI observability is set up: 8 insights tracking costs, latency, errors
- Autocapture is working: Pageviews, clicks, exceptions all captured
What’s Missing
- No custom
user_signed_upevent — can’t build accurate retention cohorts - No Actions defined — can’t group related events or rename anything
- No UTM tracking on 99% of traffic — can’t attribute any campaigns
- No session recordings visible — can’t see what users actually experience
- No dashboards for marketing or conversion — only AI observability dashboard exists
- No feature flags or experiments — can’t A/B test anything
2. For the Product Manager
What’s Happening with Our Website Visitors
Traffic Overview (30 Days)
| Metric | Value |
|---|---|
| Unique Visitors | 239 |
| Total Pageviews | 1,002 |
| Sessions | 406 |
| Avg Session Duration | 5m 38s |
| Bounce Rate | 44.3% |
| Signups | 16 (6.7%) |
| Paid Conversions | 4 (1.7%) |
Where Are Our Visitors Coming From?
| Channel | Visitors | % of Total | Bounce Rate |
|---|---|---|---|
| Direct | 159 | 64.6% | 41.7% |
| Organic Social | 40 | 16.3% | 61.0% |
| Organic Search (Google) | 23 | 9.3% | 40.7% |
| Referral | 22 | 8.9% | 45.7% |
| AI (chatgpt.com) | 2 | 0.8% | 100% |
External referrers by source:
- Google organic search: 21 users
- Reddit (web): 16 users
- Reddit (mobile app): 15 users
- LinkedIn (web): 8 users
- LinkedIn (mobile app): 2 users
Note: Reddit is our #2 external traffic source (31 users combined). This channel is working — keep investing in it.
Where Are Our Visitors From?
| Country | Visitors | % | Bounce Rate |
|---|---|---|---|
| India | 70 | 29.8% | 41.9% |
| United States | 54 | 23.0% | 68.4% |
| Indonesia | 21 | 8.9% | 25.0% |
| UAE | 15 | 6.4% | 33.3% |
| China | 15 | 6.4% | 100% |
| Germany | 9 | 3.8% | 22.2% |
| UK | 6 | 2.6% | 19.2% |
⚠️ US visitors have 68.4% bounce rate — nearly 1.6x higher than India. The site may not resonate with US audience. This needs investigation.
Device Breakdown
| Device | Visitors | % | Bounce Rate |
|---|---|---|---|
| Desktop | 135 | 58.7% | 38.2% |
| Mobile | 95 | 41.3% | 53.2% |
⚠️ Mobile bounce rate is 15 percentage points higher than desktop. Mobile also gets heavy TypeErrors (279 from 24 users on Mobile Safari).
Page Performance
| Page | Pageviews | Users | Bounce Rate | Avg Time |
|---|---|---|---|---|
| Homepage (/) | 317 | 154 | 55.7% | ~4s |
| Pricing | 62 | 25 | 57.1% | ~4.2s |
| Build My Personal Brand | 35 | 10 | 0% | ~1s |
| Generate Leads | 11 | 4 | 0% | ~0.02s |
| Comparisons (TryKondo) | 6 | 5 | — | — |
| Features | 4 | 4 | 0% | ~0.02s |
Homepage has 55.7% bounce rate and average time of only ~4 seconds. The pricing page is even worse at 57.1% bounce.
Homepage CTA Performance
| CTA Element | Clicks | Unique Users | CTR (of 154 visitors) |
|---|---|---|---|
| Pricing | 21 | 16 | 10.4% |
| Sign In | 13 | 11 | 7.1% |
| I Want To Build My Brand | 13 | 7 | 4.5% |
| Start 14-Day Free Trial | 12 | 11 | 7.1% |
| I want to Generate Leads | 9 | 4 | 2.6% |
| Watch Demo | 5 | 5 | 3.2% |
| Features | 3 | 3 | 1.9% |
The primary CTA “Start 14-Day Free Trial” gets only 7.1% CTR. “Pricing” actually gets more clicks (21 vs 12). The persona buttons (“Build My Brand” + “Generate Leads”) combined get 22 clicks — nearly 2x the primary CTA. This suggests visitors want to understand the product before committing to a trial.
Signup & Conversion Funnel
| Step | Users | % of Visitors |
|---|---|---|
| Any pageview | 239 | 100% |
| Homepage visit | 154 | 64.4% |
| Pricing page visit | 25 | 10.5% |
| Clicked “Start Free Trial” | 11 | 4.6% |
| Email registered | 16 | 6.7% |
| Persona configured | 14 | 5.9% |
| LinkedIn connected | 6 | 2.5% |
| Paid plan purchased | 4 | 1.7% |
Note: More people signed up (16) than clicked “Start Free Trial” (11). This means some users are signing up through other paths (direct /start page access, sign-in page). The funnel isn’t linear.
Error Impact on Business
1,864 TypeErrors in 30 days. If even 10% of those 99 affected users would have converted without the error, that’s ~10 lost signups. At 69/mo, that’s 690/mo in directly lost revenue from a single JavaScript bug.
3. For the Development Team
Technical Issues to Fix — Prioritized
🔴 P0: Fix Homepage TypeError (Do Today)
The Problem: 938 TypeErrors on the homepage affecting 76 users. 441 more on the pricing page. 1,845 total TypeErrors from 99 users.
What We Know:
- Error type:
TypeError(confirmed via$exception_typesproperty) - Cross-browser: Chrome (873), Brave (306), Mobile Safari (279), Edge (270), Firefox (60)
- Cross-OS: Mac (833), Android (360), iOS (309), Windows (278), Linux (74)
- Concentrated on: Homepage (938), Pricing page (441), Build My Personal Brand page (257)
- The
$exception_messageproperty is NOT in the PostHog taxonomy — we can’t see the exact error text from analytics
How to Debug:
- Open
https://growreach.app/in Chrome DevTools → Console tab - Look for red
TypeErrormessages — they’ll show the exact file, line number, and error text - Common causes:
Cannot read properties of null(reading ‘classList’ or ‘addEventListener’), a missing DOM element that a script expects - Check WordPress theme’s
homepage.js,main.js, or any third-party plugin scripts - Test in incognito mode to rule out extension conflicts
Fix: Add a null check before the failing operation. This is likely a 1-line fix.
// Before (likely what's breaking):
header.classList.add('sticky');
// After (fix):
if (header) {
header.classList.add('sticky');
}Expected Impact: Fixing this alone could recover 5-10% of lost conversions.
🔴 P0: Add user_signed_up Custom Event
The Problem: We’re using email_registered_on_signup as our signup event, but PostHog’s autocapture can’t give us a reliable signup event. We need an explicit custom event from both frontend and backend.
What to Do:
Add this to your signup success handler (frontend):
posthog.capture('user_signed_up', {
signup_method: 'email', // or 'google', 'linkedin'
plan_type: 'free_trial', // or 'free', 'paid'
referral_source: 'direct', // or 'reddit', 'google', etc.
is_first_time: true
});
// Also identify the user
posthog.identify('user_distinct_id', {
email: 'user@example.com',
name: 'John Doe',
plan: 'free_trial',
signup_date: '2026-07-28'
});Also add backend confirmation (Node.js):
client.capture({
distinctId: 'user_distinct_id',
event: 'user_signed_up',
properties: {
signup_method: 'email',
plan_type: 'free_trial',
is_first_time: true
}
});🔴 P0: Create Actions in PostHog
The Problem: Zero Actions defined. Actions are how you group related events, rename events, and create conversion goals.
What to Do: Go to Data Management → Actions in PostHog and create:
| Action Name | Events to Group | Purpose |
|---|---|---|
Signup Completed | email_registered_on_signup + user_signed_up | Single signup metric |
Homepage CTA Clicked | All autocapture clicks on “Start 14-Day Free Trial”, “Pricing”, “Sign In” | Track CTA effectiveness |
Onboarding Started | persona_settings_configured | Funnel step |
LinkedIn Connected | linkedin_account_connected | Funnel step |
Paid Conversion | free_plan_purchased + paid_plan_purchased | Revenue tracking |
🟡 P1: Add UTM Parameters to All Outbound Links
The Problem: 99% of traffic has no UTM source. We can’t attribute any campaigns.
What to Do: Add UTMs to every link you share:
https://growreach.app/?utm_source=reddit&utm_medium=social&utm_campaign=launch_post
https://growreach.app/?utm_source=linkedin&utm_medium=social&utm_campaign=profile_bio
https://growreach.app/?utm_source=google&utm_medium=organic&utm_campaign=seo
https://growreach.app/?utm_source=twitter&utm_medium=social&utm_campaign=tweet
PostHog automatically captures: utm_source, utm_medium, utm_campaign, utm_content, utm_term, gclid, fbclid, msclkid.
🟡 P1: Enable Session Recordings
The Problem: We can’t see what users actually experience on the site. Session recordings would show us exactly where they get stuck.
What to Do: Check your PostHog JS config. Ensure disable_session_recording is NOT set to true:
posthog.init('<token>', {
api_host: 'https://eu.i.posthog.com',
// Make sure this is NOT set:
// disable_session_recording: false, // default is false — good
session_recording: {
maskAllInputs: true,
maskTextSelector: '.ph-no-capture'
}
});Also enable in Project Settings → Session Recording → Record user sessions.
🟡 P1: Set Up a Reverse Proxy
The Problem: Ad blockers and tracking protection (especially on Safari and Firefox) can block PostHog events. A reverse proxy sends events through your own domain.
What to Do:
# Nginx config — add to your server block
location /ph/ {
proxy_pass https://eu.i.posthog.com/;
proxy_set_header Host eu.i.posthog.com;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}Then update PostHog init:
posthog.init('<token>', {
api_host: 'https://growreach.app/ph', // Your domain
});🟡 P1: Fix Exception Message Capture
The Problem: The $exception_message property isn’t in the PostHog taxonomy. We can only see error types (e.g., “TypeError”) but not the actual error text.
What to Do: Update to the latest posthog-js SDK version. The $exception_list property (available in newer versions) contains the actual error message in the value field. You can then query:
SELECT
properties.$exception_list[1].type AS error_type,
properties.$exception_list[1].value AS error_message,
count() AS count
FROM events
WHERE event = '$exception'
AND timestamp >= now() - INTERVAL 7 DAY
GROUP BY error_type, error_message
ORDER BY count DESC🟢 P2: Standardize Event Naming Convention
Adopt PostHog’s recommended [object] [verb] format:
| Current Name | Recommended Name | Properties |
|---|---|---|
email_registered_on_signup | user signed_up | signup_method, plan_type, referral_source |
persona_settings_configured | persona configured | persona_type, industry |
linkedin_account_connected | linkedin connected | account_type |
paid_plan_purchased | plan purchased | plan_tier, price, billing_cycle |
commenting_voice_configured | voice configured | voice_type, tone |
Use Actions to group old + new names so you don’t lose historical data.
🟢 P2: Add More Custom Events for Key Actions
Track these additional events to get full visibility:
// Pricing page interactions
posthog.capture('pricing viewed', { plan_tier: 'pro', page: 'pricing' });
posthog.capture('pricing plan_selected', { plan_tier: 'pro', billing: 'monthly' });
// Feature page engagement
posthog.capture('feature viewed', { feature: 'linkedin-comments', page: '/features/' });
// Comparison page engagement
posthog.capture('comparison viewed', { competitor: 'trykondo', page: '/comparisons/' });
// Free tool usage
posthog.capture('free_tool used', { tool: 'linkedin-carousel-generator' });
// Demo request
posthog.capture('demo requested', { source: 'homepage_cta' });4. For the Designer
UI/UX Improvements Needed on Web Pages
Based on the analytics data, here are specific design improvements that could increase conversion:
4.1 Homepage — Above the Fold
Problem: 55.7% bounce rate, average time ~4 seconds. Visitors aren’t staying long enough to understand the value proposition.
Data:
- “Start 14-Day Free Trial” CTA gets only 7.1% CTR (12 clicks from 154 visitors)
- “Pricing” gets more clicks (21) than the primary CTA
- Persona buttons (“Build My Brand” + “Generate Leads”) combined get 22 clicks — nearly 2x the primary CTA
Recommendations:
-
Make the value proposition instantly scannable — 4 seconds is not enough time to read paragraphs. Use a bold headline + 3 bullet benefits max.
-
Test moving the persona buttons above the fold — They’re getting more engagement than the primary CTA. Consider making them the primary interaction point.
-
Add social proof near the CTA — Number of users, testimonials, or logos build trust before commitment.
-
Consider an inline email capture — A simple “Get early access” email field above the fold could capture visitors who aren’t ready to commit to a 14-day trial.
-
“Watch Demo” only gets 5 clicks — Either the button isn’t visible enough, or it doesn’t lead to an actual demo. Check where it goes.
4.2 Pricing Page
Problem: 57.1% bounce rate, 73.9% exit rate. Only 4 of 25 visitors click through to trial.
Data:
- 441 TypeErrors on this page (23 users affected)
- Quarterly (-20%) and Yearly (-40%) badges get clicks but don’t convert
- “Continue With Free” gets 7 clicks
Recommendations:
-
Fix the TypeError first — 92% of pricing page visitors hit a JS error. No design fix matters until this is resolved.
-
Add a comparison table or feature highlights — Visitors clicking “Pricing” from the homepage want to understand what they get. Make feature differentiation between tiers obvious.
-
Add a “Most Popular” badge — Standard SaaS pattern that guides decision-making.
-
Consider a monthly vs annual toggle — Currently showing both side by side with discount badges. A toggle is cleaner and reduces cognitive load.
-
Add FAQ below pricing — Common questions about cancellation, LinkedIn safety, and results timeline are already on the homepage. Move them to the pricing page where they’re more relevant.
4.3 Mobile Experience
Problem: 53.2% bounce rate (vs 38.2% desktop). Mobile Safari has 279 TypeErrors from 24 users.
Recommendations:
-
Test the full mobile flow — Open growreach.app on an iPhone Safari. If the TypeError breaks the page, mobile users see a broken site.
-
Ensure CTA buttons are thumb-friendly — Minimum 48px touch target, adequate spacing between buttons.
-
Reduce above-the-fold content — Mobile screens have limited real estate. Prioritize the value prop and one primary CTA.
-
Test page load speed on 4G — Mobile users on slower connections may leave before the page finishes loading.
4.4 General Design Improvements
-
“Start 14-Day Free Trial” vs “Pricing” — The fact that “Pricing” gets more clicks suggests visitors want to evaluate before committing. Consider:
- Adding pricing information to the homepage hero
- Testing “See Plans & Pricing” as the primary CTA
- Adding a “Free forever” or “No credit card required” trust signal
-
Persona-based onboarding is working — The “I Want To Build My Brand” and “I want to Generate Leads” buttons get strong engagement. Consider making this the primary navigation pattern.
-
Trust signals are needed — Questions about LinkedIn safety and cancellation appear in FAQ clicks. Surface these concerns earlier in the experience.
5. PostHog Implementation Guide
Complete Setup Checklist for the Dev Team
Phase 1: Fix Critical Issues (This Week)
- Fix homepage TypeError — Debug and fix the null reference JS error
- Add
user_signed_upcustom event — Frontend + backend - Create Actions — Signup Completed, Homepage CTA Clicked, Onboarding Started, LinkedIn Connected, Paid Conversion
- Add UTM parameters to all outbound links
Phase 2: Build Analytics Foundation (This Month)
- Enable session recordings — Config + project settings
- Set up reverse proxy — Nginx config for
/ph/endpoint - Fix exception message capture — Update posthog-js SDK
- Create Growth Funnel dashboard — Pageview → Signup → Onboarding → LinkedIn → Paid
- Create Marketing dashboard — Traffic by channel, country, device, bounce rate
- Create Error Monitoring dashboard — TypeError count, error rate by page, rageclicks
- Create Revenue dashboard — Signup → Paid conversion, plan distribution
Phase 3: Advanced Features (Next Quarter)
- Standardize event naming — Adopt
[object] [verb]convention - Add custom events for pricing, features, comparisons, free tools, demo requests
- Enable Marketing Analytics beta — Connect ad platforms
- Set up A/B testing with feature flags
- Add user surveys — Exit intent, post-signup, NPS
- Create cohorts — Trial users, power users, US visitors, mobile visitors
- Save HogQL views — Daily error rate, signup funnel, mobile vs desktop conversion
PostHog JS Config (Reference)
posthog.init('<ph_project_token>', {
api_host: 'https://eu.i.posthog.com', // EU region
// After reverse proxy:
// api_host: 'https://growreach.app/ph',
// Recommended defaults for new projects
defaults: '2026-05-30',
// Session recording
session_recording: {
maskAllInputs: true,
maskTextSelector: '.ph-no-capture'
},
// Exception autocapture (enabled by default in recent versions)
// enableExceptionAutocapture: true,
// Person profiles
person_profiles: 'identified_only', // or 'always'
});Key HogQL Queries to Save as Views
Daily TypeError Rate:
SELECT
toStartOfDay(timestamp) AS day,
count() AS errors,
count(DISTINCT person_id) AS affected_users
FROM events
WHERE event = '$exception'
AND timestamp >= now() - INTERVAL 30 DAY
GROUP BY day
ORDER BY daySignup Funnel with Error Impact:
SELECT
countIf(event = '$pageview') AS pageviews,
countIf(event = 'email_registered_on_signup') AS signups,
countIf(event = 'paid_plan_purchased') AS paid,
countIf(event = '$exception') AS errors
FROM events
WHERE timestamp >= now() - INTERVAL 30 DAYMobile vs Desktop Conversion:
SELECT
multiIf(
properties.$device_type = 'Desktop', 'Desktop',
properties.$device_type = 'Mobile', 'Mobile',
'Other'
) AS device_type,
count(DISTINCT person_id) AS visitors,
countIf(event = 'email_registered_on_signup') AS signups
FROM events
WHERE timestamp >= now() - INTERVAL 30 DAY
AND event IN ('$pageview', 'email_registered_on_signup')
GROUP BY device_type6. Appendix
Raw Data Tables
A. Exception Types (30 days)
| Exception Type | Count | Affected Users |
|---|---|---|
| TypeError | 1,845 | 99 |
| Error | 12 | 4 |
| ReferenceError | 4 | 2 |
| SyntaxError | 2 | 2 |
| UnhandledRejection | 1 | 1 |
| Total | 1,864 | 101 |
B. TypeErrors by Page
| Page | TypeErrors | Affected Users |
|---|---|---|
| Homepage (/) | 938 | 76 |
| Pricing page | 441 | 23 |
| Build My Personal Brand | 257 | 10 |
| Generate Leads from Comments | 65 | 3 |
| Features | 6 | 3 |
C. TypeErrors by Browser
| Browser | Exceptions | Users |
|---|---|---|
| Chrome | 873 | 49 |
| Brave | 306 | 11 |
| Mobile Safari | 279 | 24 |
| Microsoft Edge | 270 | 5 |
| Firefox | 60 | 6 |
| Chrome iOS | 39 | 3 |
| Safari | 27 | 2 |
D. TypeErrors by OS
| OS | Exceptions | Users |
|---|---|---|
| Mac OS X | 833 | 28 |
| Android | 360 | 24 |
| iOS | 309 | 25 |
| Windows | 278 | 14 |
| Linux | 74 | 10 |
E. Signup & Conversion Events (30 days)
| Event | Count | Unique Users |
|---|---|---|
| email_registered_on_signup | 16 | 16 |
| persona_settings_configured | 14 | 14 |
| linkedin_profile_url_submitted_on_signup | 13 | 13 |
| is_manual_commenting_configured | 8 | 8 |
| linkedin_account_connected | 6 | 6 |
| paid_plan_purchased | 4 | 4 |
| commenting_voice_configured | 2 | 1 |
| free_plan_purchased | 1 | 1 |
F. $identify Events (30 days)
| Metric | Value |
|---|---|
| Total $identify events | 37 |
| Unique identified users | 22 |
G. Rageclicks (30 days)
| Metric | Value |
|---|---|
| Total rageclick events | 48 |
| Affected users | 16 |
H. Existing PostHog Insights
| Insight Name | Created |
|---|---|
| Generations by HTTP status | Jul 23 |
| Generation latency by model (median) | Jul 23 |
| AI Errors | Jul 23 |
| Generation calls | Jul 23 |
| Cost by model (USD) | Jul 23 |
| Cost per user (USD) | Jul 23 |
| Total cost (USD) | Jul 23 |
| Generative AI users | Jul 23 |
| Traces | Jul 23 |
| Pageview funnel, by browser | Mar 6 |
| Referring domain (last 14 days) | Mar 6 |
| Growth accounting | Mar 6 |
| Retention | Mar 6 |
| Weekly active users (WAUs) | Mar 6 |
| Daily active users (DAUs) | Mar 6 |
I. Existing Dashboards
| Dashboard Name | Created |
|---|---|
| AI observability default | Jul 23 |
| PROD Dashboard | Mar 6 |
Related
Report generated by CRO Agent via PostHog MCP. Data source: PostHog EU Cloud, Project ID 136693 (GrowReach PROD).