Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions reflex_ui/blocks/telemetry/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"""Telemetry blocks for the Reflex UI library."""

from .clearbit import get_clearbit_trackers
from .common_room import get_common_room_trackers, identify_common_room_user
from .google import get_google_analytics_trackers
from .koala import get_koala_trackers
from .posthog import get_posthog_trackers
from .rb2b import get_rb2b_trackers

__all__ = [
"get_clearbit_trackers",
"get_common_room_trackers",
"get_google_analytics_trackers",
"get_koala_trackers",
"get_posthog_trackers",
"get_rb2b_trackers",
"identify_common_room_user",
]
22 changes: 22 additions & 0 deletions reflex_ui/blocks/telemetry/clearbit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"""Clearbit analytics tracking integration for Reflex applications."""

import reflex as rx

CLEARBIT_SCRIPT_URL_TEMPLATE: str = (
"https://tag.clearbitscripts.com/v1/{public_key}/tags.js"
)


def get_clearbit_trackers(public_key: str) -> rx.Component:
"""Generate Clearbit tracking component for a Reflex application.

Args:
public_key: Clearbit public key (defaults to app's public key)

Returns:
rx.Component: Script component needed for Clearbit tracking
"""
return rx.el.script(
src=CLEARBIT_SCRIPT_URL_TEMPLATE.format(public_key=public_key),
referrer_policy="strict-origin-when-cross-origin",
)
77 changes: 77 additions & 0 deletions reflex_ui/blocks/telemetry/common_room.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
"""Common Room website visitor tracking integration for Reflex applications."""

import json

import reflex as rx

# Common Room tracking configuration
COMMON_ROOM_CDN_URL_TEMPLATE: str = (
"https://cdn.cr-relay.com/v1/site/{site_id}/signals.js"
)

# Common Room tracking script template
COMMON_ROOM_SCRIPT_TEMPLATE: str = """
(function() {{
if (typeof window === 'undefined') return;
if (typeof window.signals !== 'undefined') return;
var script = document.createElement('script');
script.src = '{cdn_url}';
script.async = true;
window.signals = Object.assign(
[],
['page', 'identify', 'form', 'track'].reduce(function (acc, method) {{
acc[method] = function () {{
signals.push([method, arguments]);
return signals;
}};
return acc;
}}, {{}})
);
document.head.appendChild(script);
}})();
"""


def get_common_room_trackers(site_id: str) -> rx.Component:
"""Generate Common Room tracking component for a Reflex application.

Args:
site_id: Your Common Room site ID (found in your tracking snippet)

Returns:
rx.Component: Script component needed for Common Room tracking
"""
cdn_url = COMMON_ROOM_CDN_URL_TEMPLATE.format(site_id=site_id)

return rx.script(COMMON_ROOM_SCRIPT_TEMPLATE.format(cdn_url=cdn_url))


def identify_common_room_user(
email: str, name: str | None = None
) -> rx.event.EventSpec:
"""Identify a user in Common Room analytics after form submission or login.

This should be called when you have user identity information available,
such as after a form submission or user login.

Args:
email: User's email address
name: User's full name (optional)

Returns:
rx.Component: Script component that identifies the user in Common Room
"""
identify_data = {"email": email}
if name:
identify_data["name"] = name

js_data = json.dumps(identify_data)

return rx.call_script(
f"""
// Identify user in Common Room after form submission or login
if (typeof window.signals !== 'undefined' && window.signals.identify) {{
window.signals.identify({js_data});
}}
"""
)
36 changes: 36 additions & 0 deletions reflex_ui/blocks/telemetry/google.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""Google Analytics tracking integration for Reflex applications."""

import reflex as rx

# Google Tag Manager script template
GTAG_SCRIPT_TEMPLATE: str = """
window.dataLayer = window.dataLayer || [];
function gtag() {{
window.dataLayer.push(arguments);
}}
gtag('js', new Date());
gtag('config', '{tracking_id}');
"""

# Google Tag Manager script URL template
GTAG_SCRIPT_URL_TEMPLATE: str = (
"https://www.googletagmanager.com/gtag/js?id={tracking_id}"
)


def get_google_analytics_trackers(
tracking_id: str,
) -> list[rx.Component]:
"""Generate Google Analytics tracking components for a Reflex application.

Args:
tracking_id: Google Analytics tracking ID (defaults to app's tracking ID)

Returns:
list[rx.Component]: Script components needed for Google Analytics tracking
"""
# Load Google Tag Manager script
return [
rx.script(src=GTAG_SCRIPT_URL_TEMPLATE.format(tracking_id=tracking_id)),
rx.script(GTAG_SCRIPT_TEMPLATE.format(tracking_id=tracking_id)),
]
46 changes: 46 additions & 0 deletions reflex_ui/blocks/telemetry/koala.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"""Koala analytics tracking integration for Reflex applications."""

import reflex as rx

# Koala tracking configuration
KOALA_SCRIPT_URL_TEMPLATE: str = "https://cdn.getkoala.com/v1/{public_api_key}/sdk.js"

# Koala initialization script template
KOALA_SCRIPT_TEMPLATE: str = """
!function(t) {{
if (window.ko) return;
window.ko = [];
[
"identify",
"track",
"removeListeners",
"on",
"off",
"qualify",
"ready"
].forEach(function(t) {{
ko[t] = function() {{
var n = [].slice.call(arguments);
return n.unshift(t), ko.push(n), ko;
}};
}});
var n = document.createElement("script");
n.async = !0;
n.setAttribute("src", "{script_url}");
(document.body || document.head).appendChild(n);
}}();
"""


def get_koala_trackers(public_api_key: str) -> rx.Component:
"""Generate Koala tracking component for a Reflex application.

Args:
public_api_key: Koala public API key

Returns:
rx.Component: Script component needed for Koala tracking
"""
script_url = KOALA_SCRIPT_URL_TEMPLATE.format(public_api_key=public_api_key)

return rx.script(KOALA_SCRIPT_TEMPLATE.format(script_url=script_url))
81 changes: 81 additions & 0 deletions reflex_ui/blocks/telemetry/posthog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
"""PostHog analytics tracking integration for Reflex applications."""

import json

import reflex as rx

# PostHog tracking configuration
POSTHOG_API_HOST: str = "https://us.i.posthog.com"

# PostHog initialization script template
POSTHOG_SCRIPT_TEMPLATE: str = """
!function(t,e){{
var o,n,p,r;
e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){{
function g(t,e){{
var o=e.split(".");
2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){{
t.push([e].concat(Array.prototype.slice.call(arguments,0)))
}}
}}
(p=t.createElement("script")).type="text/javascript",p.async=!0,p.src=s.api_host.replace(".i.posthog.com","-assets.i.posthog.com")+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);
var u=e;
for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){{
var e="posthog";
return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e
}},u.people.toString=function(){{
return u.toString(1)+".people (stub)"
}},o="capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys getNextSurveyStep onSessionId setPersonProperties".split(" "),n=0;n<o.length;n++)g(u,o[n]);
e._i.push([i,s,a])
}},e.__SV=1)
}}(document,window.posthog||[]);

posthog.init('{project_id}', {{
api_host: '{api_host}',
person_profiles: 'always',
session_recording: {{
recordCrossOriginIframes: true,
}}
}});
"""


def identify_posthog_user(user_id: str) -> rx.event.EventSpec:
"""Identify a user in PostHog analytics.

Args:
user_id: Unique identifier for the user

Returns:
rx.event.EventSpec: Event specification for identifying the user in PostHog
"""
user_id = json.dumps(user_id)

return rx.call_script(
f"""
if (typeof posthog !== 'undefined') {{
posthog.identify({user_id});
}}
"""
)


def get_posthog_trackers(
project_id: str,
api_host: str = POSTHOG_API_HOST,
) -> rx.Component:
"""Generate PostHog tracking component for a Reflex application.

Args:
project_id: PostHog project ID (defaults to app's project ID)
api_host: PostHog API host URL (defaults to US instance)

Returns:
rx.Component: Script component needed for PostHog tracking
"""
return rx.script(
POSTHOG_SCRIPT_TEMPLATE.format(
project_id=project_id,
api_host=api_host,
)
)
47 changes: 47 additions & 0 deletions reflex_ui/blocks/telemetry/rb2b.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""RB2B (Reveal Bot to Bot) analytics tracking integration for Reflex applications."""

import reflex as rx

# RB2B tracking script template
RB2B_SCRIPT_TEMPLATE: str = """
!function () {{
var reb2b = window.reb2b = window.reb2b || [];
if (reb2b.invoked) return;
reb2b.invoked = true;
reb2b.methods = ["identify", "collect"];
reb2b.factory = function (method) {{
return function () {{
var args = Array.prototype.slice.call(arguments);
args.unshift(method);
reb2b.push(args);
return reb2b;
}};
}};
for (var i = 0; i < reb2b.methods.length; i++) {{
var key = reb2b.methods[i];
reb2b[key] = reb2b.factory(key);
}}
reb2b.load = function (key) {{
var script = document.createElement("script");
script.type = "text/javascript";
script.async = true;
script.src = "https://s3-us-west-2.amazonaws.com/b2bjsstore/b/" + key + "/reb2b.js.gz";
var first = document.getElementsByTagName("script")[0];
first.parentNode.insertBefore(script, first);
}};
reb2b.SNIPPET_VERSION = "1.0.1";
reb2b.load("{api_key}");
}}();
"""


def get_rb2b_trackers(api_key: str) -> rx.Component:
"""Generate RB2B tracking component for a Reflex application.

Args:
api_key: Your RB2B API key (found in your RB2B dashboard)

Returns:
rx.Component: Script component needed for RB2B tracking
"""
return rx.script(RB2B_SCRIPT_TEMPLATE.format(api_key=api_key))