Облегченная веб-аналитика с нуля без использования баннера cookie с использованием React и Python.

Я покажу вам, как создать собственную веб-аналитику в нескольких строках кода.

Создание собственной веб-аналитики может иметь много преимуществ:

  • Вам не нужно передавать пользовательские данные третьим лицам
  • Вы уменьшите общий размер скрипта
  • Вы можете выбрать, какие данные собирать
  • Вы можете избежать баннера cookie

Мы будем использовать React для внешнего интерфейса и Python с PostgreSQL для внутреннего интерфейса.

Как мы можем избежать баннера cookie?

Баннеры cookie могут негативно повлиять на взаимодействие пользователей с вашей страницей.

Чтобы избежать их, вам необходимо соответствовать определенным критериям Директивы о конфиденциальности (закон о файлах cookie) и GDPR.

Эти правила сложны, но вкратце это означает, что вы не можете создавать какие-либо постоянные идентификаторы и не можете собирать или хранить какие-либо личные или идентифицируемые данные.

Это не юридическая консультация, а только моя личная интерпретация. Вы можете провести собственное исследование, начав с веб-сайта GDPR.

Внедрив эти правила, вы не сможете отслеживать пользователей на разных устройствах или в течение нескольких дней.

Вы сможете измерить только самые важные точки данных. Цель состоит в том, чтобы отслеживать общие тенденции и выявлять проблемы с производительностью и ошибки.

Какие данные мы будем собирать?

Мы будем собирать следующее:

  • URL-адрес страницы
  • Время, проведенное на странице
  • HTTP-референт
  • Версия браузера и операционной системы
  • Ширина окна
  • Страна
  • Статус установки PWA (это бонус для PWA 😊)
  • анонимный идентификатор

Чтобы иметь возможность подсчитывать уникальных посетителей за один день, не сохраняя файлы cookie или другие идентифицирующие данные, мы хэшируем IP-адрес пользователя и версию браузера с постоянно меняющимся числом, которое меняется каждый день. Мы называем это анонимным идентификатором.

Как это будет работать?

Чтобы показать вам, как это будет работать, давайте возьмем пример, основанный на работающей реализации моего веб-приложения PetiteCarrot.com:

Предположим, вы посещаете https://petitecarrot.com.

Через 10 секунд на этой странице вы переходите на другую: https://petitecarrot.com/nutrient/calories.

Вы задерживаетесь еще на 5 секунд и переходите к третьему: https://petitecarrot.com/food-category/foods-high-in-vitamin-c.

Вы, наконец, остаетесь за 60 секунд до «ухода».

Определим, что именно означает «уходить» последним.

Непосредственно перед «уходом» браузер отправит нашему бэкэнду запрос HTTPS POST, содержащий следующий JSON:

{
 "d":"2022–02–17T16:07:36.726Z",
 "r":"https://medium.com",
 "w":756,
 "i":true,
 "p":{
   "/" : [1, 10],
   "/nutrient/calories" : [2, 5],
   "/food-category/foods-high-in-vitamin-c" : [3, 60]
 }
}

Параметры:

  • d: временная метка пользователя, «уходящего» с последней страницы.
  • r: реферер HTTP
  • w: ширина экрана пользователя
  • i: статус установки PWA
  • p: словарь, представляющий порядок навигации и время, затраченное на страницу.

При получении запроса наш API Python сохранит эти данные в дополнение к версии браузера и операционной системы, содержащейся в заголовке запроса.

Мы будем использовать IP-адрес из запроса, чтобы получить страну и создать анонимный идентификатор. Затем мы откажемся от IP.

Теперь давайте углубимся в код.

Бэкэнд

Мы используем PostgreSQL для базы данных, SQLAlchemy для ORM и FastAPI для Python API.

База данных и ORM

SQLAlchemy — это ORM (реляционное сопоставление объектов), которое позволяет нам запрашивать нашу базу данных, используя классы и функции Python.

Во-первых, мы определяем наш создатель сеанса ORM:

Нам нужно будет искать страну IP-адреса на лету, прежде чем отбрасывать IP-адрес.

Для этого нам нужно хранить все диапазоны IP-адресов по странам.

Вы можете скачать csv-файл с сайта Maxmind.

Диапазоны IP-адресов выражаются в CIDR (бесклассовая междоменная маршрутизация).

PostgreSQL поддерживает тип CIDR, поэтому мы можем напрямую сохранять диапазоны IP-адресов в этом формате.

Тем не менее, мы можем повысить производительность чтения, преобразовав CIDR в диапазоны целых чисел с комбинацией индекса обобщенного дерева поиска (GIST). На моей машине время запроса сократилось с 60 мс до 3 мс.

Давайте напишем нашу модель ORM, не забывая индекс GIST:

Мы создали две разные таблицы для IPv4 и Ipv6, чтобы ускорить поиск.

Мы использовали тип INT8RANGE для Ipv4 и тип NUMRANGE для Ipv6 из PostgreSQL.

Теперь нам нужна функция для загрузки CSV-файла, содержащего диапазоны IP-адресов по странам, и сохранения их в нашей базе данных. Единственная сложная часть — преобразование строки CIDR в тип числового диапазона из PostgreSQL:

Я позволю вам завершить этот код для IPv6. Я не буду подробно описывать всю функцию, так как она не слишком сложна.

Теперь давайте определим наши две таблицы Analytics:

Обратите внимание на отношение «многие к одному», используемое для сохранения словаря страниц из нашего JSON.

Наконец, мы можем создать все таблицы базы данных с помощью:

Base.metadata.create_all(engine)

Не забудьте сохранить все диапазоны IP по странам с помощью файла csv.

API

В качестве API мы будем использовать FastAPI, современный и высокопроизводительный веб-фреймворк для создания API с помощью Python.

Во-первых, мы определяем нашу функцию get_session, которая будет создавать новый сеанс базы данных для каждого запроса:

Затем мы определяем нашу модель данных Analytics с помощью Pydantic.

FastAPI будет использовать его для проверки параметров запроса:

Вы всегда должны проверять каждый ввод перед сохранением их в базе данных. FastAPI уже проверяет модель данных, но вам следует добавить дополнительную проверку длины строки и размера списка.

Теперь давайте создадим функцию для анонимизации IP-адреса.

Помните, мы хотим подсчитывать уникальных пользователей в день. Однако одного IP-адреса недостаточно, поскольку несколько пользователей могут иметь один и тот же IP-адрес (например, студенты, использующие университетский Wi-Fi).

Чтобы добавить больше детализации, мы используем версию браузера и операционной системы (пользовательский агент).

Нам также нужно добавить день в хеш-функцию, иначе мы сможем отслеживать идентификаторы пользователей с течением времени, делая их «идентифицируемыми».

То, как GDPR определяет термин «идентифицируемый», можно интерпретировать. Некоторые могут возразить, что хеширования IP и пользовательского агента достаточно. Не стесняйтесь высказать свою точку зрения в комментариях.

У нас есть много вариантов хеширования нашей вновь созданной строки. Здесь мы выбираем алгоритм XXH64 из xxhash. Это чрезвычайно быстрый некриптографический алгоритм хеширования:

Теперь мы создаем нашу функцию save_analytics, которая будет сохранять данные аналитики в базе данных. Я также покажу вам функцию для запроса country_id с помощью оператора contains "@>" из PostgreSQL:

Наконец, мы создаем конечную точку API:

Теперь вы можете протестировать свой API локально с помощью:

uvicorn api:app --port 8000 --host=0.0.0.0 --reload

Фронтенд

Для фронтенда будем использовать React. Код тот же, если вы хотите использовать NextJS.

Мы переопределяем приложение по умолчанию, создавая новый файл ./pages/_app.js.

Чтобы избежать отправки аналитических данных после каждого изменения страницы, мы будем использовать событие visibilitychange, которое срабатывает, когда пользователь «покидает» приложение.

Это повысит производительность и уменьшит количество запросов к API.

Событие visibilitychange возникает, когда пользователь переходит на новую страницу, переключает вкладки, сворачивает или закрывает вкладку, закрывает браузер или переключается на другое приложение.

Не забудьте сбросить состояние аналитики, когда пользователь вернется в приложение. Для этой цели мы используем document.visibilityState:

И это все для фронтенда! Это меньше 1 КБ после сжатия, что является огромным улучшением по сравнению с ~ 40 КБ от Google Analytics.

Визуализация данных

Я оставил забавную часть на конец: построение ваших данных.

Мы будем использовать Plotly для создания красивых интерактивных HTML-кодов. Вы можете добавить их на панель аналитики или просто интегрировать в отчеты по электронной почте.

Построим график количества посетителей в день и страны:

С помощью SQLAlchemy, Pandas и Plotly это действительно быстро:

Теперь у вас есть все инструменты для создания полноценной панели аналитики.

Заключение

И вуаля! Вы только что создали собственную веб-аналитику, эффективную, легкую и уважающую конфиденциальность ваших пользователей.

Кроме того, вы улучшили взаимодействие с пользователем, удалив баннер cookie.

Спасибо за чтение этого.