Skip to main content
# Django NPS

Django app supporting Net Promoter Score (NPS) surveys

## Compatibility

This package supports Python 3.12+ and Django 5.2-6.0.

## Background - Net Promoter Score

The NPS is a measure of customer loyalty that is captured by asking your customers a single
question:

> How likely is it that you would recommend our [company|product|service] to a friend or colleague?"

The answer to this question is a number from 0-10 (inclusive). These scores are then broken out into
three distinct groups: 'detractors' (0-6), 'neutral' (7-8) and 'promoters' (9-10). The NPS is then
the difference between the number of promoters and detractors (as a percentage of the whole
population).

For example, if you ask 100 people, and you get the following results:

```
detractors: 20%
neutrals: 10%
promoters: 70%
```

Then your NPS is 70 - 20 = 50. _(NPS is expressed as a number, not a %)_

NPS was originally developed at the strategy consultants Bain & Company by Fred Reichheld in 2003.
They retain the registered trademark for NPS, and you can read all about the history of it on their
site "[Net Promoter System](http://netpromotersystem.com/about/index.aspx)".

## Usage

This app is used to store the individual scores, and calculate the NPS based on these. It does not
contain any templates for displaying the question itself, neither does it put any restriction around
how often you ask the question, or to whom. It is up to the app developer to determine how this
should work - each score is timestamped and linked to a Django User object, so you can easily work
out the time elapsed since the last time they were asked.

For example, if you want to ensure that you only survey users every X days, you can add a context
property to the template using the `display_to_user` method:

```python
>>> # only show the survey every 90 days
>>> UserScore.objects.days_since_user_score(request.user) > 90
True
```

If you then show the survey - the output of which is a single value (the score) together with an
optional reason ("what is the main reason for your score"), is then posted to the `post_score`
endpoint, which registers the user score.

The NPS value itself can be calculated on any queryset of `UserScore` objects - which allows you to
track the score based on any attribute of the score itself or the underlying user. For instance, if
you have custom user profiles, you may wish to segment your NPS by characteristics of those
profiles.

```python
>>> # December's NPS
>>> UserScore.objects.filter(timestamp__month=12).net_promoter_score()
50
```

The `post_score` endpoint returns a `JsonResponse` which contains a `'success': True|False` value
together with the `UserScore` details:

```python
{
"success": True,
"score": {"id": 1, "user": 1, "score": 0, "group": "detractor"}
}
```

If the score was rejected, the errors are returned in place of the score (errors are a list of
lists, as returned from the Django `Form.errors` property):

```python
{
"success": False,
"errors": [["score", "Score must be between 0-10"]]
}
```

The app contains a piece of middleware, `NPSMiddleware`, which will add an attribute to the
`HttpRequest` object called `show_nps`. If you add the middleware to your settings:

```python
# settings.py
MIDDLEWARE_CLASSES = (
# standard django middleware
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
...
'net_promoter_score.NPSMiddleware',
)
```

You can then use this value in your templates:

```html
<!-- show_nps template = {{request.show_nps}} -->
{% if request.show_nps %}
<div>HTML goes here</div>
{% endif %}
```

## Settings

**NPS_DISPLAY_INTERVAL**

The number of days between surveys, integer, defaults to 30. This value is used by the default
`show_nps` function to determine whether someone should be shown the survey.

**NPS_DISPLAY_FUNCTION**

A function that takes an `HttpRequest` object as its only argument, and which returns True if you
want to show the survey. This function is used by the `net_promoter_score.show_nps` function. It
defaults to return True if the request user has either never seen the survey, or hasn't seen it for
more days than the `NPS_DISPLAY_INTERVAL`.

This function should be overridden if you want fine-grained control over the process - it's the main
hook into the app.

## Tests

There is a full suite of tests for the app, which are best run through `tox`. If you wish to run the
tests outside of tox, you should install the requirements first:

```
$ pip install -r requirements.txt
$ python manage.py test
```

## License

MIT

## Contributing

Usual rules apply:

1. Fork to your own account
2. Create a branch, fix the issue / add the feature
3. Submit PR

Please take care to follow the coding style - and PEP8.

## Acknowledgements

Credit is due to **epantry** for the
[original project](https://github.com/epantry/django-netpromoterscore) from which this was forked.

Thanks also to the kind people at **Eldarion** ([website](http://eldarion.com/)) for releasing the
PyPI package name.

Metadata

Release files for django-nps 1.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-nps 1.3
File Size Uploaded
django_nps-1.3.tar.gz 10.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for django-nps 1.3
File Interpreter ABI Platform
django_nps-1.3-py3-none-any.whl Python 3 none any Details

Total release size: 24.0 kB

Release files / django_nps-1.3.tar.gz

Download URL django_nps-1.3.tar.gz
Size 10.2 kB
Tags Source
SHA-256 checksum
How to use checksums
d74bc203fb13120092f11b39725ba90dffe8c6c8c741e71ba1cb7b3951089369
BLAKE2b-256 checksum
How to use checksums
d11fa78de3bb5ce019ccc6edb778ac1323eda859fc9023f664f63fa11015d27c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.2

Release files / django_nps-1.3-py3-none-any.whl

Download URL django_nps-1.3-py3-none-any.whl
Size 13.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
67753263157ed1bf784f712b0492b317de66c98b005b07d3a1ca2a28e54d0d9d
BLAKE2b-256 checksum
How to use checksums
348dfc85b868e0b56462d8b194231927d20853c4741b436ec7fb8f07695f6bef
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.2

Release history Release notifications | RSS feed

This release

1.3 This release

2 release files

1.2

2 release files

1.1

2 release files

1.0.0

2 release files

0.7.2

2 release files

0.7

2 release files

0.6

2 release files

0.5

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.3.2

1 release file

0.3.1

3 release files

0.3.0

1 release file

0.2.3

3 release files

0.2.2

1 release file

0.2.1

3 release files

0.2.0

3 release files

0.1.1

3 release files

0.1.0

3 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page