Merge pull request #137 from pjdelport/add-hotjar-support

Add Hotjar support
This commit is contained in:
Joost Cassee 2018-11-15 20:16:42 +01:00 committed by GitHub
commit e91615b754
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 225 additions and 0 deletions

View file

@ -57,6 +57,7 @@ Currently Supported Services
* `Gaug.es`_ real time web analytics
* `Google Analytics`_ traffic analysis
* `GoSquared`_ traffic monitoring
* `Hotjar`_ analytics and user feedback
* `HubSpot`_ inbound marketing
* `Intercom`_ live chat and support
* `KISSinsights`_ feedback surveys
@ -81,6 +82,7 @@ Currently Supported Services
.. _`Gaug.es`: http://get.gaug.es/
.. _`Google Analytics`: http://www.google.com/analytics/
.. _`GoSquared`: http://www.gosquared.com/
.. _`Hotjar`: https://www.hotjar.com/
.. _`HubSpot`: http://www.hubspot.com/
.. _`Intercom`: http://www.intercom.io/
.. _`KISSinsights`: http://www.kissinsights.com/

View file

@ -24,6 +24,7 @@ TAG_MODULES = [
'analytical.gauges',
'analytical.google_analytics',
'analytical.gosquared',
'analytical.hotjar',
'analytical.hubspot',
'analytical.intercom',
'analytical.kiss_insights',

View file

@ -0,0 +1,65 @@
"""
Hotjar template tags and filters.
"""
from __future__ import absolute_import
import re
from django.template import Library, Node, TemplateSyntaxError
from analytical.utils import get_required_setting, is_internal_ip, disable_html
HOTJAR_TRACKING_CODE = """\
<script>
(function(h,o,t,j,a,r){
h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};
h._hjSettings={hjid:%(HOTJAR_SITE_ID)s,hjsv:6};
a=o.getElementsByTagName('head')[0];
r=o.createElement('script');r.async=1;
r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;
a.appendChild(r);
})(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');
</script>
"""
register = Library()
def _validate_no_args(token):
bits = token.split_contents()
if len(bits) > 1:
raise TemplateSyntaxError("'%s' takes no arguments" % bits[0])
@register.tag
def hotjar(parser, token):
"""
Hotjar template tag.
"""
_validate_no_args(token)
return HotjarNode()
class HotjarNode(Node):
def __init__(self):
self.site_id = get_required_setting(
'HOTJAR_SITE_ID',
re.compile(r'^\d+$'),
"must be (a string containing) a number",
)
def render(self, context):
html = HOTJAR_TRACKING_CODE % {'HOTJAR_SITE_ID': self.site_id}
if is_internal_ip(context, 'HOTJAR'):
return disable_html(html, 'Hotjar')
else:
return html
def contribute_to_analytical(add_node):
# ensure properly configured
HotjarNode()
add_node('head_bottom', HotjarNode)

View file

@ -0,0 +1,84 @@
"""
Tests for the Hotjar template tags.
"""
from django.http import HttpRequest
from django.template import Context, Template, TemplateSyntaxError
from django.test import override_settings
from analytical.templatetags.analytical import _load_template_nodes
from analytical.templatetags.hotjar import HotjarNode
from analytical.tests.utils import TagTestCase
from analytical.utils import AnalyticalException
expected_html = """\
<script>
(function(h,o,t,j,a,r){
h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};
h._hjSettings={hjid:123456789,hjsv:6};
a=o.getElementsByTagName('head')[0];
r=o.createElement('script');r.async=1;
r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;
a.appendChild(r);
})(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');
</script>
"""
@override_settings(HOTJAR_SITE_ID='123456789')
class HotjarTagTestCase(TagTestCase):
maxDiff = None
def test_tag(self):
html = self.render_tag('hotjar', 'hotjar')
self.assertEqual(expected_html, html)
def test_node(self):
html = HotjarNode().render(Context({}))
self.assertEqual(expected_html, html)
def test_tags_take_no_args(self):
self.assertRaisesRegexp(
TemplateSyntaxError,
r"^'hotjar' takes no arguments$",
lambda: (Template('{% load hotjar %}{% hotjar "arg" %}')
.render(Context({}))),
)
@override_settings(HOTJAR_SITE_ID=None)
def test_no_id(self):
expected_pattern = r'^HOTJAR_SITE_ID setting is not set$'
self.assertRaisesRegexp(AnalyticalException, expected_pattern, HotjarNode)
@override_settings(HOTJAR_SITE_ID='invalid')
def test_invalid_id(self):
expected_pattern = (
r"^HOTJAR_SITE_ID setting: must be \(a string containing\) a number: 'invalid'$")
self.assertRaisesRegexp(AnalyticalException, expected_pattern, HotjarNode)
@override_settings(ANALYTICAL_INTERNAL_IPS=['1.1.1.1'])
def test_render_internal_ip(self):
request = HttpRequest()
request.META['REMOTE_ADDR'] = '1.1.1.1'
context = Context({'request': request})
actual_html = HotjarNode().render(context)
disabled_html = '\n'.join([
'<!-- Hotjar disabled on internal IP address',
expected_html,
'-->',
])
self.assertEqual(disabled_html, actual_html)
def test_contribute_to_analytical(self):
"""
`hotjar.contribute_to_analytical` registers the head and body nodes.
"""
template_nodes = _load_template_nodes()
self.assertEqual({
'head_top': [],
'head_bottom': [HotjarNode],
'body_top': [],
'body_bottom': [],
}, template_nodes)

73
docs/services/hotjar.rst Normal file
View file

@ -0,0 +1,73 @@
=====================================
Hotjar -- analytics and user feedback
=====================================
`Hotjar`_ is a website analytics and user feedback tool.
.. _`Hotjar`: https://www.hotjar.com/
.. hotjar-installation:
Installation
============
To start using the Hotjar integration, you must have installed the
django-analytical package and have added the ``analytical`` application
to :const:`INSTALLED_APPS` in your project :file:`settings.py` file.
See :doc:`../install` for details.
Next you need to add the Hotjar template tag to your templates.
This step is only needed if you are not using the generic
:ttag:`analytical.*` tags. If you are, skip to
:ref:`hotjar-configuration`.
The Hotjar code is inserted into templates using template tags.
Because every page that you want to track must have the tag,
it is useful to add it to your base template.
At the top of the template, load the :mod:`hotjar` template tag library.
Then insert the :ttag:`hotjar` tag at the bottom of the head section::
{% load hotjar %}
<html>
<head>
...
{% hotjar %}
</head>
...
</html>
.. _hotjar-configuration:
Configuration
=============
Before you can use the Hotjar integration, you must first set your Site ID.
.. _hotjar-id:
Setting the Hotjar Site ID
--------------------------
You can find the Hotjar Site ID in the "Sites & Organizations" section of your Hotjar account.
Set :const:`HOTJAR_SITE_ID` in the project :file:`settings.py` file::
HOTJAR_SITE_ID = 'XXXXXXXXX'
If you do not set a Hotjar Site ID, the code will not be rendered.
.. _hotjar-internal-ips:
Internal IP addresses
---------------------
Usually you do not want to track clicks from your development or
internal IP addresses. By default, if the tags detect that the client
comes from any address in the :const:`HOTJAR_INTERNAL_IPS`
setting, the tracking code is commented out. It takes the value of
:const:`ANALYTICAL_INTERNAL_IPS` by default (which in turn is
:const:`INTERNAL_IPS` by default). See :ref:`identifying-visitors` for
important information about detecting the visitor IP address.