DEV Community

gulnur
gulnur

Posted on

PostHog Custom Surveys: Beyond the Default UI

PostHog provides a powerful analytics and experimentation platform, including built-in surveys for collecting user feedback. However, in real-world applications especially dashboards, internal tools, or B2B SaaS products the default survey UI is not always flexible enough.

In this article, I’ll walk through how I built a fully custom in-app survey UI on top of PostHog, while still using PostHog as the data and analytics layer.

This approach allowed me to keep full control over UX, layout, and behavior without introducing an additional backend or feedback system.

Why Go Beyond the Default Survey UI?

PostHog’s built-in surveys are great for quick setups, but I ran into a few limitations and I would like to edit the pop-up.

Limited control over positioning and layout

UI didn’t fully match with my applicaiton

Needed a lightweight, non-intrusive CES-style survey

Wanted tighter control over when and how the survey appears

Instead of replacing PostHog, I decided to treat it as a survey engine, not a UI framework.

Architecture

The idea is simple:

PostHog Survey

onSurveysLoaded()

getActiveMatchingSurveys()

Custom Angular UI

posthog.capture()

PostHog decides when a survey should be shown.
My application decides how it should look and behave.

Listening for Active Surveys

One important lesson: calling getActiveMatchingSurveys() too early often returns an empty array.

The correct approach is to wait for surveys to finish loading.

posthog.onSurveysLoaded(() => {
  posthog.getActiveMatchingSurveys((surveys) => {
    if (!surveys.length) return;

    const survey = surveys[0];
    this.surveyId = survey.id;
    this.questionId = survey.questions[0]?.id;
    this.question = survey.questions[0]?.question;
  });
});
Enter fullscreen mode Exit fullscreen mode

Why this matters

Without onSurveysLoaded, surveys may not be available yet

Ad blockers or strict CSP rules can silently block surveys

Defensive checks prevent runtime errors

Building a Lightweight Custom UI

Rather than using modals or full-screen components, I chose a small fixed-position card with a basic css, that feels native.

.survey {
  position: fixed;
  bottom: 24px;
  right: 24px;
  max-width: 360px;
  padding: 16px;
  border-radius: 4px;
  border: 1px solid #ddd;
  background: #fff;
  font-size: 14px;
  z-index: 1000;
}

@media (max-width: 768px) {
  .survey {
    right: 16px;
    left: 16px;
  }
}
Enter fullscreen mode Exit fullscreen mode

Design goals:

  • Minimal color usage
  • Mobile-friendly
  • Easy to dismiss

No disruption to the main workflow

Submitting Survey Responses

When the user submits a response, the survey is sent back to PostHog as a custom event.

posthog.capture('custom_survey_submitted', {
  survey_id: this.surveyId,
  question_id: this.questionId,
  value: selectedValue,
});
Enter fullscreen mode Exit fullscreen mode

When Does a Custom Survey Make Sense?

Custom surveys are especially useful when:

You need design-system consistency

You’re building internal tools or admin panels

Feedback should feel contextual, not disruptive

You want analytics-grade data, not just form responses

PostHog excels as the decision and data layer,custom UI lets your product own the experience.

If you want, you can visit posthog website,they doing lots of great things.

Useful Links:
https://posthog.com/
https://github.com/PostHog/posthog
https://www.npmjs.com/package/posthog-js

Top comments (0)