Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add RFC for repeatable surveys #203

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions requests-for-comments/2024-05-07-repeatable-surveys.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Request for comments: Recurring surveys, Phani Raj

Desired decision date: May 10th, 2024

## Problem statement
_Who are we building for, what are their needs (include example cases), why is this important?_


Customers want a way to show a survey on a recurring schedule to track user sentiments over a period of time. [Customer issue](https://github.com/PostHog/posthog/issues/22099)

A premier example of this requirement is tracking NPS over time,
`are my customers getting happier about the product in the last year?`

## Success Criteria
_How do we know if this is successful (i.e. metrics, customer feedback), what's out of scope, whats makes this ambitious?_

We will be successful in building this feature if :

1. The customer's existing pain points with NPS tracking is solved, as described in the above issue.

2. We see surveys created with a repeated schedule after this feature ships, I'm not sure of an exact number right now, but I assume that once we give customers the ability
to repeat a survey, they'll start using it.

## Context
_What are our competitors doing, what are the technical constraints, what are customers asking for, what does the data tell us, are there external motivations (e.g. launch week, enterprise contract)?_

Our competitors have already built tools that help customers track user sentiment over a time period, allowing them to repeat surveys and gain insights into changing user behavior.

Our current workarounds of `just repeat the survey manually` might get them to repeat the survey, but there's no way to gain any useful insights since the responses will end up in different surveys.

### Similar tools
1. [Pendo's custom NPS survey type](https://support.pendo.io/hc/en-us/articles/360033527151-Set-up-an-NPS-survey#h_01HGD0SKYSRB6SNKXBFJ1QG7M7)
2. [Surveymonkey's multiple responses](https://help.surveymonkey.com/en/surveymonkey/send/allowing-multiple-responses/)

This is how UserPilot shows NPS scores changing over time

<img width="1115" alt="image" src="https://github.com/PostHog/meta/assets/82819/3fbaa08d-aa79-4781-b0f4-07b56242486f">


## Design
_What are the key user experience and technical design decisions / trade-offs?_

A survey is assumed to have only one response in the system and we have filter conditions that govern **who** can see the survey.
A user's survey response action is tracked as a boolean, i.e. we add a person property with the survey-id `$survey_response/<surveyID>` when a user submits or dismisses a review.

To support this feature, we need to introduce the concept of `survey iterations` to the UI and person properties.

Here's what we need to do to solve this :

### Data model changes to the surveys table
1. Add properties to the survey data model to track

| Column name | type | description | nullable |
|:----|:----|:----|:----|
| `iteration_frequency_days` | integer | Frequency, in days, at which the survey should be repeated | Yes |
| `iteration_count` | integer | max number of times the survey should be repeated | Yes |
| `iteration_start_dates` | []date | Start dates of all iterations for this survey. | Yes |

This design allows our users to setup such surveys:

1. `repeat this survey 4 times, once every 90 days`.
2. They can also just leave the `iteration_count` as zero to have an infinitely repeating survey `repeat this survey, once every 90 days`

These three properties are nullable and we need to make our work backwards compatible to make existing survey responses function without issues to show NPS scores etc.

#### UI changes.
1. Show the user an interface to pick the repeat interval of the survey, this will be a frequency in Days.
2. Show the user an interface to pick the iteration count, how many times should this survey repeat?
3. Once both values are collected, on the server, use `[Recurrence Rule](https://dateutil.readthedocs.io/en/stable/rrule.html)` to save the `iteration_start_dates` of the Survey.
4. If a survey has an iteration count of more than 1, change the existing UI to run custom clickhouse queries to account for a survey with multiple response sets, one for each iteration.
5. Depending on survey type, introduce a section to show historic results:

4.1. NPS : Display NPS scores bucketed by detractors, passives, promoters, over time. Here's an example.
<img width="1115" alt="image" src="https://github.com/PostHog/meta/assets/82819/3fbaa08d-aa79-4781-b0f4-07b56242486f">
4.2. CSAT: Display cumulative CSAT over time. Here's an example from https://theacsi.org/
<img width="489" alt="image" src="https://github.com/PostHog/meta/assets/82819/ff9d9928-862b-4fb3-a718-225922efce4a">

6. Along with historic results, allow users to pick a time period/iteration and show the following information over that time period.

5.1. Users viewed/submitted/dismissed

5.2. for NPS, responses segmented into detractors,passives & promoters.

5.3. for CSAT, responses segmented into dissatisfied, satisfied & very satisfied.

7. Custom new sections to show:

6.1. Survey response rate over time, i.e., if the number of people responding to a survey increases/decreases over time.

6.2. Survey user base changing over time, i.e., if users who submitted the survey once do it again.

#### posthog-js changes.
1. To decide when to show a survey, see if a user has a survey response submitted for the current survey start date, and show the survey if they haven't.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see if a user has a survey response submitted for the current survey start date

How are you planning to query this?

Also worth noting that you'll need to put the local storage cache on a ttl / find another way around not showing the same survey repeatedly. There are some complex patterns here to handle:

  1. When a user first dismisses/responds to a survey, we add something to local storage to not show this survey again.
  2. Now, I'm assuming there's some mechanism like flags(?) controlling when to next show it. This will almost certainly have some delay (since we need to send properties back via ingestion, which can take some time).
  3. Because of the async nature of (2), the client side needs some way to remember not to show this survey again, hence (1). But now, if we do want to re-show it, we also want to delete (1), hence some ttl there.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is, as you noted, going to be complicated.
For a given survey iteration, we can't depend on the local storage having the necessary information to show/hide a survey given how long the iterations last.
To get over this, we could associate each iteration of the survey with its own feature flag, that has a time based activation.

e.g. survey-targeting-flag-iter-1 is only true for 90 days, until Aug 11 2024. and
survey-targeting-flag-iter-2 is from Aug 11 2024 to November 9th 2024. And we create these flags on a schedule based on the survey frequency. posthog-js just uses this feature flag information to show/hide the dialog. And when it sends the event, it sends the iteration_id as a person property, from the survey object properties.

3. When a survey is submitted, add properties for survey iteration count and survey start date in the current iteration to the person properties. So this person is accounted as having submitted the survey for this iteration/start date.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unclear to me how this is used in point (1) above, or how we use this info?

Are you creating a targeting flag behind the scenes with info like:

$survey_response/${survey.id}/iteration_count is less than 4

AND

$survey_response/${survey.id}/${current_iteration} is not set ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks somewhat different than what you're proposing

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For a given survey iteration, e.g. 2 of 4, if a user submits a response for iteration 2 on May 13th 2024,
we will add the following person properties.

$survey_response/${survey.id}/2
$survey_response/${survey.id}/05-13-2024

`$survey_response/${survey.id}/${survey.iteration_start_date}/`
`$survey_response/${survey.id}/${survey.iteration_count}/`

### out of scope
1. Survey creators cannot change the frequency once a survey is created, as this will change the way we calculate the survey response rates.
2. Changing the survey questions over time, i.e. having a different set of questions for each time period is not supported.