diff --git a/src/components/blocks/company/lead-form-client.ts b/src/components/blocks/company/lead-form-client.ts
index 4053aa1..9033cf9 100644
--- a/src/components/blocks/company/lead-form-client.ts
+++ b/src/components/blocks/company/lead-form-client.ts
@@ -75,6 +75,7 @@ function wire(root: HTMLElement) {
});
const data = (await res.json().catch(() => ({}))) as LeadResponse;
if (res.ok && data.ok) {
+ (window as unknown as { posthog?: { capture: (e: string, p?: object) => void } }).posthog?.capture("lead_submitted", { form: form.getAttribute("action") });
form.reset();
root.dataset.state = "done";
donePanel?.focus();
diff --git a/src/components/chat/chat-widget-client.ts b/src/components/chat/chat-widget-client.ts
index a16f63e..73bd017 100644
--- a/src/components/chat/chat-widget-client.ts
+++ b/src/components/chat/chat-widget-client.ts
@@ -207,6 +207,8 @@ export function initChatWidget() {
if (!clean) return;
render({ role: "user", text: clean, at: Date.now() });
suggest.hidden = true;
+ // "Thinking" dots right away; the server's typing/delta/message frames take it from here.
+ showTyping();
send({ type: "message", text: clean });
};
diff --git a/src/components/layout/CookieBadge.astro b/src/components/layout/CookieBadge.astro
index 83ae049..3814b21 100644
--- a/src/components/layout/CookieBadge.astro
+++ b/src/components/layout/CookieBadge.astro
@@ -1,7 +1,7 @@
---
/**
- * Cookie notice. Essential storage needs no consent; analytics (Google Tag Manager, production
- * only) stays in cookieless Consent Mode until the visitor presses "Accept". The choice is kept
+ * Cookie notice. Essential storage needs no consent; analytics (Google Tag Manager and PostHog,
+ * production only) stays in cookieless Consent Mode until the visitor presses "Accept". The choice is kept
* in `dewee.cookies` ("all" or "essential") and the notice does not come back once answered.
*/
import { localePath, type Locale } from "~/i18n/config";
@@ -65,8 +65,10 @@ const { locale } = Astro.props;
const choice = btn.dataset.cookieChoice as Choice;
try { localStorage.setItem(KEY, choice); } catch { /* still hide for this page */ }
if (choice === "all") {
- const w = window as unknown as { gtag?: (...args: unknown[]) => void };
+ const w = window as unknown as { gtag?: (...args: unknown[]) => void; posthog?: { set_config: (c: Record
) => void } };
w.gtag?.("consent", "update", { analytics_storage: "granted", ad_storage: "granted", ad_user_data: "granted", ad_personalization: "granted" });
+ // PostHog ran in memory until now; keep the visitor's id from here on.
+ w.posthog?.set_config({ persistence: "localStorage+cookie" });
}
removeEventListener("scroll", onScroll);
el.hidden = true;
diff --git a/src/components/layout/PosthogAnalytics.astro b/src/components/layout/PosthogAnalytics.astro
new file mode 100644
index 0000000..e047131
--- /dev/null
+++ b/src/components/layout/PosthogAnalytics.astro
@@ -0,0 +1,57 @@
+---
+/**
+ * PostHog product analytics through the first-party /ingest proxy (see posthog-proxy). Loads
+ * on production only, like Google Tag Manager, so staging and local traffic stay out of the
+ * project. Until the visitor accepts cookies, PostHog keeps its id in memory only (nothing is
+ * stored); CookieBadge switches it to persistent storage on "Accept".
+ * Events: pageviews, plan CTAs, app/contact/outbound clicks, theme toggles, chat opens, leads.
+ */
+import { SITE } from "~/content/site";
+import type { Locale } from "~/i18n/config";
+interface Props { locale: Locale }
+const { locale } = Astro.props;
+const enabled = (Astro.site?.hostname ?? "") === SITE.domain;
+const config = {
+ key: "phc_x3SRpJyREJK2UfZhvQGaqAxax94u6Aj7YLnQ3Xo7kp7m",
+ props: { site: "dewee-web-v2", locale },
+};
+---
+
+{enabled && (
+
+)}
diff --git a/src/layouts/BaseLayout.astro b/src/layouts/BaseLayout.astro
index c31143b..2122431 100644
--- a/src/layouts/BaseLayout.astro
+++ b/src/layouts/BaseLayout.astro
@@ -13,6 +13,7 @@ import SiteHeader from "~/components/layout/SiteHeader.astro";
import SiteFooter from "~/components/layout/SiteFooter.astro";
import CookieBadge from "~/components/layout/CookieBadge.astro";
import GoogleTagManager from "~/components/layout/GoogleTagManager.astro";
+import PosthogAnalytics from "~/components/layout/PosthogAnalytics.astro";
import ChatLauncher from "~/components/chat/ChatLauncher.astro";
interface Props {
@@ -52,6 +53,7 @@ const isStaging = (Astro.site?.hostname ?? "").startsWith("staging.");
+