Skip to content

Commit e7a244d

Browse files
authored
update telemetry (#68)
1 parent 9736a64 commit e7a244d

File tree

4 files changed

+110
-6
lines changed

4 files changed

+110
-6
lines changed

reflex_ui/blocks/demo_form.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@
55
based on company size.
66
"""
77

8+
from typing import Any
9+
810
import reflex as rx
911
from reflex.event import EventType
1012
from reflex.experimental.client_state import ClientStateVar
1113
from reflex.vars.base import get_unique_variable_name
1214

1315
import reflex_ui as ui
16+
from reflex_ui.blocks.telemetry.posthog import track_demo_form_posthog_submission
1417

1518
demo_form_error_message = ClientStateVar.create("demo_form_error_message", "")
1619
demo_form_open_cs = ClientStateVar.create("demo_form_open", False)
@@ -85,6 +88,15 @@ def validate_email(self, email: str):
8588
else:
8689
yield demo_form_error_message.push("")
8790

91+
@rx.event
92+
def track_demo_form_posthog(self, form_data: dict[str, Any]):
93+
"""Send demo form fields to PostHog (identify + capture) in the browser.
94+
95+
Returns:
96+
Event that runs PostHog identify and capture in the browser.
97+
"""
98+
return track_demo_form_posthog_submission(form_data)
99+
88100

89101
def input_field(
90102
label: str,
@@ -327,8 +339,10 @@ def demo_form(id_prefix: str = "", **props) -> rx.Component:
327339
"@container flex flex-col lg:gap-6 gap-2 p-6",
328340
props.pop("class_name", ""),
329341
),
330-
# Close the dialog when the form is submitted
331-
on_submit=demo_form_open_cs.set_value(False),
342+
on_submit=[
343+
DemoFormStateUI.track_demo_form_posthog,
344+
rx.call_function(demo_form_open_cs.set_value(False)),
345+
],
332346
data_default_form_id="965991",
333347
**props,
334348
)

reflex_ui/blocks/intro_form.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@
66
from typing import Any
77

88
import reflex as rx
9-
from reflex.event import EventType
9+
from reflex.event import EventType, IndividualEventType
1010
from reflex.experimental.client_state import ClientStateVar
1111
from reflex.vars.base import get_unique_variable_name
1212

1313
import reflex_ui as ui
14+
from reflex_ui.blocks.telemetry.posthog import track_intro_form_posthog_submission
1415

1516
intro_form_error_message = ClientStateVar.create("intro_form_error_message", "")
1617
intro_form_open_cs = ClientStateVar.create("intro_form_open", False)
@@ -86,6 +87,15 @@ def validate_email(self, email: str):
8687
else:
8788
yield intro_form_error_message.push("")
8889

90+
@rx.event
91+
def track_intro_form_posthog(self, form_data: dict[str, Any]):
92+
"""Send intro form fields to PostHog (identify + capture) in the browser.
93+
94+
Returns:
95+
Event that runs PostHog identify and capture in the browser.
96+
"""
97+
return track_intro_form_posthog_submission(form_data)
98+
8999

90100
def input_field(
91101
label: str,
@@ -241,7 +251,7 @@ def select_field(
241251

242252
def intro_form(
243253
id_prefix: str = "",
244-
on_submit: EventType[dict[str, Any]] | EventType[()] | None = None,
254+
on_submit: EventType[dict[str, Any]] | None = None,
245255
**props,
246256
) -> rx.Component:
247257
"""Create and return the intro form component.
@@ -261,6 +271,11 @@ def intro_form(
261271
"""
262272
prefix = id_prefix or get_unique_variable_name()
263273
email_id = f"{prefix}_user_email"
274+
275+
extra: list[IndividualEventType[dict[str, Any]]] = (
276+
on_submit if isinstance(on_submit, list) else [on_submit] if on_submit else []
277+
)
278+
264279
form = rx.el.form(
265280
rx.el.div(
266281
input_field("First name", "John", "first_name", "text", True),
@@ -340,7 +355,7 @@ def intro_form(
340355
"@container flex flex-col lg:gap-6 gap-2 p-6",
341356
props.pop("class_name", ""),
342357
),
343-
on_submit=on_submit,
358+
on_submit=[IntroFormStateUI.track_intro_form_posthog, *extra],
344359
**props,
345360
)
346361
return rx.fragment(
@@ -351,7 +366,7 @@ def intro_form(
351366
def intro_form_dialog(
352367
trigger: rx.Component | None = None,
353368
id_prefix: str = "",
354-
on_submit: EventType[dict[str, Any]] | EventType[()] | None = None,
369+
on_submit: EventType[dict[str, Any]] | None = None,
355370
**props,
356371
) -> rx.Component:
357372
"""Return a intro form dialog container element.

reflex_ui/blocks/telemetry/posthog.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""PostHog analytics tracking integration for Reflex applications."""
22

33
import json
4+
from typing import Any
45

56
import reflex as rx
67

@@ -60,6 +61,76 @@ def identify_posthog_user(user_id: str) -> rx.event.EventSpec:
6061
)
6162

6263

64+
def _track_form_posthog(
65+
event_name: str,
66+
form_data: dict[str, Any],
67+
allowed_keys: set[str],
68+
) -> rx.event.EventSpec:
69+
"""Identify the submitter and capture a form event in PostHog.
70+
71+
Args:
72+
event_name: PostHog event name to capture.
73+
form_data: Submitted form fields as a string-keyed dict.
74+
allowed_keys: Set of keys to include from form_data.
75+
76+
Returns:
77+
Event that runs PostHog identify and capture in the browser.
78+
"""
79+
filtered = {k: v for k, v in form_data.items() if k in allowed_keys}
80+
props_json = json.dumps(filtered)
81+
return rx.call_script(
82+
f"""
83+
if (typeof posthog !== 'undefined') {{
84+
const props = {props_json};
85+
const distinctId = props.email || ('anon_' + String(Date.now()));
86+
posthog.identify(distinctId, {{
87+
email: props.email,
88+
first_name: props.first_name,
89+
last_name: props.last_name,
90+
job_title: props.job_title,
91+
company_name: props.company_name,
92+
}});
93+
posthog.capture('{event_name}', props);
94+
}}
95+
"""
96+
)
97+
98+
99+
_COMMON_KEYS = {
100+
"email",
101+
"first_name",
102+
"last_name",
103+
"job_title",
104+
"company_name",
105+
"number_of_employees",
106+
"how_did_you_hear_about_us",
107+
"internal_tools",
108+
"technical_level",
109+
}
110+
111+
112+
def track_demo_form_posthog_submission(form_data: dict[str, Any]) -> rx.event.EventSpec:
113+
"""Capture a demo_request event in PostHog.
114+
115+
Returns:
116+
Event that runs PostHog identify and capture in the browser.
117+
"""
118+
return _track_form_posthog("demo_request", form_data, _COMMON_KEYS)
119+
120+
121+
def track_intro_form_posthog_submission(
122+
form_data: dict[str, Any],
123+
) -> rx.event.EventSpec:
124+
"""Capture an intro_submit event in PostHog.
125+
126+
Returns:
127+
Event that runs PostHog identify and capture in the browser.
128+
"""
129+
return _track_form_posthog(
130+
"intro_submit", form_data, _COMMON_KEYS | {"phone_number"}
131+
)
132+
133+
63134
def get_posthog_trackers(
64135
project_id: str,
65136
api_host: str = POSTHOG_API_HOST,

shared/reflex_ui_shared/telemetry/pixels.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from reflex_ui.blocks.telemetry import (
66
get_default_telemetry_script,
77
get_google_analytics_trackers,
8+
get_posthog_trackers,
89
get_unify_trackers,
910
gtag_report_conversion,
1011
)
@@ -19,4 +20,7 @@ def get_pixel_website_trackers() -> list[rx.Component]:
1920
),
2021
get_unify_trackers(),
2122
get_default_telemetry_script(),
23+
get_posthog_trackers(
24+
project_id="phc_JoMo0fOyi0GQAooY3UyO9k0hebGkMyFJrrCw1Gt5SGb"
25+
),
2226
]

0 commit comments

Comments
 (0)