mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-17 09:31:55 +00:00
feat: add PostHog analytics integration
- Add PostHog client configuration in ui/lib/posthog.ts - Integrate PostHog tracking in auth forms and provider workflows - Add PostHog dependencies (posthog-js and posthog-node) - Update Next.js config for PostHog integration - Add environment variables for PostHog configuration - Update changelog with PostHog integration entry
This commit is contained in:
@@ -150,3 +150,7 @@ LANGSMITH_TRACING=false
|
||||
LANGSMITH_ENDPOINT="https://api.smith.langchain.com"
|
||||
LANGSMITH_API_KEY=""
|
||||
LANGCHAIN_PROJECT=""
|
||||
|
||||
# posthog integration
|
||||
NEXT_PUBLIC_POSTHOG_KEY=""
|
||||
NEXT_PUBLIC_POSTHOG_HOST=https://eu.i.posthog.com
|
||||
|
||||
@@ -6,6 +6,8 @@ All notable changes to the **Prowler UI** are documented in this file.
|
||||
|
||||
### 🚀 Added
|
||||
|
||||
- PostHog analytics integration
|
||||
[(#PR_NUMBER)](https://github.com/prowler-cloud/prowler/pull/PR_NUMBER)
|
||||
- Mutelist configuration form [(#8190)](https://github.com/prowler-cloud/prowler/pull/8190)
|
||||
- SAML login integration [(#8203)](https://github.com/prowler-cloud/prowler/pull/8203)
|
||||
- Resource view [(#7760)](https://github.com/prowler-cloud/prowler/pull/7760)
|
||||
|
||||
+18
-1
@@ -5,6 +5,9 @@ import { useRouter } from "next/navigation";
|
||||
import { SessionProvider } from "next-auth/react";
|
||||
import { ThemeProvider as NextThemesProvider } from "next-themes";
|
||||
import { ThemeProviderProps } from "next-themes/dist/types";
|
||||
import posthog from "posthog-js";
|
||||
import { PostHogProvider as PHProvider } from "posthog-js/react";
|
||||
import { useEffect } from "react";
|
||||
import * as React from "react";
|
||||
|
||||
export interface ProvidersProps {
|
||||
@@ -15,10 +18,24 @@ export interface ProvidersProps {
|
||||
export function Providers({ children, themeProps }: ProvidersProps) {
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
|
||||
api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST,
|
||||
ui_host: process.env.NEXT_PUBLIC_POSTHOG_HOST,
|
||||
autocapture: false,
|
||||
defaults: "2025-05-24",
|
||||
capture_exceptions: true,
|
||||
capture_pageview: false,
|
||||
capture_pageleave: false,
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<SessionProvider>
|
||||
<NextUIProvider navigate={router.push}>
|
||||
<NextThemesProvider {...themeProps}>{children}</NextThemesProvider>
|
||||
<NextThemesProvider {...themeProps}>
|
||||
<PHProvider client={posthog}>{children}</PHProvider>
|
||||
</NextThemesProvider>
|
||||
</NextUIProvider>
|
||||
</SessionProvider>
|
||||
);
|
||||
|
||||
@@ -4,6 +4,7 @@ import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Icon } from "@iconify/react";
|
||||
import { Button, Checkbox, Divider, Link, Tooltip } from "@nextui-org/react";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import posthog from "posthog-js";
|
||||
import { useEffect } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
@@ -80,6 +81,8 @@ export const AuthForm = ({
|
||||
const isSamlMode = form.watch("isSamlMode");
|
||||
|
||||
const onSubmit = async (data: z.infer<typeof formSchema>) => {
|
||||
//getting an new posthog init
|
||||
posthog.reset(true);
|
||||
if (type === "sign-in") {
|
||||
if (data.isSamlMode) {
|
||||
const email = data.email.toLowerCase();
|
||||
@@ -107,6 +110,11 @@ export const AuthForm = ({
|
||||
password: data.password,
|
||||
});
|
||||
if (result?.message === "Success") {
|
||||
posthog.identify(data.email.toLowerCase());
|
||||
posthog.capture("user_login", {
|
||||
email: data.email.toLocaleLowerCase(),
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
router.push("/");
|
||||
} else if (result?.errors && "credentials" in result.errors) {
|
||||
form.setError("email", {
|
||||
@@ -128,6 +136,20 @@ export const AuthForm = ({
|
||||
const newUser = await createNewUser(data);
|
||||
|
||||
if (!newUser.errors) {
|
||||
let firstName = "";
|
||||
let lastName = "";
|
||||
if (data.name) {
|
||||
const nameParts = data.name.trim().split(" ");
|
||||
firstName = nameParts[0] || "";
|
||||
lastName = nameParts.slice(1).join(" ") || "";
|
||||
}
|
||||
posthog.capture("user_registered", {
|
||||
email: data.email.toLocaleLowerCase(),
|
||||
firstname: firstName,
|
||||
lastname: lastName,
|
||||
company: data.company || "",
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
toast({
|
||||
title: "Success!",
|
||||
description: "The user was registered successfully.",
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Icon } from "@iconify/react";
|
||||
import { Checkbox } from "@nextui-org/react";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import posthog from "posthog-js";
|
||||
import { useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
@@ -145,6 +146,13 @@ export const TestConnectionForm = ({
|
||||
});
|
||||
} else {
|
||||
setIsRedirecting(true);
|
||||
// Capture PostHog event for successful cloud connection
|
||||
posthog.capture("cloud_connection_success", {
|
||||
provider_type: providerType,
|
||||
provider_alias: providerData.data.attributes.alias,
|
||||
scan_type: form.watch("runOnce") ? "single" : "scheduled",
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
router.push("/scans");
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import { PostHog } from "posthog-node";
|
||||
|
||||
// NOTE: This is a Node.js client, so you can use it for sending events from the server side to PostHog.
|
||||
export default function PostHogClient() {
|
||||
const posthogClient = new PostHog(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
|
||||
host: process.env.NEXT_PUBLIC_POSTHOG_HOST,
|
||||
flushAt: 1,
|
||||
flushInterval: 0,
|
||||
});
|
||||
return posthogClient;
|
||||
}
|
||||
+4
-4
@@ -4,12 +4,12 @@
|
||||
// 'unsafe-eval' is configured under `script-src` because it is required by NextJS for development mode
|
||||
const cspHeader = `
|
||||
default-src 'self';
|
||||
script-src 'self' 'unsafe-inline' 'unsafe-eval' https://js.stripe.com https://www.googletagmanager.com;
|
||||
connect-src 'self' https://api.iconify.design https://api.simplesvg.com https://api.unisvg.com https://js.stripe.com https://www.googletagmanager.com;
|
||||
img-src 'self' https://www.google-analytics.com https://www.googletagmanager.com;
|
||||
script-src 'self' 'unsafe-inline' 'unsafe-eval' https://js.stripe.com https://www.googletagmanager.com https://*.posthog.com;
|
||||
connect-src 'self' https://api.iconify.design https://api.simplesvg.com https://api.unisvg.com https://js.stripe.com https://www.googletagmanager.com https://*.posthog.com;
|
||||
img-src 'self' https://www.google-analytics.com https://www.googletagmanager.com https://*.posthog.com;
|
||||
font-src 'self';
|
||||
style-src 'self' 'unsafe-inline';
|
||||
frame-src 'self' https://js.stripe.com https://www.googletagmanager.com;
|
||||
frame-src 'self' https://js.stripe.com https://www.googletagmanager.com https://*.posthog.com;
|
||||
frame-ancestors 'none';
|
||||
`;
|
||||
|
||||
|
||||
Generated
+2
@@ -47,6 +47,8 @@
|
||||
"next": "^14.2.30",
|
||||
"next-auth": "^5.0.0-beta.25",
|
||||
"next-themes": "^0.2.1",
|
||||
"posthog-js": "^1.256.1",
|
||||
"posthog-node": "^5.1.1",
|
||||
"radix-ui": "^1.1.3",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
"next": "^14.2.30",
|
||||
"next-auth": "^5.0.0-beta.25",
|
||||
"next-themes": "^0.2.1",
|
||||
"posthog-js": "^1.256.1",
|
||||
"posthog-node": "^5.1.1",
|
||||
"radix-ui": "^1.1.3",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
|
||||
Reference in New Issue
Block a user