mirror of
https://github.com/jazzband/django-analytical.git
synced 2026-03-16 22:20:25 +00:00
Merge pull request #137 from pjdelport/add-hotjar-support
Add Hotjar support
This commit is contained in:
commit
e91615b754
5 changed files with 225 additions and 0 deletions
|
|
@ -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/
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ TAG_MODULES = [
|
|||
'analytical.gauges',
|
||||
'analytical.google_analytics',
|
||||
'analytical.gosquared',
|
||||
'analytical.hotjar',
|
||||
'analytical.hubspot',
|
||||
'analytical.intercom',
|
||||
'analytical.kiss_insights',
|
||||
|
|
|
|||
65
analytical/templatetags/hotjar.py
Normal file
65
analytical/templatetags/hotjar.py
Normal 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)
|
||||
84
analytical/tests/test_tag_hotjar.py
Normal file
84
analytical/tests/test_tag_hotjar.py
Normal 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
73
docs/services/hotjar.rst
Normal 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.
|
||||
Loading…
Reference in a new issue