Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed gtag user_id setup and added support for custom dimensions #226

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 8 additions & 13 deletions analytical/templatetags/google_analytics_gtag.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
"""
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
Expand All @@ -21,13 +22,10 @@
function gtag(){{dataLayer.push(arguments);}}
gtag('js', new Date());

{extra}
gtag('config', '{property_id}');
gtag('config', '{property_id}', {custom_dimensions});
</script>
"""

GTAG_SET_CODE = """gtag('set', {{'{key}': '{value}'}});"""

register = Library()


Expand Down Expand Up @@ -55,18 +53,15 @@ def __init__(self):
'G-XXXXXXXX', 'DC-XXXXXXXX')''')

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')
Expand Down
45 changes: 45 additions & 0 deletions docs/services/google_analytics_gtag.rst
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,48 @@ 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::
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use an explicit code-block here, as in the examples above.

.. code-block:: python

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Added here


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`::
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use an explicit code-block here (instead of ::), as in the examples above.

.. code-block:: python

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added here


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
50 changes: 40 additions & 10 deletions tests/unit/test_tag_google_analytics_gtag.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
@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):
Expand All @@ -25,15 +25,15 @@ def test_tag(self):
'<script async src="https://www.googletagmanager.com/gtag/js?id=UA-123456-7"></script>'
) 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())
assert (
'<script async src="https://www.googletagmanager.com/gtag/js?id=UA-123456-7"></script>'
) 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):
Expand All @@ -57,7 +57,7 @@ def test_render_internal_ip(self):
@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):
"""
Expand All @@ -66,10 +66,9 @@ def test_identity_context_specific_provider(self):
"""
r = GoogleAnalyticsGTagNode().render(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):
"""
Expand All @@ -79,7 +78,7 @@ def test_identity_context_general(self):
'analytical_identity': 'bar_analytical_identity',
'user': User(username='test'),
}))
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):
Expand All @@ -88,7 +87,7 @@ def test_tag_with_measurement_id(self):
'<script async src="https://www.googletagmanager.com/gtag/js?id=G-12345678"></script>'
) 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):
Expand All @@ -97,7 +96,7 @@ def test_tag_with_conversion_id(self):
'<script async src="https://www.googletagmanager.com/gtag/js?id=AW-1234567890"></script'
) in r
assert "gtag('js', new Date());" in r
assert "gtag('config', 'AW-1234567890');" in r
assert "gtag('config', 'AW-1234567890', {});" in r

@override_settings(GOOGLE_ANALYTICS_GTAG_PROPERTY_ID='DC-12345678')
def test_tag_with_advertiser_id(self):
Expand All @@ -106,4 +105,35 @@ def test_tag_with_advertiser_id(self):
'<script async src="https://www.googletagmanager.com/gtag/js?id=DC-12345678"></script>'
) 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