Skip to content

Commit

Permalink
Merge pull request #84 from sikmir/yandex-metrica
Browse files Browse the repository at this point in the history
Support Yandex.Metrica
  • Loading branch information
jcassee committed May 25, 2016
2 parents 6de1b13 + fa034b0 commit cb3accc
Show file tree
Hide file tree
Showing 6 changed files with 231 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ Currently Supported Services
* `Spring Metrics`_ conversion tracking
* `UserVoice`_ user feedback and helpdesk
* `Woopra`_ web analytics
* `Yandex.Metrica`_ web analytics

.. _`Chartbeat`: http://www.chartbeat.com/
.. _`Clickmap`: http://getclickmap.com/
Expand All @@ -93,6 +94,7 @@ Currently Supported Services
.. _`Spring Metrics`: http://www.springmetrics.com/
.. _`UserVoice`: http://www.uservoice.com/
.. _`Woopra`: http://www.woopra.com/
.. _`Yandex.Metrica`: http://metrica.yandex.com

Documentation and Support
-------------------------
Expand Down
1 change: 1 addition & 0 deletions analytical/templatetags/analytical.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
'analytical.spring_metrics',
'analytical.uservoice',
'analytical.woopra',
'analytical.yandex_metrica',
]

logger = logging.getLogger(__name__)
Expand Down
93 changes: 93 additions & 0 deletions analytical/templatetags/yandex_metrica.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
"""
Yandex.Metrica template tags and filters.
"""

from __future__ import absolute_import

import json
import re

from django.conf import settings
from django.template import Library, Node, TemplateSyntaxError

from analytical.utils import is_internal_ip, disable_html, \
get_required_setting


COUNTER_ID_RE = re.compile(r'^\d{8}$')
COUNTER_CODE = """
<script type="text/javascript">
(function (d, w, c) {
(w[c] = w[c] || []).push(function() {
try {
w.yaCounter%(counter_id)s = new Ya.Metrika(%(options)s);
} catch(e) { }
});
var n = d.getElementsByTagName("script")[0],
s = d.createElement("script"),
f = function () { n.parentNode.insertBefore(s, n); };
s.type = "text/javascript";
s.async = true;
s.src = "https://mc.yandex.ru/metrika/watch.js";
if (w.opera == "[object Opera]") {
d.addEventListener("DOMContentLoaded", f, false);
} else { f(); }
})(document, window, "yandex_metrika_callbacks");
</script>
<noscript><div><img src="https://mc.yandex.ru/watch/%(counter_id)s" style="position:absolute; left:-9999px;" alt="" /></div></noscript>
"""


register = Library()


@register.tag
def yandex_metrica(parser, token):
"""
Yandex.Metrica counter template tag.
Renders Javascript code to track page visits. You must supply
your website counter ID (as a string) in the
``YANDEX_METRICA_COUNTER_ID`` setting.
"""
bits = token.split_contents()
if len(bits) > 1:
raise TemplateSyntaxError("'%s' takes no arguments" % bits[0])
return YandexMetricaNode()


class YandexMetricaNode(Node):
def __init__(self):
self.counter_id = get_required_setting(
'YANDEX_METRICA_COUNTER_ID', COUNTER_ID_RE,
"must be (a string containing) a number'")

def render(self, context):
options = {
'id': int(self.counter_id),
'clickmap': True,
'trackLinks': True,
'accurateTrackBounce': True
}
if getattr(settings, 'YANDEX_METRICA_WEBVISOR', False):
options['webvisor'] = True
if getattr(settings, 'YANDEX_METRICA_TRACKHASH', False):
options['trackHash'] = True
if getattr(settings, 'YANDEX_METRICA_NOINDEX', False):
options['ut'] = 'noindex'
if getattr(settings, 'YANDEX_METRICA_ECOMMERCE', False):
options['ecommerce'] = 'dataLayer'
html = COUNTER_CODE % {
'counter_id': self.counter_id,
'options': json.dumps(options),
}
if is_internal_ip(context, 'YANDEX_METRICA'):
html = disable_html(html, 'Yandex.Metrica')
return html


def contribute_to_analytical(add_node):
YandexMetricaNode() # ensure properly configured
add_node('head_bottom', YandexMetricaNode)
47 changes: 47 additions & 0 deletions analytical/tests/test_tag_yandex_metrica.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""
Tests for the Yandex.Metrica template tags and filters.
"""

import re

from django.contrib.auth.models import User, AnonymousUser
from django.http import HttpRequest
from django.template import Context
from django.test.utils import override_settings

from analytical.templatetags.yandex_metrica import YandexMetricaNode
from analytical.tests.utils import TagTestCase
from analytical.utils import AnalyticalException


@override_settings(YANDEX_METRICA_COUNTER_ID='12345678')
class YandexMetricaTagTestCase(TagTestCase):
"""
Tests for the ``yandex_metrica`` template tag.
"""

def test_tag(self):
r = self.render_tag('yandex_metrica', 'yandex_metrica')
self.assertTrue("w.yaCounter12345678 = new Ya.Metrika" in r, r)

def test_node(self):
r = YandexMetricaNode().render(Context({}))
self.assertTrue("w.yaCounter12345678 = new Ya.Metrika" in r, r)

@override_settings(YANDEX_METRICA_COUNTER_ID=None)
def test_no_site_id(self):
self.assertRaises(AnalyticalException, YandexMetricaNode)

@override_settings(YANDEX_METRICA_COUNTER_ID='1234abcd')
def test_wrong_site_id(self):
self.assertRaises(AnalyticalException, YandexMetricaNode)

@override_settings(ANALYTICAL_INTERNAL_IPS=['1.1.1.1'])
def test_render_internal_ip(self):
req = HttpRequest()
req.META['REMOTE_ADDR'] = '1.1.1.1'
context = Context({'request': req})
r = YandexMetricaNode().render(context)
self.assertTrue(r.startswith(
'<!-- Yandex.Metrica disabled on internal IP address'), r)
self.assertTrue(r.endswith('-->'), r)
4 changes: 4 additions & 0 deletions docs/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@ settings required to enable each service are listed here:

WOOPRA_DOMAIN = 'abcde.com'

* :doc:`Yandex.Metrica <services/yandex_metrica>`::

YANDEX_METRICA_COUNTER_ID = '12345678'

----

The django-analytical application is now set-up to track visitors. For
Expand Down
84 changes: 84 additions & 0 deletions docs/services/yandex_metrica.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
==================================
Yandex.Metrica -- traffic analysis
==================================

`Yandex.Metrica`_ is an analytics tool like as google analytics.

.. _`Yandex.Metrica`: http://metrica.yandex.com/


.. yandex-metrica-installation:
Installation
============

To start using the Yandex.Metrica 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 Yandex.Metrica 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:`yandex-metrica-configuration`.

The Yandex.Metrica counter code is inserted into templates using a template
tag. Load the :mod:`yandex_metrica` template tag library and insert the
:ttag:`yandex_metrica` tag. Because every page that you want to track must
have the tag, it is useful to add it to your base template. Insert
the tag at the bottom of the HTML head::

{% load yandex_metrica %}
<html>
<head>
...
{% yandex_metrica %}
</head>
...


.. _yandex-metrica-configuration:

Configuration
=============

Before you can use the Yandex.Metrica integration, you must first set
your website counter ID.


.. _yandex-metrica-counter-id:

Setting the counter ID
----------------------

Every website you track with Yandex.Metrica gets its own counter ID,
and the :ttag:`yandex_metrica` tag will include it in the rendered
Javascript code. You can find the web counter ID on the overview page
of your account. Set :const:`YANDEX_METRICA_COUNTER_ID` in the
project :file:`settings.py` file::

YANDEX_METRICA_COUNTER_ID = '12345678'

If you do not set a counter ID, the counter code will not be rendered.

You can set additional options to tune your counter:

============================ ============= =============================================
Constant Default Value Description
============================ ============= =============================================
``YANDEX_METRICA_WEBVISOR`` False Webvisor, scroll map, form analysis.
``YANDEX_METRICA_TRACKHASH`` False Hash tracking in the browser address bar.
``YANDEX_METRICA_NOINDEX`` False Stop automatic page indexing.
``YANDEX_METRICA_ECOMMERCE`` False Dispatch ecommerce data to Metrica.
============================ ============= =============================================

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:`YANDEX_METRICA_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.

0 comments on commit cb3accc

Please sign in to comment.