Skip to content

Commit

Permalink
Add posthog component
Browse files Browse the repository at this point in the history
  • Loading branch information
matheusgr committed Sep 11, 2024
1 parent 475157f commit 23569c6
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 0 deletions.
112 changes: 112 additions & 0 deletions analytics/components/PostHog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { Head } from "$fresh/runtime.ts";
import { useScriptAsDataURI } from "deco/hooks/useScript.ts";

export interface Props {
/**
* @description posthog identifier.
*/
projectAPIKey: string;
/**
* @description posthog api host. Default to: https://us.i.posthog.com.
*/
apiHost?: string;
/**
* @description create profiles for anonymous users as well.
*/
anonUsers?: boolean;
}

declare global {
interface Window {
posthog: {
capture: (
name: string,
values: Record<string, string | boolean>,
) => void;
};
}
}

// This function should be self contained, because it is stringified!
const snippet = () => {
// Flags and additional dimentions
const props: Record<string, string> = {};

const trackPageview = () =>
globalThis.window.posthog?.capture("pageview", props);

// Attach pushState and popState listeners
const originalPushState = history.pushState;
if (originalPushState) {
history.pushState = function () {
// @ts-ignore monkey patch
originalPushState.apply(this, arguments);
trackPageview();
};
addEventListener("popstate", trackPageview);
}

// 2000 bytes limit
const truncate = (str: string) => `${str}`.slice(0, 990);

// setup plausible script and unsubscribe
globalThis.window.DECO.events.subscribe((event) => {
if (!event || event.name !== "deco") return;

if (event.params) {
const { flags, page } = event.params;
if (Array.isArray(flags)) {
for (const flag of flags) {
props[flag.name] = truncate(flag.value.toString());
}
}
props["pageId"] = truncate(`${page.id}`);
}

trackPageview();
})();

globalThis.window.DECO.events.subscribe((event) => {
if (!event) return;

const { name, params } = event;

if (!name || !params || name === "deco") return;

const values = { ...props };
for (const key in params) {
// @ts-expect-error somehow typescript bugs
const value = params[key];

if (value !== null && value !== undefined) {
values[key] = truncate(
typeof value !== "object" ? value : JSON.stringify(value),
);
}
}

globalThis.window.posthog?.capture(name, values);
});
};

function Component({ projectAPIKey, apiHost, anonUsers }: Props) {
apiHost ??= "https://us.i.posthog.com";
return (
<Head>
<link rel="dns-prefetch" href={apiHost} />
<link
rel="preconnect"
href={apiHost}
crossOrigin="anonymous"
/>
<script dangerouslySetInnerHTML={{
__html: `!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="init capture register register_once register_for_session unregister unregister_for_session getFeatureFlag getFeatureFlagPayload isFeatureEnabled reloadFeatureFlags updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures on onFeatureFlags onSessionId getSurveys getActiveMatchingSurveys renderSurvey canRenderSurvey getNextSurveyStep identify setPersonProperties group resetGroups setPersonPropertiesForFlags resetPersonPropertiesForFlags setGroupPropertiesForFlags resetGroupPropertiesForFlags reset get_distinct_id getGroups get_session_id get_session_replay_url alias set_config startSessionRecording stopSessionRecording sessionRecordingStarted captureException loadToolbar get_property getSessionProperty createPersonProfile opt_in_capturing opt_out_capturing has_opted_in_capturing has_opted_out_capturing clear_opt_in_out_capturing debug".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('${projectAPIKey}',{api_host:'${apiHost}', person_profiles: '${
anonUsers ? "always" : "identified_only"}'})`}}>
</script>
<script defer src={useScriptAsDataURI(snippet)} />
</Head>
);
}

export default Component;
2 changes: 2 additions & 0 deletions analytics/manifest.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@

import * as $$$0 from "./loaders/DecoAnalyticsScript.ts";
import * as $$$$$$0 from "./sections/Analytics/DecoAnalytics.tsx";
import * as $$$$$$1 from "./sections/Analytics/PostHog.tsx";

const manifest = {
"loaders": {
"analytics/loaders/DecoAnalyticsScript.ts": $$$0,
},
"sections": {
"analytics/sections/Analytics/DecoAnalytics.tsx": $$$$$$0,
"analytics/sections/Analytics/PostHog.tsx": $$$$$$1,
},
"name": "analytics",
"baseUrl": import.meta.url,
Expand Down
14 changes: 14 additions & 0 deletions analytics/sections/Analytics/PostHog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import PostHog, { type Props } from "../../components/PostHog.tsx";

function Section(props: Props) {
return <PostHog {...props} />;
}

export const Preview = () => (
<iframe
style="width: 100%; height: 100vh; border: none;"
src="https://posthog.com/"
/>
);

export default Section;

0 comments on commit 23569c6

Please sign in to comment.