5 заметок с тегом

google analytics

Проблема Roistat как готового решения для аналитики

Время чтения текста – 16 минут

Нередко компании, которые обращаются к нам за системой сквозной аналитики, уже используют какие-то инструменты для работы с данными. Иногда это «коробочные» решения. Сразу отказываться от них в пользу кастома не обязательно — на старте их можно интегрировать в новую систему, чтобы сэкономить время и деньги на разработку. Но в этом случае надо быть готовым к тому, что готовые решения не гарантируют точность данных на том же уровне, что специально построенная под вас система аналитики. Именно с этой проблемой мы столкнулись, когда начали строить аналитику для стартапа Refocus: до нас они использовали Roistat, но ошибки в его работе вынудили нас отказаться от него раньше, чем мы планировали.

Способов построить сквозную аналитику, не обращаясь к готовым решениям, немало: можно собрать in-house отдел аналитики или найти специалистов на аутсорсе.

При этом нужно учитывать, что работа целой команды аналитики может стоить порядка 5-7 тысяч евро или 500-700 тысяч рублей в месяц. И это не предел — все зависит от размеров компании-заказчика, состояния аналитики до начала работ и других факторов.

На начальном этапе для многих компаний, у которых объем данных небольшой, такие расходы неоправданы. Из-за этого они часто предпочитают «коробочные» продукты — например, тот же Roistat. Это самое популярное решение на рынке, которое предлагает премиум-тариф с максимумом функционала и полной поддержкой от 1500 евро / 150 тысяч рублей в месяц. Базовые тарифы у них и того дешевле. У этого инструмента больше 200 встроенных интеграций, и не только с популярными Google Analytics или Яндекс Директ, но и с целым списком нишевых кабинетов и систем, о которых вы даже не слышали.

После настройки интеграций с вашими источниками Roistat позволит создать дашборды за пару кликов, а сверху предложит автоматизацию маркетинга и лидогенерации. Конкуренты Roistat вроде OWOX BI или Alytics также предоставляют базовые возможности для аналитики и визуализации. В общем, недорогих решений под любые потребности много.

Хотя “коробка” гораздо лучше бесконечных таблиц и поначалу хорошо оптимизирует работу с данными, она далеко не идеальна. С точки зрения эксперта все минусы универсальных решений видны как на ладони:

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

Кроме того, у вендоров таких готовых решений почти никогда нет ресурсов и возможностей, чтобы подогнать его под специфические требования каждого клиента. Более того, чаще такие “кастомные” требования многократно превосходят стоимость самой коробки (в этом суть готового решения). Если что-то не так на бэке у юзера, если меняется воронка в CRM, если нужно настроить кастомные интеграции — велики шансы, что за это придется доплатить немаленькие деньги, если вендор вообще согласится реализовать эти “специфичные требования”.

На одном из наших проектов нам довелось поработать именно с такой ситуацией: Roistat не смог обеспечить точность данных и интеграций со всеми нужными источниками, и с этим пришлось разбираться самой компании — и нам.

Как Refocus работал с аналитикой

Один из наших заказчиков, который строил аналитику на самых ранних этапах — EdTech-стартап Refocus. Неудивительно, что когда мы пришли создавать для них кастомную систему, они уже работали с Roistat.

Почему Refocus выбрали именно его? Во-первых, он доступен на русском языке, и это было удобно для команды, в которой много русскоязычных сотрудников. Во-вторых, им нужна была именно система сквозной аналитики, а не CRM с функцией автоматического построения графиков, поэтому альтернативы вроде HubSpot не подходили. В-третьих, все базовые потребности компании он удовлетворял за относительно небольшую сумму. Ну и в-четвертых — многие сотрудники из команды Refocus уже имели опыт работы с Roistat, так что для них это был удобный и знакомый инструмент.

Roistat тянул данные из двух основных рекламных кабинетов — Google и Facebook*. В нем трекались все базовые метрики — бюджеты, показы, клики, конверсия — и отражались на автоматически созданных внутри программы дашбордах.

К сожалению, скрины дашбордов из Roistat у нас не сохранились, но мы нашли для вас пример в интернете — выглядели они примерно так.

Там даже присутствовал свой пользовательский идентификатор — когда мы вводили общий айди студентов, мы думали попробовать использовать его для мэтчинга персональных данных. На практике оказалось, что сопоставление по нему проходит очень неточно, и эту идею оставили.

Стартап рос, число требований и людей увеличилось, поэтому нас позвали строить для ребят кастомную аналитику и более подробные дашборды, и подключились мы.

Как обнаружилась проблема

Мы провели аудит существующей системы, получили доступы к нужным ресурсам и начали выстраивать инфраструктуру и готовить первый дашборд — маркетинговый, самый актуальный для компании на тот момент.

Откуда мы тянули данные для этого дашборда? Конечно, из Roistat, ведь именно там уже лежали готовые маркетинговые показатели. Настройка хранилища и выгрузка данных из источников, которые Roistat не трекал, еще не была закончена, а смотреть на классные, качественные дашборды хотелось уже сейчас.

Например, так выглядел код для выгрузки данных о затратах на рекламу через API:

def get_costs(channel, channel_level, date_from, date_to, source):
         
     data = '{"dimensions": ["marker_level_2", "marker_level_3", "marker_level_4"],\
     "metrics":["visitsCost", "impressions", "visits"],\
     "period":{"from":"' + date_from + '","to":"' + date_to + '"},\
     "filters":[{"field":"' + channel_level + '", "operation":"=", "value":"' + channel + '"}],\
     "interval": "1d"}'
     columns=['dimensions.marker_level_2.value',
             'dimensions.marker_level_2.title',
             'dimensions.marker_level_3.value',
             'dimensions.marker_level_3.title',
             'dimensions.marker_level_4.value',
             'dimensions.marker_level_4.title',
             'dateFrom'
             ]
     headers = {'content-type': 'application/json'}

     response = requests.request("POST", url, data=data, headers=headers)
     df = response.json()['data']

     l = []
     for i in range(len(df)):
         if df[i]['items'] != []:
             l.append(df[i])
     if len(l) > 0:
         res1 = pd.json_normalize(l, 'items', ['dateFrom'])[columns]
         res2 = pd.DataFrame()
         q = pd.json_normalize(l, ['items', 'metrics'])
         for x in ["visitsCost", "impressions", "visits"]:
             res2[x] = q.query('metric_name == @x')['value'].values
         res = pd.concat([res1, res2], axis=1)
         res['source'] = source
         return res
     else:
         return pd.DataFrame()

Подробнее о marker_levels можно прочитать здесь в документации API Roistat.

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

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

Дело в том, что пока компания смотрела только на визуализации Roistat, расхождения в данных не бросались в глаза. А наш дашборд содержал несколько новых графиков, более подробных, чем мог предложить Roistat. Когда Refocus стали сравнивать детали по разным срезам, на которые Roistat не позволял посмотреть, расхождения стали очевидны.

У нас дашборд был более гибкий — можно было отфильтровать данные по разным важным срезам, более тонко настроить гранулярность. И благодаря этому ошибки в метриках стали заметны.

Об этом мы и сообщили коллегам, продемонстрировав совпадение. Как раз в этот момент сыграл роль недостаток закрытой системы — посмотреть внутрь Roistat и найти, где именно происходит ошибка, не могли ни мы, ни бэкенд-специалисты Refocus.

Разумеется, кастомная система уже предполагала отключение этого источника в будущем — зачем платный посредник, если мы все равно будем грузить данные напрямую и из рекламных кабинетов, и из кучи других источников?

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

Полностью отказаться от Roistat сразу не получилось, поэтому мы добавили на дашборд фильтр “match with Roistat”.

На нем мы отмечали количество рекламных кампаний, данные по которым расходятся с показателями на нашем дашборде и на Roistat’овском.

Как мы наконец заменили Roistat на кастомную систему и уточнили данные о воронках

Мы сразу написали несколько скриптов для выгрузки тех же самых данных из GA4 и Facebook Ads* через API.
Например, так данные о рекламных показах, затратах и кликах за день в разрезе {campaign, adset, adname} выгружались из кабинета GA4:

def get_google_costs(date_start, customer_id):

    request = RunReportRequest(
        property = f"properties/{property_id}",
        dimensions = [Dimension(name = "date"),
                     Dimension(name = "sessionGoogleAdsCustomerId"),
                     Dimension(name = "sessionGoogleAdsCampaignId"),
                     Dimension(name = "sessionGoogleAdsCampaignName"),
                     Dimension(name = "sessionGoogleAdsAdGroupId"),
                     Dimension(name = "sessionGoogleAdsAdGroupName"),
                     Dimension(name = "sessionGoogleAdsCreativeId")],
        metrics = [Metric(name="advertiserAdCost"),
                   Metric(name="advertiserAdImpressions"),
                   Metric(name='advertiserAdClicks')],
        date_ranges = [DateRange(start_date = date_start, end_date = date_start)],
        dimension_filter = FilterExpression(
            filter = Filter(
                field_name = "sessionGoogleAdsCustomerId",
                string_filter = Filter.StringFilter(value = customer_id),
            )
        ),
    )
    response = client.run_report(request)

    date = map(lambda x: x.dimension_values[0].value, response.rows)
    customer_id = map(lambda x: int(x.dimension_values[1].value), response.rows)
    campname_id = map(lambda x: int(x.dimension_values[2].value), response.rows)
    campname = map(lambda x: x.dimension_values[3].value, response.rows)
    groupname_id = map(lambda x: int(x.dimension_values[4].value), response.rows)
    groupname = map(lambda x: x.dimension_values[5].value, response.rows)
    adnam_id = map(lambda x: int(x.dimension_values[6].value), response.rows)
    visitsCost = map(lambda x: float(x.metric_values[0].value), response.rows)
    impressions = map(lambda x: int(x.metric_values[1].value), response.rows)
    visits = map(lambda x: int(x.metric_values[2].value), response.rows)

    df = pd.DataFrame({'region': customer_id, 'date': date, 'campname': campname, 'groupname': groupname, 'campname_id': campname_id, 'groupname_id': groupname_id, 'adnam_id': adnam_id, 'visitsCost': visitsCost, 'impressions': impressions, 'visits': visits})
    return df

df = pd.DataFrame()

После этого обнаружилось еще одно несовпадение: метрики в самом кабинете были чуть меньше, чем у нас на дашбордах. Отклонение не было критичным, но клиент снова не был уверен в точности наших данных.

Оказалось, что в GA4 по умолчанию включается настройка Thresholding applied. Ее цель — предотвратить возможную идентификацию отдельных пользователей по данным о возрасте, гендере и интересах. В результате ее применения терялись данные о кампаниях с небольшим (меньше 50) количеством кликов. Чтобы этого избежать, нужно было или не трекать эти показатели, или не использовать в дашбордах метрики, касающиеся пользователей напрямую. Roistat тоже не выгружал эти “пограничные” кампании через свою дефолтную интеграцию с GA4, поэтому для Refocus расхождение стало неожиданностью. Зато при прямой выгрузке через API этого ограничения не было, и ускользнувшие поначалу кампании считались, так что данные были более полными без дополнительных ухищрений.

С добавлением все новых и новых источников, конечно, пришлось еще и мэтчить данные рекламных кабинетов о затратах, кликах и показах с записями на вебинары и их посещением, со сделками в CRM — но Roistat этого вовсе не делал, и поэтому не мог дать полной картины о воронках.

После введения прямой выгрузки из рекламных кабинетов данные наконец-то стали полностью совпадать с реальностью, и Roistat отключили, заменив другими источниками. Теперь Refocus могли не платить дважды и получить куда более точный анализ.

Выводы

Кастомная сквозная аналитика — конечно, не панацея, и есть много причин и возможностей обойтись без услуг агентств, которые ее строят. Тем не менее, даже самое популярное на рынке коробочное решение, очевидно, не всегда корректно работает. Обрубать его сразу не обязательно, и ничего не мешает сочетать Roistat и похожие продукты с кастомом. В конце концов, иногда удобно просто достроить интеграции, которые не поддерживает Roistat, и держать дашборды в нем. Но в этом случае важно понимать, что данные там могут быть неполными или некорректными, а сообщение с бэком компании — ненадежным. В результате обнаружить или исправить ошибки может быть сложнее, чем организовать прямую выгрузку данных в хранилище — и здесь кастомная система отлично справится.

*Facebook принадлежит компании Meta, которая признана экстремистской организацией в России.

 Нет комментариев    4353   5 мес   api   dashboard   google analytics   roistat   troubleshooting

How to: Google App Script

Время чтения текста – 5 минут

Сегодняшний пост прольет свет на то, как можно еще более эффективно использовать один из очень удобных инструментов для базовой аналитики — Google Sheets.
Зачастую, аналитикам нужно часто и много работать с таблицами и создавать выборки по различным условиям. В работе с таблицами проблема часто заключается в том, что приходится обрабатывать и систематизировать большие объемы данных, хранящихся на разных листах. К примеру, вы ведете учет клиентов на одном листе таблицы, выгружая данные из сторонних сервисов, и вам хотелось бы, при обновлении ячеек менять данные на другом листе, используя возможности скриптов Google Sheets. Давайте посмотрим как легко и просто решить эту задачу.

Редактор скриптов

Если у вас есть Google аккаунт и таблицы с данными, загруженные в Google Sheets, то можно создавать скрипт для этой таблицы. Выберите таблицу, в которой нужно автоматизировать перенос информации с одного листа на другой, откройте её и выберете в меню «Инструменты» пункт «Редактор скриптов». Браузер переадресует вас на страницу Apps Script, где вы можете создавать и редактировать скрипты для таблицы.

Автоматизация переноса строк на другой лист

Итак, наш скрипт должен автоматически выполнять задачу переноса строки на другой лист. Для этого, мы создаем еще одну колонку в таблице, в которой можно будет поставить галочку для переноса строки и убрать её для отмены этого действия. Давайте разберемся, как именно это делается.
При написании скрипта можно использовать функцию-триггер, которая срабатывает при выполнении определенного условия. Подробнее о функциях-триггерах вы можете прочитать в документации. В нашем скрипте мы используем функцию OnEdit(e), которая запускается при редактировании ячейки таблицы (включение и выключение галочки). Эту функцию мы вызовем в конце скрипта, а пока что, пропишем все, что в функции должно происходить.

function myScript(e) {   
  // Задаем следующее условие для функции: нужно реагировать только на нажатие галочки в восьмой колонке на листе "Лиды-воронка". 
  if (e.source.getActiveSheet().getName() == "Лиды- воронка" && e.range.getColumn() == 8)
  {
    // Сохраняем объекты исходного листа и листа назначения
    destSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('test');
    sourceSheet = e.source.getActiveSheet();
    // Очищаем лист назначения. При очистке, начинаем со второй строки, так как у нас в таблице есть заголовок.
    destSheet.getRange(2, 1, destSheet.getLastRow(), destSheet.getLastColumn()).clearContent();
    //Перебираем все ячейки с галочками, ищем те ячейки, в которых галочки проставлены.
    range = sourceSheet.getRange(1, 1, sourceSheet.getLastRow(), sourceSheet.getLastColumn());       
    for (i = 2; i <= range.getNumRows(); i++) 
    {      
      //Получаем все проставленные галочки.
      if (range.getCell(i,8).getValue())
      {        
        // Если галочка проставлена, то текущая строка переносится на новый лист.
        currentRow = sourceSheet.getRange(i, 1, i, sourceSheet.getLastColumn());           
        destSheet.appendRow(currentRow.getValues()[0]);
      }      
    }    
  }

// Затем, вызываем функцию-триггер, которая будет вызывать наш скрипт при каждом редактировании ячейки.
function onEdit(e) {
  myScript(e)
}

В итоге, если галочка в столбце выделена, то соответствующая строка будет перенесена на другой лист. Также, важно помнить, что, при удалении галочки, строка убирается с другого листа.
В нашем примере мы получили следующие две таблицы:

Выводы

Сегодня мы показали вам простой пример скрипта, который упростит, а может даже улучшит, рутинную работу с таблицами. Конечно, с помощью скриптов Google Sheets можно автоматизировать еще очень много других процессов. Вы можете сами прочитать о других функциях, а мы подробно расскажем о некоторых из них в следующих постах!

 2 комментария    407   2021   api   google analytics

Бот для преобразования данных из Coinkeeper

Время чтения текста – 6 минут

Coinkeeper — кроссплатформенное приложение для учёта финансов. Внутри можно выпустить виртуальную банковскую карту Visa с бесплатным годовым обслуживанием, которая будет присылать уведомления, если вы тратите больше, чем запланировали. Помимо уведомлений, приложение ведёт историю трат и позволяет выгрузить сводный отчёт в формате csv. Данные, которое выгружает приложение ещё не готовы к анализу и выглядят так:

Азат Шарипов сделал скрипт обработки данных в пригодный для Tableau вид и подготовил Tableau Public книгу, а Рома Бунин в рамках своего проекта «Переверстка» переработал дашборд.

Мы решили тоже поучаствовать, и с нашей стороны Елизавета Мазурова сделала чат-бота.

Чат-бот крутой! Помимо того, что он может как и прежде отдавать обратно .csv-файл, он позволяет автоматизировать рутину по обновлению отчета через Google-таблицы. Как, наверное, многие помнят, Tableau Public может работать на гугл-таблицах или csv файлах, но не разрешает подключение к данным. Бот умный: он создаст за вас гугл-таблицу и когда вы повторно отправите ему новый файл обновит ее.

Использование бота

Перейдите в диалог с ботом и введите команду /start — в ответе бот расскажет немного о себе. Для продолжения работы нажмите на кнопку «Начать».

Сразу после можно отправить csv-файл, выгруженный из Coinkeeper:

Выберите тип файла — csv или таблицу в Google Spreadsheets.

В случае выбора csv-файла бот пришлёт его:

А в случае ссылки в первый раз нужно будет пройти небольшую регистрацию — указать почту и наименование для файла.

Затем бот пришлёт ссылку на файл:

Скрипт преобразовал данные, и таблицу можно указать в качестве источника данных в Tableau. А благодаря тому, что в случае загрузки нового файла создаётся не новая таблица, а обновляется старая, отчёт в Tableau тоже обновится. В результате открывается возможность еженедельно присылать боту новую таблицу и сразу переходить в обновлённый отчёт.

 Нет комментариев    132   2021   Analytics Engineering   coinkeeper   google analytics   tableau   telegram

Строим funnel-репорт в redash

Время чтения текста – 4 минуты

Итак, мы планировали разобрать Funnel-визуализацию отчета в redash.
В первую очередь, построим запрос к подключенному нами источнику данных — google analytics.

Прямо вот такой текст необходимо положить в консоль запроса:

{
    "ids": "ga:128886640",
    "start_date": "30daysAgo",
    "end_date": "yesterday",
    "metrics": "ga:users,ga:goal1Completions,ga:goal2Completions,ga:goal3Completions"
}

В данном запросе мы просим API Google Analytics отдать данные за последние 30 дней по аккаунту GA: 128886640. Мы хотим увидеть число пользователей и число выполнения целей 1, 2 и 3.

В итоге получаем таблицу следующего вида:

ga:users ga:goal1Completions ga:goal2Completions ga:goal3Completions
3,926 105 41 32

Отлично, это именно то, что нам нужно для построения воронки.
Расскажу об одной очень полезной фиче Redash: query-results. Чтобы подключить таблицы с результатами выполнения запросов, идем в Data Sources и ищем query-results (beta). Подключаем новый источник данных.
Теперь у нас появилась возможность обращаться к результатам запросов redash. Так, например, мы можем воспользоваться результатами запроса к Google Analytics.

Как это сделать?
Необходимо выбрать слева источник данных query-results:

Выпадающее меню с выбором источников данных (в консоли — слева)

Теперь научимся делать funnel-визуализацию. Для этого пишем следующий SQL-запрос:

select 'Добавление товара в корзину' as step_name, ga_goal1Completions as goalCompletion from query_8
union all
select 'Просмотр корзины' as step_name, ga_goal2Completions from query_8
union all
select 'Оформление заказа' as step_name, ga_goal3Completions from query_8

В данном случае query_8 — это как раз таблица с результатами запроса к источнику данных Google Analytics.

Настроим визуализацию:

Аккуратно выбираем параметры, чтобы получить желаемый результат

В итоге мы получаем воронку конверсий из одной цели в другую:

Данную воронку можно отобразить в дашборде и добавить к ней фильтры / параметры

Как подключить Google Analytics к Redash?

Время чтения текста – 4 минуты

В этой статье разберем как подключить источник данных Google Analytic к сервису Redash [подробнее Redash и его возможности мы разбирали в предыдущих заметках].

Создаем сервисный аккаунт в Google

Переходим в консоль сервисных аккаунтов.

Создаем новый сервисный аккаунт

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

Включаем Analytics API

Для созданного нами сервисного аккаунта необходимо включить Analytics API.

Когда мы все установили, Analytics API должен гореть зеленым

Добавляем сервисного пользователя в Google Analytics

Далее, необходимо добавить созданного нами сервисного пользователя в Google Analytics. Пользователь будет иметь примерно такой вид:
user@PROJECT-ID.iam.gserviceaccount.com.
Необходимо добавлять пользователя с правами на Чтение и Просмотр.

Создаем новый источник данных в Redash

Идем в Настройки (Settings) -> Добавляем новый источник данных

Подключаем новый источник данных.

Нас интересует источник данных Google Analytics, поэтому ищем «google»:

Ищем google analytics в источниках данных.

Вспоминаем, куда мы сохранили JSON файл, он нам сейчас потребуется

Выбираем созданный ранее JSON файл

Пишем запрос к новому источнику данных

Именно в таком виде запрос выполняется в консоли redash:

{
    "ids": "ga:128886640",
    "start_date": "30daysAgo",
    "end_date": "yesterday",
    "metrics": "ga:users,ga:newUsers,ga:goal1Starts,ga:goal2Completions,ga:goal3Starts,ga:transactions,ga:transactionRevenue", 
    "dimensions": "ga:date"
}

Как узнать параметры для выполнения запроса?

У Google есть отличный ресурс Query Explorer, в котором можно найти все необходимые метрики и измерения, которые доступны в Google Analytics.

Надеюсь, данная инструкция оказалась вам полезной, далее мы разберемся как построить воронку целей в Redash на основании данных из Google Analytics.

 Нет комментариев    40   2018   BI-инструменты   google analytics   redash