diff --git a/analytical/templatetags/google_analytics_gtag.py b/analytical/templatetags/google_analytics_gtag.py
index f83f835..07c5a00 100644
--- a/analytical/templatetags/google_analytics_gtag.py
+++ b/analytical/templatetags/google_analytics_gtag.py
@@ -1,7 +1,9 @@
"""
-Google Analytics template tags and filters, using the new analytics.js library.
+Google Analytics template tags and filters, using the new gtag.js library.
+https://developers.google.com/tag-platform/gtagjs/reference
"""
+import json
import re
from django.template import Library, Node, TemplateSyntaxError
@@ -23,13 +25,10 @@ SETUP_CODE = """
function gtag(){{dataLayer.push(arguments);}}
gtag('js', new Date());
- {extra}
- gtag('config', '{property_id}');
+ gtag('config', '{property_id}', {custom_dimensions});
"""
-GTAG_SET_CODE = """gtag('set', {{'{key}': '{value}'}});"""
-
register = Library()
@@ -59,21 +58,15 @@ class GoogleAnalyticsGTagNode(Node):
)
def render(self, context):
- other_fields = {}
+ custom_dimensions = context.get('google_analytics_custom_dimensions', {})
- identity = get_identity(context, 'google_analytics_gtag')
+ identity = get_identity(context, prefix='google_analytics_gtag')
if identity is not None:
- other_fields['user_id'] = identity
+ custom_dimensions['user_id'] = identity
- extra = '\n'.join(
- [
- GTAG_SET_CODE.format(key=key, value=value)
- for key, value in other_fields.items()
- ]
- )
html = SETUP_CODE.format(
property_id=self.property_id,
- extra=extra,
+ custom_dimensions=json.dumps(custom_dimensions),
)
if is_internal_ip(context, 'GOOGLE_ANALYTICS'):
html = disable_html(html, 'Google Analytics')
diff --git a/docs/services/google_analytics_gtag.rst b/docs/services/google_analytics_gtag.rst
index a5f6f24..9760930 100644
--- a/docs/services/google_analytics_gtag.rst
+++ b/docs/services/google_analytics_gtag.rst
@@ -117,3 +117,52 @@ or in the template:
{% endwith %}
.. _`Google Analytics conditions`: https://developers.google.com/analytics/solutions/crm-integration#user_id
+
+.. _google-analytics-custom-dimensions:
+
+Custom dimensions
+----------------
+
+As described in the Google Analytics `custom dimensions`_ documentation
+page, you can define custom dimensions which are variables specific to your
+business needs. These variables can include both custom event parameters as
+well as customer user properties. Using the template context variable
+``google_analytics_custom_dimensions``, you can let the :ttag:`google_analytics_gtag`
+pass custom dimensions to Google Analytics automatically. The ``google_analytics_custom_dimensions``
+variable must be set to a dictionary where the keys are the dimension names
+and the values are the dimension values. You can set the context variable in your
+view when you render a template containing the tracking code::
+
+.. code-block:: python
+
+ context = RequestContext({
+ 'google_analytics_custom_dimensions': {
+ 'gender': 'female',
+ 'country': 'US',
+ 'user_properties': {
+ 'age': 25
+ }
+ }
+ })
+ return some_template.render(context)
+
+Note that the ``user_properties`` key is used to pass user properties to Google
+Analytics. It's not necessary to always use this key, but that'd be the way of
+sending user properties to Google Analytics automatically.
+
+You may want to set custom dimensions in a context processor that you add
+to the :data:`TEMPLATE_CONTEXT_PROCESSORS` list in :file:`settings.py`::
+
+.. code-block:: python
+
+ def google_analytics_segment_language(request):
+ try:
+ return {'google_analytics_custom_dimensions': {'language': request.LANGUAGE_CODE}}
+ except AttributeError:
+ return {}
+
+Just remember that if you set the same context variable in the
+:class:`~django.template.context.RequestContext` constructor and in a
+context processor, the latter clobbers the former.
+
+.. _`custom dimensions`: https://support.google.com/analytics/answer/10075209
diff --git a/tests/unit/test_tag_google_analytics_gtag.py b/tests/unit/test_tag_google_analytics_gtag.py
index 16c356f..c84c327 100644
--- a/tests/unit/test_tag_google_analytics_gtag.py
+++ b/tests/unit/test_tag_google_analytics_gtag.py
@@ -16,7 +16,7 @@ from analytical.utils import AnalyticalException
@override_settings(GOOGLE_ANALYTICS_GTAG_PROPERTY_ID='UA-123456-7')
class GoogleAnalyticsTagTestCase(TagTestCase):
"""
- Tests for the ``google_analytics_js`` template tag.
+ Tests for the ``google_analytics_gtag`` template tag.
"""
def test_tag(self):
@@ -25,7 +25,7 @@ class GoogleAnalyticsTagTestCase(TagTestCase):
''
) in r
assert "gtag('js', new Date());" in r
- assert "gtag('config', 'UA-123456-7');" in r
+ assert "gtag('config', 'UA-123456-7', {});" in r
def test_node(self):
r = GoogleAnalyticsGTagNode().render(Context())
@@ -33,7 +33,7 @@ class GoogleAnalyticsTagTestCase(TagTestCase):
''
) in r
assert "gtag('js', new Date());" in r
- assert "gtag('config', 'UA-123456-7');" in r
+ assert "gtag('config', 'UA-123456-7', {});" in r
@override_settings(GOOGLE_ANALYTICS_GTAG_PROPERTY_ID=None)
def test_no_property_id(self):
@@ -57,7 +57,7 @@ class GoogleAnalyticsTagTestCase(TagTestCase):
@override_settings(ANALYTICAL_AUTO_IDENTIFY=True)
def test_identify(self):
r = GoogleAnalyticsGTagNode().render(Context({'user': User(username='test')}))
- assert "gtag('set', {'user_id': 'test'});" in r
+ assert 'gtag(\'config\', \'UA-123456-7\', {"user_id": "test"});' in r
def test_identity_context_specific_provider(self):
"""
@@ -68,12 +68,13 @@ class GoogleAnalyticsTagTestCase(TagTestCase):
Context(
{
'google_analytics_gtag_identity': 'foo_gtag_identity',
- 'analytical_identity': 'bar_analytical_identity',
'user': User(username='test'),
}
)
)
- assert "gtag('set', {'user_id': 'foo_gtag_identity'});" in r
+ assert (
+ 'gtag(\'config\', \'UA-123456-7\', {"user_id": "foo_gtag_identity"});' in r
+ )
def test_identity_context_general(self):
"""
@@ -87,7 +88,10 @@ class GoogleAnalyticsTagTestCase(TagTestCase):
}
)
)
- assert "gtag('set', {'user_id': 'bar_analytical_identity'});" in r
+ assert (
+ 'gtag(\'config\', \'UA-123456-7\', {"user_id": "bar_analytical_identity"});'
+ in r
+ )
@override_settings(GOOGLE_ANALYTICS_GTAG_PROPERTY_ID='G-12345678')
def test_tag_with_measurement_id(self):
@@ -96,7 +100,7 @@ class GoogleAnalyticsTagTestCase(TagTestCase):
''
) in r
assert "gtag('js', new Date());" in r
- assert "gtag('config', 'G-12345678');" in r
+ assert "gtag('config', 'G-12345678', {});" in r
@override_settings(GOOGLE_ANALYTICS_GTAG_PROPERTY_ID='AW-1234567890')
def test_tag_with_conversion_id(self):
@@ -105,7 +109,7 @@ class GoogleAnalyticsTagTestCase(TagTestCase):
''
) in r
assert "gtag('js', new Date());" in r
- assert "gtag('config', 'DC-12345678');" in r
+ assert "gtag('config', 'DC-12345678', {});" in r
+
+ def test_tag_with_custom_dimensions(self):
+ r = GoogleAnalyticsGTagNode().render(
+ Context(
+ {
+ 'google_analytics_custom_dimensions': {
+ 'dimension_1': 'foo',
+ 'dimension_2': 'bar',
+ 'user_properties': {
+ 'user_property_1': True,
+ 'user_property_2': 'xyz',
+ },
+ },
+ }
+ )
+ )
+ assert (
+ "gtag('config', 'UA-123456-7', {"
+ '"dimension_1": "foo", '
+ '"dimension_2": "bar", '
+ '"user_properties": {'
+ '"user_property_1": true, '
+ '"user_property_2": "xyz"}});' in r
+ )
+
+ def test_tag_with_identity_and_custom_dimensions(self):
+ r = GoogleAnalyticsGTagNode().render(
+ Context(
+ {
+ 'google_analytics_gtag_identity': 'foo_gtag_identity',
+ 'google_analytics_custom_dimensions': {
+ 'dimension_1': 'foo',
+ 'dimension_2': 'bar',
+ },
+ }
+ )
+ )
+ assert (
+ "gtag('config', 'UA-123456-7', {"
+ '"dimension_1": "foo", '
+ '"dimension_2": "bar", '
+ '"user_id": "foo_gtag_identity"});' in r
+ )