Skip to content

Commit 7253a3a

Browse files
authored
Fix gtag user_id setup and add support for custom dimensions (#226)
* Fixed user_id setup for gtag according to latest docs * Added the possibility to include custom dimensions to be sent along with every event * Added custom dimensions section to the gtag docs * Added explicit python code blocks in the docs * Reformat test_tag_google_analytics_gtag.py with Ruff formatter
1 parent a751ffa commit 7253a3a

File tree

3 files changed

+114
-25
lines changed

3 files changed

+114
-25
lines changed

analytical/templatetags/google_analytics_gtag.py

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
"""
2-
Google Analytics template tags and filters, using the new analytics.js library.
2+
Google Analytics template tags and filters, using the new gtag.js library.
3+
https://developers.google.com/tag-platform/gtagjs/reference
34
"""
45

6+
import json
57
import re
68

79
from django.template import Library, Node, TemplateSyntaxError
@@ -23,13 +25,10 @@
2325
function gtag(){{dataLayer.push(arguments);}}
2426
gtag('js', new Date());
2527
26-
{extra}
27-
gtag('config', '{property_id}');
28+
gtag('config', '{property_id}', {custom_dimensions});
2829
</script>
2930
"""
3031

31-
GTAG_SET_CODE = """gtag('set', {{'{key}': '{value}'}});"""
32-
3332
register = Library()
3433

3534

@@ -59,21 +58,15 @@ def __init__(self):
5958
)
6059

6160
def render(self, context):
62-
other_fields = {}
61+
custom_dimensions = context.get('google_analytics_custom_dimensions', {})
6362

64-
identity = get_identity(context, 'google_analytics_gtag')
63+
identity = get_identity(context, prefix='google_analytics_gtag')
6564
if identity is not None:
66-
other_fields['user_id'] = identity
65+
custom_dimensions['user_id'] = identity
6766

68-
extra = '\n'.join(
69-
[
70-
GTAG_SET_CODE.format(key=key, value=value)
71-
for key, value in other_fields.items()
72-
]
73-
)
7467
html = SETUP_CODE.format(
7568
property_id=self.property_id,
76-
extra=extra,
69+
custom_dimensions=json.dumps(custom_dimensions),
7770
)
7871
if is_internal_ip(context, 'GOOGLE_ANALYTICS'):
7972
html = disable_html(html, 'Google Analytics')

docs/services/google_analytics_gtag.rst

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,52 @@ or in the template:
117117
{% endwith %}
118118
119119
.. _`Google Analytics conditions`: https://developers.google.com/analytics/solutions/crm-integration#user_id
120+
121+
.. _google-analytics-custom-dimensions:
122+
123+
Custom dimensions
124+
----------------
125+
126+
As described in the Google Analytics `custom dimensions`_ documentation
127+
page, you can define custom dimensions which are variables specific to your
128+
business needs. These variables can include both custom event parameters as
129+
well as customer user properties. Using the template context variable
130+
``google_analytics_custom_dimensions``, you can let the :ttag:`google_analytics_gtag`
131+
pass custom dimensions to Google Analytics automatically. The ``google_analytics_custom_dimensions``
132+
variable must be set to a dictionary where the keys are the dimension names
133+
and the values are the dimension values. You can set the context variable in your
134+
view when you render a template containing the tracking code::
135+
136+
.. code-block:: python
137+
138+
context = RequestContext({
139+
'google_analytics_custom_dimensions': {
140+
'gender': 'female',
141+
'country': 'US',
142+
'user_properties': {
143+
'age': 25
144+
}
145+
}
146+
})
147+
return some_template.render(context)
148+
149+
Note that the ``user_properties`` key is used to pass user properties to Google
150+
Analytics. It's not necessary to always use this key, but that'd be the way of
151+
sending user properties to Google Analytics automatically.
152+
153+
You may want to set custom dimensions in a context processor that you add
154+
to the :data:`TEMPLATE_CONTEXT_PROCESSORS` list in :file:`settings.py`::
155+
156+
.. code-block:: python
157+
158+
def google_analytics_segment_language(request):
159+
try:
160+
return {'google_analytics_custom_dimensions': {'language': request.LANGUAGE_CODE}}
161+
except AttributeError:
162+
return {}
163+
164+
Just remember that if you set the same context variable in the
165+
:class:`~django.template.context.RequestContext` constructor and in a
166+
context processor, the latter clobbers the former.
167+
168+
.. _`custom dimensions`: https://support.google.com/analytics/answer/10075209

tests/unit/test_tag_google_analytics_gtag.py

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
@override_settings(GOOGLE_ANALYTICS_GTAG_PROPERTY_ID='UA-123456-7')
1717
class GoogleAnalyticsTagTestCase(TagTestCase):
1818
"""
19-
Tests for the ``google_analytics_js`` template tag.
19+
Tests for the ``google_analytics_gtag`` template tag.
2020
"""
2121

2222
def test_tag(self):
@@ -25,15 +25,15 @@ def test_tag(self):
2525
'<script async src="https://www.googletagmanager.com/gtag/js?id=UA-123456-7"></script>'
2626
) in r
2727
assert "gtag('js', new Date());" in r
28-
assert "gtag('config', 'UA-123456-7');" in r
28+
assert "gtag('config', 'UA-123456-7', {});" in r
2929

3030
def test_node(self):
3131
r = GoogleAnalyticsGTagNode().render(Context())
3232
assert (
3333
'<script async src="https://www.googletagmanager.com/gtag/js?id=UA-123456-7"></script>'
3434
) in r
3535
assert "gtag('js', new Date());" in r
36-
assert "gtag('config', 'UA-123456-7');" in r
36+
assert "gtag('config', 'UA-123456-7', {});" in r
3737

3838
@override_settings(GOOGLE_ANALYTICS_GTAG_PROPERTY_ID=None)
3939
def test_no_property_id(self):
@@ -57,7 +57,7 @@ def test_render_internal_ip(self):
5757
@override_settings(ANALYTICAL_AUTO_IDENTIFY=True)
5858
def test_identify(self):
5959
r = GoogleAnalyticsGTagNode().render(Context({'user': User(username='test')}))
60-
assert "gtag('set', {'user_id': 'test'});" in r
60+
assert 'gtag(\'config\', \'UA-123456-7\', {"user_id": "test"});' in r
6161

6262
def test_identity_context_specific_provider(self):
6363
"""
@@ -68,12 +68,13 @@ def test_identity_context_specific_provider(self):
6868
Context(
6969
{
7070
'google_analytics_gtag_identity': 'foo_gtag_identity',
71-
'analytical_identity': 'bar_analytical_identity',
7271
'user': User(username='test'),
7372
}
7473
)
7574
)
76-
assert "gtag('set', {'user_id': 'foo_gtag_identity'});" in r
75+
assert (
76+
'gtag(\'config\', \'UA-123456-7\', {"user_id": "foo_gtag_identity"});' in r
77+
)
7778

7879
def test_identity_context_general(self):
7980
"""
@@ -87,7 +88,10 @@ def test_identity_context_general(self):
8788
}
8889
)
8990
)
90-
assert "gtag('set', {'user_id': 'bar_analytical_identity'});" in r
91+
assert (
92+
'gtag(\'config\', \'UA-123456-7\', {"user_id": "bar_analytical_identity"});'
93+
in r
94+
)
9195

9296
@override_settings(GOOGLE_ANALYTICS_GTAG_PROPERTY_ID='G-12345678')
9397
def test_tag_with_measurement_id(self):
@@ -96,7 +100,7 @@ def test_tag_with_measurement_id(self):
96100
'<script async src="https://www.googletagmanager.com/gtag/js?id=G-12345678"></script>'
97101
) in r
98102
assert "gtag('js', new Date());" in r
99-
assert "gtag('config', 'G-12345678');" in r
103+
assert "gtag('config', 'G-12345678', {});" in r
100104

101105
@override_settings(GOOGLE_ANALYTICS_GTAG_PROPERTY_ID='AW-1234567890')
102106
def test_tag_with_conversion_id(self):
@@ -105,7 +109,7 @@ def test_tag_with_conversion_id(self):
105109
'<script async src="https://www.googletagmanager.com/gtag/js?id=AW-1234567890"></script'
106110
) in r
107111
assert "gtag('js', new Date());" in r
108-
assert "gtag('config', 'AW-1234567890');" in r
112+
assert "gtag('config', 'AW-1234567890', {});" in r
109113

110114
@override_settings(GOOGLE_ANALYTICS_GTAG_PROPERTY_ID='DC-12345678')
111115
def test_tag_with_advertiser_id(self):
@@ -114,4 +118,47 @@ def test_tag_with_advertiser_id(self):
114118
'<script async src="https://www.googletagmanager.com/gtag/js?id=DC-12345678"></script>'
115119
) in r
116120
assert "gtag('js', new Date());" in r
117-
assert "gtag('config', 'DC-12345678');" in r
121+
assert "gtag('config', 'DC-12345678', {});" in r
122+
123+
def test_tag_with_custom_dimensions(self):
124+
r = GoogleAnalyticsGTagNode().render(
125+
Context(
126+
{
127+
'google_analytics_custom_dimensions': {
128+
'dimension_1': 'foo',
129+
'dimension_2': 'bar',
130+
'user_properties': {
131+
'user_property_1': True,
132+
'user_property_2': 'xyz',
133+
},
134+
},
135+
}
136+
)
137+
)
138+
assert (
139+
"gtag('config', 'UA-123456-7', {"
140+
'"dimension_1": "foo", '
141+
'"dimension_2": "bar", '
142+
'"user_properties": {'
143+
'"user_property_1": true, '
144+
'"user_property_2": "xyz"}});' in r
145+
)
146+
147+
def test_tag_with_identity_and_custom_dimensions(self):
148+
r = GoogleAnalyticsGTagNode().render(
149+
Context(
150+
{
151+
'google_analytics_gtag_identity': 'foo_gtag_identity',
152+
'google_analytics_custom_dimensions': {
153+
'dimension_1': 'foo',
154+
'dimension_2': 'bar',
155+
},
156+
}
157+
)
158+
)
159+
assert (
160+
"gtag('config', 'UA-123456-7', {"
161+
'"dimension_1": "foo", '
162+
'"dimension_2": "bar", '
163+
'"user_id": "foo_gtag_identity"});' in r
164+
)

0 commit comments

Comments
 (0)