Атрибуция

Новых считаем по первому клику, старых — как хотите. Для новых реально важен первый канал, откуда он приплыл

Проблема остается в том, что масштабировать каналы retention почти невозможно. Здесь мне кажется позиция Тимофея Шиколенкова о том, что каналы retention не должны впрямую участвовать в дележе стоимости конверсии согласно мультиканальной атрибуции логичной

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

Зависит от типичного сценария привлечения и конверсии клиента. На мой взгляд самые ценные переходы — первый и последний. В Analytics есть атрибуция, 40% на первый, 40% на последний, и 20% равномерно на все остальные. Называется «Атрибуция с привязкой к позиции»: https://support.google.com/analytics/answer/1665189?hl=ru

Снова про MP

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

Например, пользователь пришле из yandex / cpc, сделал заказ. Ему позвонил на след. день менеджер и изменил статус заказа. Пользователь, например, вернулся по ретаргетингу по google / cpc или другим способом на сайт на след. день. Еще через день менеджер опять позвонил и заказ по каким-то причинам отменился. в GA уйдет транзакция и запишеться на google / cpc.
на всякий для всех написал, так как это очень частотный вопрос.
Если кто знает придумает другой способ, с удовольствием узнаю (видел порядка 5-7 архитектур и способов все не работающие, в том числе склеивание через Import Data protocol, но с удовольствием узнаю, если я что-то не учитываю или появился новый способ)

Гугл делает сервис аналитики для Adwords, Googl Analytics не создавался как инструмент бизнес или продуктовой аналитики
Он ничего не знает про юнит-экономику, ARPU, ARPPU, все еще работает в основном по сессиям (хотя API 4 года как переводят на user-base аналитику и последние новости в блоге радуют). GA — в первую очередь API first разработку делают и они ок работать с доп. сервисами — Гуглу это выгодно иначе пользователи передут на другие user base системы аналитики и гугл потеряет возможность использовать данные для анализа что люди ищут и для продажи Adwords
Вместе с тем GA действительно улучшается, просто очень медлено.
edited
Сложного в MP полно, объясните разработчикам (хотя это есть в справке), почему при отправке eventAction с не целым eventValue (например 2.0 — число почти целое, но просто разработчик тип не проверил) в ответ на post запрос вы получите 200 ОК, но событие не будет записана
объясните что питон библиотеки, которые разработчики правильно берут с гитхаба для работы с MP часто записывают свой user-agent и по этой причине легко увидеть в GA что транзакции были отправлены с браузера или устройства: Python
Объясните чем “” отличается от (not set), и почему если использовать Core API вы выгружаете данные с запросом с dimension=ga:sourceMedium, ga:campaign, ga:keyword — вы получите меньше строчек чем через dimension=ga:sourceMedium, ga:campaign — потому что пустые “” keyword не передадуться в отличие от (not set)
ну и реально еще 50 таких примеров, могу в личке рассказать.
А еще попробуйте своими силами передавать транзакции, которые в CRM были получены через jivosite, calltracking и т.д. да еще правильно положив их в GA — практика показывает, что у 90 из 100 компаний это не получается или стоит очень дорого
и нафиг ломается и падает точность статистики, если кто-то из маркетологов забыл и выложил лендинг с неверно поставленным счетчиком через ga_clientID

Или поставил счетчик через GTM (еще недавно там погрешность была 10-15% при записи ga_clientID — теперь с помощью custom Task можно ставить счетчик через GTM почти без погрешности)

Мера новых клиентов в DAX

новый клиент = COUNTROWS(
 FILTER(VALUES(mysql_transactions_facts[userPhone]); 
 CALCULATE(DISTINCTCOUNT(mysql_transactions_facts[orderId]); 
 FILTER(ALL('calendar'); 
 'calendar'[Date]<MAX('calendar'[Date])
 )
 )>1 &&
 CALCULATE(COUNTROWS('mysql_transactions_facts'))=1
 )
 )

или так

COUNTROWS (
 FILTER (
 ADDCOLUMNS (
 VALUES ( mysql_transactions_facts[userPhone] ),
 "PreviousSales", CALCULATE (
 COUNTROWS ( mysql_transactions_facts),
 FILTER (
 ALL ( 'calendar' ),
 'calendar'[Date]< MIN ( 'calendar'[Date] )
 )
 )
 ),
 [PreviousSales] = 0
 )
)

а вот так вернувшийся клиент:

COUNTROWS (
 CALCULATETABLE (
 VALUES ( mysql_transactions_facts[userPhone] ),
 VALUES ( mysql_transactions_facts[userPhone]),
 FILTER (
 ALL ( 'calendar' ),
 'calendar'[Date]< MIN ( 'calendar'[Date] )
 )
 )
)

Как искать аутлаеров

В PBI:

Создаем отдельную табличку:

without_outliers = FILTER(SUMMARIZE(Query1;Query1[card];"count";COUNT(Query1[card]));[count]<40)

С помощью SUMMARIZE создаем сводную табличку и фильтруем аутлаеров с помощью FILTER

Потом связываем

 

В R:

boxplot(dataset$count)
out = boxplot(dataset$count)$out
out_data = as.data.frame(out)

 

 

Настройка удаленного сервера для работы

Вводная часть здесь: https://data36.com/data-coding-101-install-python-sql-r-bash/

R лучше устанавливать по этому туториалу: https://www.digitalocean.com/community/tutorials/how-to-install-r-on-ubuntu-16-04-2

Rstudio также отсюда https://data36.com/data-coding-101-install-python-sql-r-bash/ , только можно версию по свежее.

Mysql по этому туториалу: https://www.digitalocean.com/community/tutorials/how-to-install-mysql-on-ubuntu-16-04 Там же нужно будет создать юзера для mysql , можно сделать это вот так https://www.digitalocean.com/community/tutorials/mysql-ru

 

 

 

Как скачать данные из GA c помощью R и сохранить в MySQL на своей машине

План прост:

1. Поставить Mysql на машину
2. Создать там нужное бд и таблицы
3. Загрузить данные за позавчерашний день через R
4. Настроить скрипт загрузки с динамическими датами http://sotnik.biz.ua/blog/ppc_in_power_bi/
5. Запустить по крону его через 5 минут https://2steps.pro/r-script-launching-with-task-scheduler.html
6. Если все ок, то ставим крон на 9.30

 

 

1. Поставить Mysql на машину

Скачиваем mysql-installer-web-community-5.7.19.0 и следуем установщику. Если что, то гуглим.

Чтобы войти в мускул:

mysql -u root -p

2. Создать там нужное бд и таблицы

Так как кодировка R и винды cp1251, то нужно создать дб в этой же кодировки.

Важно чтобы кодировка в скрипте и в БД была одинаковая. Проверить кодировку в R можно так Sys.getlocale()

CREATE DATABASE organic_data1 CHARACTER SET cp1251 COLLATE cp1251_general_ci;

А затем нужные таблицы:

CREATE TABLE ga_organic_data(
 date DATE,
 sourceMedium VARCHAR(256),
 landingPagePath VARCHAR(256),
 deviceCategory VARCHAR(256),
 hostname VARCHAR(256),
 sessions INTEGER,
 transactions INTEGER,
 transactionRevenue DECIMAL
 );

3. Загрузить данные за позавчерашний день через R

Коннектимся к бд и загружаем:

conMySQL1 <- dbConnect(MySQL(), dbname = "organic_data1", user = "root", password = "makarovs", host = "localhost",port=3306)

dbWriteTable (conMySQL1, "ga_organic_data", ga_organic_data, row.names = FALSE, append = TRUE)

Сложность была в определении hostname и имени пользователя. Помогла статья: https://stackoverflow.com/questions/4093603/how-do-i-find-out-my-mysql-url-host-port-and-username 

4. Настроить скрипт загрузки с динамическими датами

library(RMySQL)
library("googleAuthR")
library("googleAnalyticsR")
library("jsonlite")


conMySQL1 <- dbConnect(MySQL(), dbname = "organic_data1", user = "root", password = "makarovs", host = "localhost",port=3306)

old_data <- dbReadTable(conMySQL1, "ga_organic_data")
last_date <- max(old_data$date)
start_date <- as.character.Date(as.Date(last_date)+1)
end_date <- as.character.Date(Sys.Date() - 1)


# Сюда вставить то, что в json-файле. Обязательно заменить обратный слеш \ на двойной \\
json <- '{

}
'

# функция для авторизации
gar_auth_service <- function(json, scope = getOption("googleAuthR.scopes.selected")){
 
 endpoint <- httr::oauth_endpoints("google")
 
 secrets <- jsonlite::fromJSON(json)
 scope <- paste(scope, collapse=" ")
 
 if(is.null(secrets$private_key)){
 stop("$private_key not found in JSON - have you downloaded the correct JSON file? 
 (Service Account Keys, not service account client)")
 }
 
 google_token <- httr::oauth_service_token(endpoint, secrets, scope)
 
 Authentication$set("public", "token", google_token, overwrite=TRUE)
 Authentication$set("public", "method", "service_json", overwrite=TRUE)
 
 return(invisible(Authentication$public_fields$token))
 
 }

# авторизируемся
gar_auth_service(
 json = json,
 scope = "https://www.googleapis.com/auth/analytics"
)

# id представления GA
ga_view <- '46195197'


df <- dim_filter("sourceMedium","REGEXP","(google / organic|yandex / organic)")
fc <- filter_clause_ga4(list(df))


# Выгружаем данные
ga_organic_data <- google_analytics_4(ga_view, 
 date_range = c(start_date,end_date),
 dimensions=c('date','sourceMedium','landingPagePath','deviceCategory','hostname'), 
 metrics = c('sessions','transactions','transactionRevenue'),
 dim_filters = fc,
 anti_sample = TRUE)


dbWriteTable (conMySQL1, "ga_organic_data", ga_organic_data, row.names = FALSE, append = TRUE)

dbDisconnect(conMySQL1)

5. Запустить по крону его через 5 минут 

 

Дебаг с помощью Google Tag Assistant

Врубаем record: http://joxi.ru/bmo6zYouxe5j4r и выполняем нужные действия, а потом смотрим отчет: http://joxi.ru/V2VRL5nSxRza72
Очень удобно смотреть что записалось в кастом деменшен или какая текущая кампания/канал. Также можно тестить кроссдоменное отслеживание.

Как исключать источники перехода

https://support.google.com/analytics/answer/2795830?hl=ru

Фишка в том, что там в поле фильтр по содержит:

В списке исключаемых источников перехода используется вариант соответствия «СОДЕРЖИТ». Например, если ввести example.com, трафик со страницы sales.example.com также будет исключаться (поскольку доменное имя содержит example.com).

 

Рефлексия по задаче

Если использовать метрику users и date одновременно, то метрика users будет завышена. Это справедливо при нескольких вызовах API.

Как делать сводные aggregate(sessions ~ sourceMedium, data =ga_data, FUN = sum)

Команда .libPaths() покажет папки где хранятся пакеты. В первую из них можно зайти и удалить пакет.

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