diff --git a/docs/user/advertising/advertising-details.rst b/docs/user/advertising/advertising-details.rst index b0cc218d723..a8f59603c06 100644 --- a/docs/user/advertising/advertising-details.rst +++ b/docs/user/advertising/advertising-details.rst @@ -107,24 +107,14 @@ Analytics --------- Analytics are a sensitive enough issue that they require their own section. -In the spirit of full transparency, Read the Docs uses Google Analytics (GA). -We go into a bit of detail on our use of GA in our :doc:`/privacy-policy`. -GA is a contentious issue inside Read the Docs and in our community. +Google Analytics is a contentious issue inside Read the Docs and in our community. Some users are very sensitive and privacy conscious to usage of GA. Some authors want their own analytics on their docs to see the usage their docs get. The developers at Read the Docs understand that different users have different priorities and we try to respect the different viewpoints as much as possible while also accomplishing our own goals. -We have taken steps to address some of the privacy concerns surrounding GA. -These steps apply to analytics only collected by Read the Docs, -since project authors could follow a different policy if they add GA to their projects. - -* Users can opt-out of analytics by using the Do Not Track feature of their browser. -* Read the Docs instructs Google to anonymize IP addresses sent to them. -* The cookie set by GA is a session (non-persistent) cookie rather than the default 2 years. - Why we use analytics ~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/user/guides/content/index.rst b/docs/user/guides/content/index.rst index 9451823e2bb..a9da61f0a5f 100644 --- a/docs/user/guides/content/index.rst +++ b/docs/user/guides/content/index.rst @@ -10,7 +10,6 @@ How-to guides: content, themes and SEO ⏩️ :doc:`Using traffic analytics ` In this guide, you can learn to use Read the Docs' built-in traffic analytics for your documentation project. - You will also learn how to optionally add your own Google Analytics account or completely disable Google Analytics on your project. ⏩️ :doc:`Managing translations for Sphinx projects ` This guide walks through the process needed to manage translations of your documentation. diff --git a/docs/user/legal/dpa/subprocessors.rst b/docs/user/legal/dpa/subprocessors.rst index 2b9ba92d500..e1470804397 100644 --- a/docs/user/legal/dpa/subprocessors.rst +++ b/docs/user/legal/dpa/subprocessors.rst @@ -2,7 +2,7 @@ Sub-processor list ================== :Effective: April 16, 2021 -:Last updated: December 27, 2022 +:Last updated: August 9, 2024 Read the Docs for Business uses services from the following sub-processors to provide documentation hosting services. This document supplements :doc:`our Data @@ -34,8 +34,8 @@ Sendgrid, Inc. and other generated messages. The body of notification emails can include user information, including email address. -Google Analytics - Website analtyics for dashboard and documentation sites. +Plausible + Website analytics for dashboard and Read the Docs owned documentation sites. Stripe Inc. Subscription payment provider. Data collected can include user data necessary diff --git a/docs/user/privacy-policy.rst b/docs/user/privacy-policy.rst index 61808579921..6b2c9dbd6da 100644 --- a/docs/user/privacy-policy.rst +++ b/docs/user/privacy-policy.rst @@ -192,7 +192,7 @@ Analytics +++++++++ We go into detail on analytics in a -:ref:`separate section specific to analytics `. +:ref:`separate section specific to analytics `. Support desk ++++++++++++ @@ -236,8 +236,6 @@ and the `EFF's DNT Policy`_. For Read the Docs, this means: * We **do not** do behavioral ad targeting regardless of your DNT preference. -* When DNT is enabled, both logged-in and logged-out users - are considered opted-out of :ref:`analytics `. * Regardless of DNT preference, our logs that contain IP addresses and user agent strings are deleted after 10 days unless a DNT exception applies. * Our full DNT policy is `available here`_. @@ -277,29 +275,23 @@ By using our website, you agree that we can place these types of cookies on your If you disable your browser or device's ability to accept cookies, you will not be able to log in to Read the Docs. -Google Analytics -~~~~~~~~~~~~~~~~ +Plausible +~~~~~~~~~ -We use Google Analytics as a third party tracking service, +We use Plausible as a third party analytics service, but we don't use it to track you individually or collect your User Personal Information. -We use Google Analytics to collect information about how our website performs +We use Plausible to collect information about how our website performs and how our users, in general, navigate through and use Read the Docs. This helps us evaluate our users' use of Read the Docs; compile statistical reports on activity; and improve our content and website performance. -Google Analytics gathers certain simple, non-personally identifying information over time, -such as your IP address, browser type, internet service provider, referring and exit pages, +Plausible gathers certain simple, non-personally identifying information over time, +such as browser type, internet service provider, referring and exit pages, time stamp, and similar data about your use of Read the Docs. We do not link this information to any of your personal information such as your user name. Read the Docs will not, nor will we allow any third party to, -use the Google Analytics tool to track our users individually; -collect any User Personal Information other than IP address; -or correlate your IP address with your identity. -Google provides further information about its own privacy practices and offers a -`browser add-on to opt out of Google Analytics tracking `_. -You may also opt-out of analytics on Read the Docs by enabling -:ref:`Do Not Track `. +use the Plausible tool to track our users individually or collect any User Personal Information. How Read the Docs secures your information diff --git a/docs/user/reference/analytics.rst b/docs/user/reference/analytics.rst index 9956a1f76a9..f972b564eca 100644 --- a/docs/user/reference/analytics.rst +++ b/docs/user/reference/analytics.rst @@ -20,8 +20,7 @@ Traffic Analytics lets you see *which* documents your users are reading. This allows you to understand how your documentation is being used, so you can focus on expanding and updating parts people are reading most. -If you require more detailed analytics, Read the Docs has native support for Google Analytics. -It's also possible to customize your documentation to include other analytics frameworks. +If you require more detailed analytics it's possible to customize your documentation to include other analytics tools. Learn more in :doc:`/analytics`. diff --git a/readthedocs/analytics/tasks.py b/readthedocs/analytics/tasks.py index 8a37e46e639..7d0d9e56974 100644 --- a/readthedocs/analytics/tasks.py +++ b/readthedocs/analytics/tasks.py @@ -7,8 +7,6 @@ import readthedocs from readthedocs.worker import app -from .utils import send_to_analytics - DEFAULT_PARAMETERS = { "v": "1", # analytics version (always 1) "aip": "1", # anonymize IP @@ -22,52 +20,6 @@ } -@app.task(queue="web") -def analytics_pageview(url, title=None, **kwargs): - """ - Send a pageview to Google Analytics. - - :see: https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters - :param url: the URL of the pageview - :param title: the title of the page being viewed - :param kwargs: extra pageview parameters to send to GA - """ - data = { - "t": "pageview", - "dl": url, # URL of the pageview (required) - "dt": title, # Title of the page - } - data.update(DEFAULT_PARAMETERS) - data.update(kwargs) - send_to_analytics(data) - - -@app.task(queue="web") -def analytics_event( - event_category, event_action, event_label=None, event_value=None, **kwargs -): - """ - Send an analytics event to Google Analytics. - - :see: https://developers.google.com/analytics/devguides/collection/protocol/v1/devguide#event - :param event_category: the category of the event - :param event_action: the action of the event (use action words like "click") - :param event_label: an optional string to differentiate the event - :param event_value: an optional numeric value for the event - :param kwargs: extra event parameters to send to GA - """ - data = { - "t": "event", # GA event - don't change - "ec": event_category, # Event category (required) - "ea": event_action, # Event action (required) - "el": event_label, # Event label - "ev": event_value, # Event value (numeric) - } - data.update(DEFAULT_PARAMETERS) - data.update(kwargs) - send_to_analytics(data) - - @app.task(queue="web") def delete_old_page_counts(): """ diff --git a/readthedocs/analytics/utils.py b/readthedocs/analytics/utils.py index 94dd0c4f14c..71e4c32cc42 100644 --- a/readthedocs/analytics/utils.py +++ b/readthedocs/analytics/utils.py @@ -3,7 +3,6 @@ import hashlib import ipaddress -import requests import structlog from django.conf import settings from django.utils.crypto import get_random_string @@ -62,34 +61,6 @@ def anonymize_user_agent(user_agent): return user_agent -def send_to_analytics(data): - """Sends data to Google Analytics.""" - if data.get("uip") and data.get("ua"): - data["cid"] = generate_client_id(data["uip"], data["ua"]) - - if data.get("uip"): - # Anonymize IP address if applicable - data["uip"] = anonymize_ip_address(data["uip"]) - - if data.get("ua"): - # Anonymize user agent if it is rare - data["ua"] = anonymize_user_agent(data["ua"]) - - resp = None - log.debug("Sending data to analytics.", data=data) - try: - resp = requests.post( - "https://www.google-analytics.com/collect", - data=data, - timeout=3, # seconds - ) - except requests.Timeout: - log.warning("Timeout sending to Google Analytics") - - if resp and not resp.ok: - log.warning("Unknown error sending to Google Analytics") - - def generate_client_id(ip_address, user_agent): """ Create an advertising ID. diff --git a/readthedocs/proxito/views/mixins.py b/readthedocs/proxito/views/mixins.py index e725c7372cc..0b014115275 100644 --- a/readthedocs/proxito/views/mixins.py +++ b/readthedocs/proxito/views/mixins.py @@ -14,8 +14,6 @@ from django.views.static import serve from slugify import slugify as unicode_slugify -from readthedocs.analytics.tasks import analytics_event -from readthedocs.analytics.utils import get_client_ip from readthedocs.audit.models import AuditLog from readthedocs.builds.constants import INTERNAL from readthedocs.core.resolver import Resolver @@ -120,15 +118,6 @@ def _serve_dowload(self, request, project, version, type_): download=True, ) - # Send media download to analytics - sensitive data is anonymized - analytics_event.delay( - event_category="Build Media", - event_action=f"Download {type_}", - event_label=str(version), - ua=request.headers.get("User-Agent"), - uip=get_client_ip(request), - ) - response = self._serve_file( request=request, storage_path=storage_path,