mirror of
https://github.com/formbricks/formbricks.git
synced 2026-04-19 02:10:33 -05:00
feat: Add PostHog
This commit is contained in:
@@ -18,6 +18,7 @@ import {
|
||||
} from "date-fns";
|
||||
import { TFunction } from "i18next";
|
||||
import { Loader2 } from "lucide-react";
|
||||
import posthog from "posthog-js";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -252,6 +253,12 @@ export const CustomFilter = ({ survey }: CustomFilterProps) => {
|
||||
});
|
||||
|
||||
if (responsesDownloadUrlResponse?.data) {
|
||||
posthog.capture("responses_exported", {
|
||||
survey_id: survey.id,
|
||||
survey_name: survey.name,
|
||||
file_type: fileType,
|
||||
filter_type: filter,
|
||||
});
|
||||
downloadResponsesFile(
|
||||
responsesDownloadUrlResponse.data.fileName,
|
||||
responsesDownloadUrlResponse.data.fileContents,
|
||||
|
||||
@@ -8,6 +8,7 @@ import { checkSurveyValidity } from "@/app/api/v2/client/[environmentId]/respons
|
||||
import { responses } from "@/app/lib/api/response";
|
||||
import { transformErrorToDetails } from "@/app/lib/api/validator";
|
||||
import { sendToPipeline } from "@/app/lib/pipelines";
|
||||
import { getPostHogClient } from "@/lib/posthog-server";
|
||||
import { getSurvey } from "@/lib/survey/service";
|
||||
import { getElementsFromBlocks } from "@/lib/survey/utils";
|
||||
import { getClientIpFromHeaders } from "@/lib/utils/client-ip";
|
||||
@@ -173,6 +174,21 @@ export const POST = async (request: Request, context: Context): Promise<Response
|
||||
surveyId: responseData.surveyId,
|
||||
response: responseData,
|
||||
});
|
||||
|
||||
try {
|
||||
const posthogServer = getPostHogClient();
|
||||
posthogServer.capture({
|
||||
distinctId: environmentId,
|
||||
event: "survey_response_finished",
|
||||
properties: {
|
||||
survey_id: responseData.surveyId,
|
||||
response_id: responseData.id,
|
||||
environment_id: environmentId,
|
||||
},
|
||||
});
|
||||
} catch {
|
||||
// non-critical, don't block the response
|
||||
}
|
||||
}
|
||||
|
||||
const quotaObj = createQuotaFullObject(quotaFull);
|
||||
|
||||
9
apps/web/instrumentation-client.ts
Normal file
9
apps/web/instrumentation-client.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import posthog from "posthog-js";
|
||||
|
||||
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
|
||||
api_host: "/ingest",
|
||||
ui_host: "https://eu.posthog.com",
|
||||
defaults: "2026-01-30",
|
||||
capture_exceptions: true,
|
||||
debug: process.env.NODE_ENV === "development",
|
||||
});
|
||||
20
apps/web/lib/posthog-server.ts
Normal file
20
apps/web/lib/posthog-server.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { PostHog } from "posthog-node";
|
||||
|
||||
let posthogClient: PostHog | null = null;
|
||||
|
||||
export function getPostHogClient(): PostHog {
|
||||
if (!posthogClient) {
|
||||
posthogClient = new PostHog(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
|
||||
host: process.env.NEXT_PUBLIC_POSTHOG_HOST,
|
||||
flushAt: 1,
|
||||
flushInterval: 0,
|
||||
});
|
||||
}
|
||||
return posthogClient;
|
||||
}
|
||||
|
||||
export async function shutdownPostHog(): Promise<void> {
|
||||
if (posthogClient) {
|
||||
await posthogClient.shutdown();
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { signIn } from "next-auth/react";
|
||||
import Link from "next/dist/client/link";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import posthog from "posthog-js";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { FormProvider, SubmitHandler, useForm } from "react-hook-form";
|
||||
import { toast } from "react-hot-toast";
|
||||
@@ -119,9 +120,15 @@ export const LoginForm = ({
|
||||
}
|
||||
|
||||
if (!signInResponse?.error) {
|
||||
posthog.identify(data.email.toLowerCase(), { email: data.email.toLowerCase() });
|
||||
posthog.capture("user_logged_in", {
|
||||
email: data.email.toLowerCase(),
|
||||
method: "email",
|
||||
});
|
||||
router.push(searchParams?.get("callbackUrl") ?? "/");
|
||||
}
|
||||
} catch (error) {
|
||||
posthog.captureException(error);
|
||||
toast.error(error.toString());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import Link from "next/link";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import posthog from "posthog-js";
|
||||
import { useMemo, useState } from "react";
|
||||
import { FormProvider, useForm } from "react-hook-form";
|
||||
import toast from "react-hot-toast";
|
||||
@@ -128,6 +129,14 @@ export const SignupForm = ({
|
||||
: `/auth/verification-requested?token=${token}`;
|
||||
|
||||
if (createUserResponse?.data) {
|
||||
posthog.identify(data.email, { name: data.name, email: data.email });
|
||||
posthog.capture("user_signed_up", {
|
||||
name: data.name,
|
||||
email: data.email,
|
||||
is_formbricks_cloud: isFormbricksCloud,
|
||||
has_invite_token: !!inviteToken,
|
||||
email_verification_disabled: emailVerificationDisabled,
|
||||
});
|
||||
router.push(url);
|
||||
|
||||
if (!emailTokenActionResponse?.data) {
|
||||
@@ -149,6 +158,7 @@ export const SignupForm = ({
|
||||
toast.error(errorMessage);
|
||||
}
|
||||
} catch (e: any) {
|
||||
posthog.captureException(e);
|
||||
toast.error(e.message);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@ import { PipelineTriggers, Webhook } from "@prisma/client";
|
||||
import clsx from "clsx";
|
||||
import { Webhook as WebhookIcon } from "lucide-react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import posthog from "posthog-js";
|
||||
import { useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import toast from "react-hot-toast";
|
||||
@@ -153,6 +154,11 @@ export const AddWebhookModal = ({ environmentId, surveys, open, setOpen }: AddWe
|
||||
webhookSecret: testResult.secret,
|
||||
});
|
||||
if (createWebhookActionResult?.data) {
|
||||
posthog.capture("webhook_created", {
|
||||
environment_id: environmentId,
|
||||
webhook_triggers: selectedTriggers,
|
||||
survey_count: selectedAllSurveys ? "all" : selectedSurveys.length,
|
||||
});
|
||||
router.refresh();
|
||||
setCreatedWebhook(createWebhookActionResult.data);
|
||||
toast.success(t("environments.integrations.webhooks.webhook_added_successfully"));
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { PlusCircleIcon } from "lucide-react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import posthog from "posthog-js";
|
||||
import { useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import toast from "react-hot-toast";
|
||||
@@ -45,6 +46,10 @@ export const CreateOrganizationModal = ({ open, setOpen }: CreateOrganizationMod
|
||||
setLoading(true);
|
||||
const createOrganizationResponse = await createOrganizationAction({ organizationName: data.name });
|
||||
if (createOrganizationResponse?.data) {
|
||||
posthog.capture("organization_created", {
|
||||
organization_id: createOrganizationResponse.data.id,
|
||||
organization_name: data.name,
|
||||
});
|
||||
toast.success(t("environments.settings.general.organization_created_successfully"));
|
||||
router.push(`/organizations/${createOrganizationResponse.data.id}`);
|
||||
setOpen(false);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { ApiKeyPermission } from "@prisma/client";
|
||||
import { FilesIcon, TrashIcon } from "lucide-react";
|
||||
import posthog from "posthog-js";
|
||||
import { useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -80,6 +81,10 @@ export const EditAPIKeys = ({ organizationId, apiKeys, locale, isReadOnly, proje
|
||||
const updatedApiKeys = [...apiKeysLocal, createApiKeyResponse.data];
|
||||
setApiKeysLocal(updatedApiKeys);
|
||||
setIsLoading(false);
|
||||
posthog.capture("api_key_created", {
|
||||
organization_id: organizationId,
|
||||
api_key_label: data.label,
|
||||
});
|
||||
toast.success(t("environments.workspace.api_keys.api_key_created"));
|
||||
} else {
|
||||
setIsLoading(false);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useRouter } from "next/navigation";
|
||||
import posthog from "posthog-js";
|
||||
import { useState } from "react";
|
||||
import { SubmitHandler, useForm } from "react-hook-form";
|
||||
import { toast } from "react-hot-toast";
|
||||
@@ -36,6 +37,11 @@ export const CreateOrganization = () => {
|
||||
setIsSubmitting(true);
|
||||
const createOrganizationResponse = await createOrganizationAction({ organizationName });
|
||||
if (createOrganizationResponse?.data) {
|
||||
posthog.capture("organization_created", {
|
||||
organization_id: createOrganizationResponse.data.id,
|
||||
organization_name: organizationName,
|
||||
source: "setup",
|
||||
});
|
||||
router.push(`/setup/organization/${createOrganizationResponse.data.id}/invite`);
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { Project } from "@prisma/client";
|
||||
import { useRouter } from "next/navigation";
|
||||
import posthog from "posthog-js";
|
||||
import { useMemo, useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -64,6 +65,12 @@ export const TemplateList = ({
|
||||
});
|
||||
|
||||
if (createSurveyResponse?.data) {
|
||||
const eventName = surveyType === "link" ? "link_survey_created" : "in_app_survey_created";
|
||||
posthog.capture(eventName, {
|
||||
survey_id: createSurveyResponse.data.id,
|
||||
template_name: activeTemplate.name,
|
||||
environment_id: environmentId,
|
||||
});
|
||||
router.push(`/environments/${environmentId}/surveys/${createSurveyResponse.data.id}/edit`);
|
||||
} else {
|
||||
const errorMessage = getFormattedErrorMessage(createSurveyResponse);
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useAutoAnimate } from "@formkit/auto-animate/react";
|
||||
import { Environment } from "@prisma/client";
|
||||
import * as Collapsible from "@radix-ui/react-collapsible";
|
||||
import { CheckIcon, LinkIcon, MonitorIcon } from "lucide-react";
|
||||
import posthog from "posthog-js";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { TSegment } from "@formbricks/types/segment";
|
||||
@@ -42,6 +43,12 @@ export const HowToSendCard = ({ localSurvey, setLocalSurvey, environment }: HowT
|
||||
endings: endingsTemp,
|
||||
}));
|
||||
|
||||
posthog.capture("survey_type_selected", {
|
||||
survey_id: localSurvey.id,
|
||||
survey_type: type,
|
||||
previous_type: localSurvey.type,
|
||||
});
|
||||
|
||||
// if the type is "app" and the local survey does not already have a segment, we create a new temporary segment
|
||||
if (type === "app" && !localSurvey.segment) {
|
||||
const tempSegment: TSegment = {
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Project } from "@prisma/client";
|
||||
import { isEqual } from "lodash";
|
||||
import { ArrowLeftIcon, SettingsIcon } from "lucide-react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import posthog from "posthog-js";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -391,6 +392,12 @@ export const SurveyMenuBar = ({
|
||||
if (updatedSurveyResponse?.data) {
|
||||
setLocalSurvey(updatedSurveyResponse.data);
|
||||
toast.success(t("environments.surveys.edit.changes_saved"));
|
||||
posthog.capture("survey_saved", {
|
||||
survey_id: localSurvey.id,
|
||||
survey_name: localSurvey.name,
|
||||
survey_type: localSurvey.type,
|
||||
survey_status: localSurvey.status,
|
||||
});
|
||||
// Set flag to prevent beforeunload warning during router.refresh()
|
||||
isSuccessfullySavedRef.current = true;
|
||||
router.refresh();
|
||||
@@ -402,6 +409,7 @@ export const SurveyMenuBar = ({
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
posthog.captureException(e);
|
||||
console.error(e);
|
||||
setIsSurveySaving(false);
|
||||
toast.error(t("environments.surveys.edit.error_saving_changes"));
|
||||
@@ -450,10 +458,16 @@ export const SurveyMenuBar = ({
|
||||
}
|
||||
|
||||
setIsSurveyPublishing(false);
|
||||
posthog.capture("survey_published", {
|
||||
survey_id: localSurvey.id,
|
||||
survey_name: localSurvey.name,
|
||||
survey_type: localSurvey.type,
|
||||
});
|
||||
// Set flag to prevent beforeunload warning during navigation
|
||||
isSuccessfullySavedRef.current = true;
|
||||
router.push(`/environments/${environmentId}/surveys/${localSurvey.id}/summary?success=true`);
|
||||
} catch (error) {
|
||||
posthog.captureException(error);
|
||||
console.error(error);
|
||||
toast.error(t("environments.surveys.edit.error_publishing_survey"));
|
||||
setIsSurveyPublishing(false);
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
} from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import posthog from "posthog-js";
|
||||
import { useMemo, useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -74,6 +75,12 @@ export const SurveyDropDownMenu = ({
|
||||
toast.error(getFormattedErrorMessage(result));
|
||||
return;
|
||||
}
|
||||
posthog.capture("survey_deleted", {
|
||||
survey_id: surveyId,
|
||||
survey_name: survey.name,
|
||||
survey_type: survey.type,
|
||||
survey_status: survey.status,
|
||||
});
|
||||
deleteSurvey(surveyId);
|
||||
toast.success(t("environments.surveys.survey_deleted_successfully"));
|
||||
} catch (error) {
|
||||
@@ -90,6 +97,11 @@ export const SurveyDropDownMenu = ({
|
||||
// For single-use surveys, this button is disabled, so we just copy the base link
|
||||
const copiedLink = copySurveyLink(surveyLink);
|
||||
navigator.clipboard.writeText(copiedLink);
|
||||
posthog.capture("survey_link_copied", {
|
||||
survey_id: survey.id,
|
||||
survey_name: survey.name,
|
||||
survey_type: survey.type,
|
||||
});
|
||||
toast.success(t("common.copied_to_clipboard"));
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
@@ -112,6 +124,13 @@ export const SurveyDropDownMenu = ({
|
||||
if (transformedDuplicatedSurvey?.data) {
|
||||
onSurveysCopied?.();
|
||||
}
|
||||
posthog.capture("survey_duplicated", {
|
||||
original_survey_id: surveyId,
|
||||
new_survey_id: duplicatedSurveyResponse.data.id,
|
||||
survey_name: survey.name,
|
||||
survey_type: survey.type,
|
||||
environment_id: environmentId,
|
||||
});
|
||||
toast.success(t("environments.surveys.survey_duplicated_successfully"));
|
||||
} else {
|
||||
const errorMessage = getFormattedErrorMessage(duplicatedSurveyResponse);
|
||||
|
||||
@@ -404,8 +404,17 @@ const nextConfig = {
|
||||
},
|
||||
];
|
||||
},
|
||||
skipTrailingSlashRedirect: true,
|
||||
async rewrites() {
|
||||
return [
|
||||
{
|
||||
source: "/ingest/static/:path*",
|
||||
destination: "https://eu-assets.i.posthog.com/static/:path*",
|
||||
},
|
||||
{
|
||||
source: "/ingest/:path*",
|
||||
destination: "https://eu.i.posthog.com/:path*",
|
||||
},
|
||||
{
|
||||
source: "/api/packages/website",
|
||||
destination: "/js/formbricks.umd.cjs",
|
||||
|
||||
@@ -102,6 +102,8 @@
|
||||
"nodemailer": "8.0.1",
|
||||
"otplib": "12.0.1",
|
||||
"papaparse": "5.5.3",
|
||||
"posthog-js": "1.360.0",
|
||||
"posthog-node": "5.28.0",
|
||||
"prismjs": "1.30.0",
|
||||
"qr-code-styling": "1.9.2",
|
||||
"qrcode": "1.5.4",
|
||||
|
||||
107
apps/web/posthog-setup-report.md
Normal file
107
apps/web/posthog-setup-report.md
Normal file
@@ -0,0 +1,107 @@
|
||||
# PostHog Setup Report
|
||||
|
||||
## Overview
|
||||
|
||||
PostHog analytics has been integrated into the Formbricks web app (`apps/web`) using the Next.js App Router approach with `instrumentation-client.ts`.
|
||||
|
||||
## Configuration
|
||||
|
||||
| Setting | Value |
|
||||
|---|---|
|
||||
| PostHog Host | `https://eu.i.posthog.com` |
|
||||
| Reverse Proxy | `/ingest/*` → `https://eu.i.posthog.com/*` |
|
||||
| Client Init | `apps/web/instrumentation-client.ts` |
|
||||
| Server Client | `apps/web/lib/posthog-server.ts` |
|
||||
|
||||
## Environment Variables
|
||||
|
||||
Added to `apps/web/.env`:
|
||||
|
||||
```
|
||||
NEXT_PUBLIC_POSTHOG_KEY=phc_ies97ZFTIL3f8T1sQOTCWQycBzqqPvkPcOkpxYJ1sOA
|
||||
NEXT_PUBLIC_POSTHOG_HOST=https://eu.i.posthog.com
|
||||
```
|
||||
|
||||
## Packages Installed
|
||||
|
||||
- `posthog-js` — client-side tracking
|
||||
- `posthog-node` — server-side tracking
|
||||
|
||||
## Files Modified
|
||||
|
||||
### New Files
|
||||
|
||||
- **`apps/web/instrumentation-client.ts`** — Client-side PostHog initialization (Next.js 15.3+ App Router pattern)
|
||||
- **`apps/web/lib/posthog-server.ts`** — Singleton server-side PostHog client
|
||||
|
||||
### Modified Files
|
||||
|
||||
- **`apps/web/next.config.mjs`** — Added `skipTrailingSlashRedirect: true` and `/ingest/*` reverse proxy rewrites
|
||||
- **`apps/web/modules/auth/signup/components/signup-form.tsx`** — Added `user_signed_up` event + `posthog.identify()`
|
||||
- **`apps/web/modules/auth/login/components/login-form.tsx`** — Added `user_logged_in` event + `posthog.identify()`
|
||||
- **`apps/web/modules/survey/editor/components/survey-menu-bar.tsx`** — Added `survey_saved` and `survey_published` events
|
||||
- **`apps/web/modules/survey/list/components/survey-dropdown-menu.tsx`** — Added `survey_deleted`, `survey_duplicated`, and `survey_link_copied` events
|
||||
- **`apps/web/modules/survey/components/template-list/index.tsx`** — Added `link_survey_created` / `in_app_survey_created` events
|
||||
- **`apps/web/modules/survey/editor/components/how-to-send-card.tsx`** — Added `survey_type_selected` event
|
||||
- **`apps/web/modules/organization/settings/api-keys/components/edit-api-keys.tsx`** — Added `api_key_created` event
|
||||
- **`apps/web/modules/organization/components/CreateOrganizationModal/index.tsx`** — Added `organization_created` event
|
||||
- **`apps/web/modules/setup/organization/create/components/create-organization.tsx`** — Added `organization_created` event (setup flow)
|
||||
- **`apps/web/modules/integrations/webhooks/components/add-webhook-modal.tsx`** — Added `webhook_created` event
|
||||
- **`apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/components/CustomFilter.tsx`** — Added `responses_exported` event
|
||||
- **`apps/web/app/api/v2/client/[environmentId]/responses/route.ts`** — Added server-side `survey_response_finished` event
|
||||
|
||||
## Events Tracked
|
||||
|
||||
| Event | Location | Properties |
|
||||
|---|---|---|
|
||||
| `user_signed_up` | `signup-form.tsx` | `name`, `email`, `is_formbricks_cloud`, `has_invite_token`, `email_verification_disabled` |
|
||||
| `user_logged_in` | `login-form.tsx` | `email`, `method` |
|
||||
| `link_survey_created` | `template-list/index.tsx` | `survey_id`, `template_name`, `environment_id` |
|
||||
| `in_app_survey_created` | `template-list/index.tsx` | `survey_id`, `template_name`, `environment_id` |
|
||||
| `survey_type_selected` | `how-to-send-card.tsx` | `survey_id`, `survey_type`, `previous_type` |
|
||||
| `survey_saved` | `survey-menu-bar.tsx` | `survey_id`, `survey_name`, `survey_type`, `survey_status` |
|
||||
| `survey_published` | `survey-menu-bar.tsx` | `survey_id`, `survey_name`, `survey_type` |
|
||||
| `survey_deleted` | `survey-dropdown-menu.tsx` | `survey_id`, `survey_name`, `survey_type`, `survey_status` |
|
||||
| `survey_duplicated` | `survey-dropdown-menu.tsx` | `original_survey_id`, `new_survey_id`, `survey_name`, `survey_type`, `environment_id` |
|
||||
| `survey_link_copied` | `survey-dropdown-menu.tsx` | `survey_id`, `survey_name`, `survey_type` |
|
||||
| `survey_response_finished` | `responses/route.ts` (server) | `survey_id`, `response_id`, `environment_id` |
|
||||
| `organization_created` | `CreateOrganizationModal`, `create-organization.tsx` | `organization_id`, `organization_name` |
|
||||
| `api_key_created` | `edit-api-keys.tsx` | `organization_id`, `api_key_label` |
|
||||
| `webhook_created` | `add-webhook-modal.tsx` | `environment_id`, `webhook_triggers`, `survey_count` |
|
||||
| `responses_exported` | `CustomFilter.tsx` | `survey_id`, `survey_name`, `file_type`, `filter_type` |
|
||||
|
||||
## PostHog Dashboards
|
||||
|
||||
### 1. Analytics Basics (ID: 563010)
|
||||
|
||||
**URL:** https://eu.posthog.com/project/138028/dashboard/563010
|
||||
|
||||
| Insight | Type | URL |
|
||||
|---|---|---|
|
||||
| User Signups & Logins Over Time | Trends (line) | https://eu.posthog.com/project/138028/insights/vRTZYMqz |
|
||||
| Signup to First Survey Published Funnel | Funnel | https://eu.posthog.com/project/138028/insights/SXvzJPQz |
|
||||
| Survey Lifecycle Events | Trends (line) — includes `link_survey_created` + `in_app_survey_created` | https://eu.posthog.com/project/138028/insights/8NJpApcm |
|
||||
| Survey Engagement Actions | Trends (bar) | https://eu.posthog.com/project/138028/insights/cQRrcfBq |
|
||||
| Full User Journey Funnel | Funnel (unordered) — includes both survey creation events | https://eu.posthog.com/project/138028/insights/kFjH9atY |
|
||||
| Total Surveys Created | Trends (bar) — combines `link_survey_created` + `in_app_survey_created` | https://eu.posthog.com/project/138028/insights/rAPBfnmR |
|
||||
|
||||
### 2. Survey Creation & Types (ID: 563022)
|
||||
|
||||
**URL:** https://eu.posthog.com/project/138028/dashboard/563022
|
||||
|
||||
| Insight | Type | URL |
|
||||
|---|---|---|
|
||||
| Link vs In-App Survey Creation | Trends (line) | https://eu.posthog.com/project/138028/insights/QL0LkWoI |
|
||||
| Survey Type Selection Distribution | Trends (pie) | https://eu.posthog.com/project/138028/insights/KPSUe2IF |
|
||||
| Survey Creation to Response Funnel | Funnel (unordered) — includes both `link_survey_created` + `in_app_survey_created` | https://eu.posthog.com/project/138028/insights/9UPWbBAf |
|
||||
| Total Surveys Created | Trends (bar) — combines both events | https://eu.posthog.com/project/138028/insights/rAPBfnmR |
|
||||
|
||||
### 3. Integrations & API (ID: 563021)
|
||||
|
||||
**URL:** https://eu.posthog.com/project/138028/dashboard/563021
|
||||
|
||||
| Insight | Type | URL |
|
||||
|---|---|---|
|
||||
| Integrations & API Usage | Trends (line) | https://eu.posthog.com/project/138028/insights/ATYgsDY2 |
|
||||
| Organizations & Responses Over Time | Trends (line) | https://eu.posthog.com/project/138028/insights/DZVTeqql |
|
||||
| Response Export Format Distribution | Trends (bar value) | https://eu.posthog.com/project/138028/insights/00bQNehy |
|
||||
Reference in New Issue
Block a user