Интернет-маркетолог. Рассказываю о том, как автоматизировать процесс работы рекламных кампаний и не только 👋
Признаюсь честно, я долго не решался писать на эту тему. Никогда не учился кодить, и мне бывает сложно использовать профессиональный сленг, объясняя простыми словами то, что сам понимаю скорее интуитивно. Однако возможности автоматической оптимизации всегда меня крайне сильно интересовали. Ведь это значительно экономит время, освобождает внимание,…
Приветствую вас! Сегодня я хочу поделиться подходом к созданию кастомных целей, основанных на действиях пользователей на сайте. В случаях, когда я работаю со сложным или дорогостоящим продуктом, количество прямых конверсионных действий может быть недостаточным для эффективного обучения рекламных кампаний.
Всем привет. Первым делом хочу поздравить всех с уже наступившим новым 2022 годом, хочу пожелать вам и вашим близким здоровья (в нынешнее время это крайне актуально), а также достижения самых амбициозных целей.
Скопилось очень много кейсов до которых никак не доходили руки, чтобы написать их. Поэтому я решил поделиться самым свежим кейсом в…
Всех приветствую. Фейсбук продолжает душить бедных таргетологов и арбитражников по всему миру. Поломанная оптимизация, ЗРД, баны аккаунтов, баны ФП, баны креативов — это всего лишь малая часть того, с чем сталкивается специалист по рекламе в Фейсбуке. Что уж там говорить — мой аккаунт заблокировали, после того как я отправил свой паспорт, чтобы под…
Всем привет, в этом кейсе я хотел бы поделиться с вами результатами продвижения краснодарского салона кухонь с помощью таргетированной рекламы в instagram.
Всем привет, меня зовут Максим Вознюк, уже около трех лет я занимаюсь настройкой таргетированной рекламы, имею небольшой опыт в арбитраже трафика. Сегодня хочу поделиться с вами небольшим кейсом, надеюсь вам будет интересно.
Настроив передачу офлайн-конверсий вы открываете для себя сразу несколько преимуществ:
"}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["Более детальную аналитику по вашим рекламным кампаниям. Теперь вы будете видеть какие кампании и за какую стоимость приводят вам целевых пользователей","Возможность дополнительной оптимизации кампаний"],"type":"UL"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"🙌 Поздравляю, вы сделали шаг к построению маркетинга, основанного на данных.
"}}],"summaryContent":null,"isExistSummaryContent":false,"warningFromEditor":null,"warningFromEditorTitle":null,"counters":{"comments":0,"favorites":1,"reposts":0,"views":85,"hits":107,"reads":null,"online":0},"dateFavorite":0,"hitsCount":107,"isCommentsEnabled":true,"isLikesEnabled":true,"isRemovedByUserRequest":false,"isFavorited":false,"isPinned":false,"repostId":null,"repostData":null,"subscribedToTreads":false,"isEditorial":false,"isAudioAvailable":false,"audioUrl":null,"isAudioAvailableToGenerate":false,"commentEditor":{"enabled":true,"who":null,"text":"","until":null,"reason":null,"type":"everybody"},"isBlur":false,"isPublished":true,"isDisabledAd":false,"withheld":[],"ogTitle":null,"ogDescription":"Настройка передачи офлайн-конверсий из Битрикс24 в Яндекс.Метрику, интеграция CRM с Метрикой, создание поля для Client ID, тестирование","url":"https://vc.ru/marketing/2243942-peredacha-oflajn-konversij-iz-bitrix24-v-yandeks-metriku","author":{"id":779649,"name":"Максим Вознюк","nickname":null,"description":"Интернет-маркетолог. Рассказываю о том, как автоматизировать процесс работы рекламных кампаний и не только 👋","uri":"","avatar":{"type":"image","data":{"uuid":"5b113363-0041-5c16-bd2f-23ffa5171ad0","width":855,"height":855,"size":409712,"type":"png","color":"993c06","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQIAHAAcAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAAKAAoDAREAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAABwUI/8QAJhAAAQMDAwIHAAAAAAAAAAAAAQIDBAAFEQYSISIxExQjMlFhYv/EABYBAQEBAAAAAAAAAAAAAAAAAAYEBf/EACIRAAEDBAICAwAAAAAAAAAAAAEAAgMEBREhMVESgSJBYf/aAAwDAQACEQMRAD8AwFpiFbvLXNmbHQ46mBvj4QVuBf4APcn6PArIu1fOJoH07iAHAHeB+5SCxWmlNNUsrGBzi0kay4deO0cLkyN6spQDk8baQeQO8owGAawlXQXpToshrod8RPWnhXv+e9C718g5p469J9YdRl4579qtcoUNVxlKVEZJL6ySWxkncahgleImgE8BWywxl7iWjk/S/9k="}},"cover":{"cover":{"type":"image","data":{"uuid":"4963838f-7454-5b9a-b626-90d521d531a9","width":4896,"height":3264,"size":329702,"type":"jpg","color":"638eca","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCAAKAAoDASEAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAwUGCP/EACYQAAIBAwIEBwAAAAAAAAAAAAECAwAEBREhBgciQRIVFzFRYYH/xAAVAQEBAAAAAAAAAAAAAAAAAAAGBf/EABwRAAICAwEBAAAAAAAAAAAAAAEDAAIEISISof/aAAwDAQACEQMRAD8AJn+YuPsbUpl7nh2FgCQsEYeTbt0Lt+1HeufCK9PkEz6beIIu/wB+9Lr5ik87P2HqY7GdTPeelle7nZ5HZmcliWJJOvelup+aOMJ9GWqDU//Z"}},"cover_y":60},"achievements":[{"title":"Год на vc.ru","code":"registration_1_year","description":"Первый год с vc.ru. Получена 24 июля 2025.","previewUuid":"0d11c244-49de-50e7-894e-b9b27945d42b","formats":{"glb":"https://static.vc.ru/achievements/fish.glb","usdz":"https://static.vc.ru/achievements/fish.usdz"},"viewData":{"contentColor":"#C67AA3","textMaxWidth":0.634765625,"textX":0.5888671875,"textY":0.54296875,"logoX":0.5859375,"logoY":0.6669921875,"logoXNoText":0.6044921875,"logoYNoText":0.5439453125},"id":4657386,"userId":779649,"count":0,"shareImage":"https://api.vc.ru/achievements/share/4657386"},{"title":"3 года на vc.ru","code":"registration_3_years","description":"Провёл 3 года вместе с vc.ru. Получена 23 июля 2025.","previewUuid":"d9d72ac5-bcb5-55e0-8c72-b99251e5cdd9","formats":{"glb":"https://static.vc.ru/achievements/shark.glb","usdz":"https://static.vc.ru/achievements/shark.usdz"},"viewData":{"contentColor":"#8E6F09","textMaxWidth":0.66796875,"textX":0.5205078125,"textY":0.341796875,"logoX":0.5205078125,"logoY":0.4609375,"logoXNoText":0.5,"logoYNoText":0.3662109375},"id":1033299,"userId":779649,"count":0,"shareImage":"https://api.vc.ru/achievements/share/1033299"}],"lastModificationDate":1764993820,"isSubscribed":false,"isSubscribedToNewPosts":false,"isMuted":false,"isAvailableForMessenger":true,"badgeId":null,"isDonationsEnabled":false,"isPlusGiftEnabled":true,"isUnverifiedBlogForCompanyWithoutPro":false,"isRemovedByUserRequest":false,"isFrozen":false,"isDisabledAd":false,"isPlus":false,"isVerified":false,"isPro":false,"yandexMetricaId":null,"badge":null,"isOnline":false,"tgChannelShortname":null,"isUnsubscribable":true,"type":1,"subtype":"personal_blog"},"subsite":{"id":199113,"name":"Маркетинг","description":"Рекламные кейсы из России и других стран, советы по продвижению, маркетинг и digital.","uri":"/marketing","avatar":{"type":"image","data":{"uuid":"d66009fe-9bf0-52da-bdbf-4c758eba39e7","width":2400,"height":2400,"size":841299,"type":"jpg","color":"f97373","hash":"0c1cf06cf0d010","external_service":[]}},"cover":{"type":"image","data":{"uuid":"5488a646-f32d-57a6-a31f-d290afc4388a","width":960,"height":280,"size":177,"type":"png","color":"fc7c7c","hash":"","external_service":[]}},"lastModificationDate":1661337194,"isSubscribed":false,"isSubscribedToNewPosts":false,"isMuted":false,"isAvailableForMessenger":false,"isDisabledAd":false,"nickname":"marketing","isUnsubscribable":true,"badge":null,"badgeId":null,"isDonationsEnabled":false,"isOnline":false,"isPlus":false,"isUnverifiedBlogForCompanyWithoutPro":false,"isVerified":false,"isRemovedByUserRequest":false,"isFrozen":false,"isPro":false,"type":2,"subtype":"community"},"reactions":{"counters":[{"id":1,"count":1}],"reactionId":0},"isNews":false,"source":null,"clusters":[],"donations":{"amount":0,"isDonated":false},"commentsSeenCount":null}},{"type":"entry","data":{"id":2163428,"customUri":"optimizatsiya-reklamy-yandeks-direkt-s-google-tablitsami","subsiteId":779649,"title":"Оптимизация рекламы в Яндекс Директ с помощью умных Google таблиц","date":1757279949,"dateModified":1759223312,"blocks":[{"type":"media","cover":true,"hidden":false,"anchor":"","data":{"items":[{"title":"","image":{"type":"image","data":{"uuid":"595d81d1-16fe-5541-8b16-7bfcbb10bd17","width":1237,"height":617,"size":227939,"type":"jpg","color":"eadcc3","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wAARCAAKAAoDAREAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAACQgK/8QAIBAAAQUBAAIDAQAAAAAAAAAABAECAwUGBwATCREUIf/EABcBAQEBAQAAAAAAAAAAAAAAAAYIAgT/xAAoEQACAgEDAgQHAAAAAAAAAAABAgMEEQAFEhMVBiFUYRQiMTVBQlL/2gAMAwEAAhEDEQA/ANqdFvNLajajIQ9By+66zlzcrNruf5GzylTpOf1VueVEpV0xtoZ7YzQh5zA4zIKz9bwZwh5fZ7Htw7OoXgnUJdFYcgvFGYB3yfrwUluI82xgeZ1xXp7deOFqVE35Ht1IZYhYirGGrNOkdm3zlBWT4SFnn6Aw8/DpowZhoi7ftvy2kW1pOBwfmsAM9ibMFDZs6nPZQiSkyvGisJqTpIVNMdHC5jC5agMSsknSR4A0AixRMPy7dBJLJI5sl3kd2KXN0RCzMWYqiWURFyThURVUYCqoAAXRu6xoBXoYCKB1KW1yPgKAOcjQM0j/ANOzMznLFiTks3zrHZGo2h2jqstnKzQ3oOvju76vo6wK5uGCbaaMRlraDCxHWDBo3OjHaXPMkLHK2NGtVU8R6PajnfEEN3W1a2eZrW63Rta1sr0a1qXBiI1qI5ERERERERPpE/ieUVsiqdl2glVz2vb/AMD0kXtqUfELv3/fPmb7xuf7H1s/vr//2Q=="}}}]}},{"type":"link","cover":false,"hidden":false,"anchor":"","data":{"link":{"type":"link","data":{"url":"https://api.vc.ru/v2.8/redirect?to=https%3A%2F%2Ft.me%2FMaxOVo&postId=2163428","title":"Maxim Voznyuk","description":"Интернет-маркетолог. Мой блог: https://vc.ru/id779649","image":{"type":"image","data":{"uuid":"0c5ec522-6456-5837-a7a9-efa6a12645d2","width":180,"height":180,"size":4016,"type":"png","color":"26a5e4","hash":"","external_service":[]}},"v":1,"hostname":"t.me"}}}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Содержание"}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["Начало","Шаблоны таблиц","Обзор мастер-таблицы","Обзор скриптов Google Apps script","Создаем свой проект на базе мастер-таблицы"],"type":"OL"}},{"type":"header","cover":false,"hidden":false,"anchor":"nachalo","data":{"style":"h2","text":"Начало"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Сегодня я покажу удобный способ работы с отчетами рекламных кампаний Яндекс Директа через Google Таблицы. В отличие от привычного формата, здесь таблицы становятся «умными» — внутри них встроены специальные скрипты на Google Apps Script. Благодаря этому данные подтягиваются и обрабатываются автоматически, что экономит время и упрощает аналитику.
"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"Google Apps Script — это облачная платформа это облачная платформа на базе JavaScript, которая позволяет автоматизировать задачи и расширять функциональность продуктов Google","lang":""}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Недавно я сделал проект на Python, который работает через API Яндекс.Директа. Всё управление рекламой происходит буквально в один клик: система сама анализирует кампании, отключает неэффективные площадки в РСЯ по заданным правилам и добавляет минус-слова в поисковые кампании. Это экономит время и помогает быстро наводить порядок в рекламе.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"У такого подхода есть и свои сложности, которые могут поставить в тупик даже опытных специалистов:
"}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["Нужно зарегистрировать приложение;","Получить токен для его работы;","Разбираться с кодом для первоначальной настройки;","Иметь хотя бы базовые знания по работе с API."],"type":"UL"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Ранее я обещал, что выпущу мануал по настройке и бесплатно дам сам проект. Пока что реакций мало и я решил попридержать разработку для себя. К тому же я решил монетизировать проект. Если интересно — пишите в Telegram.
"}},{"type":"link","cover":false,"hidden":false,"anchor":"","data":{"link":{"type":"link","data":{"url":"https://api.vc.ru/v2.8/redirect?to=https%3A%2F%2Ft.me%2FMaxOVo&postId=2163428","title":"Maxim Voznyuk","description":"Интернет-маркетолог. Мой блог: https://vc.ru/id779649","image":{"type":"image","data":{"uuid":"0c5ec522-6456-5837-a7a9-efa6a12645d2","width":180,"height":180,"size":4016,"type":"png","color":"26a5e4","hash":"","external_service":[]}},"v":1,"hostname":"t.me"}}}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Способ, о котором я расскажу сегодня, по сути решает те же задачи, что и проект на Python, но его реализация намного проще. Не нужно вникать в сложные технические детали — всё делается легко и быстро.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Подключать API не придётся, поэтому напрямую управлять рекламными кампаниями через Google Таблицу вы не сможете. Зато я максимально упростил процесс запуска: всё, что нужно — просто скопировать две готовые таблицы, и система начнёт работать.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Это последний способ автоматизации, который я планирую опубликовать, поскольку у меня уже есть несколько готовых вариантов. В следующих постах я планирую публиковать кейсы (давно не делился) и поделиться решениями для автоматизации других процессов, связанных с рекламой в Яндекс Директе и не только.
"}},{"type":"header","cover":false,"hidden":false,"anchor":"shabloni-tablic","data":{"style":"h2","text":"Шаблоны таблиц"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Для удобства работы я создал две таблицы. Мастер-таблица служит центром управления: в ней прописаны все проекты и автоправила, а также содержатся все скрипты Google Apps Script. Вторая таблица предназначена для выгрузки и хранения данных.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"👉 шаблон мастер-таблицы: первым делом сделайте копию шаблона и назовите её «Главная». Важно убрать из названия слово «копия», чтобы таблица корректно работала.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"👉 шаблон внешнего отчета: сделайте копию и назовите ее названием вашего проекта.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"❗ Очень важно: чтобы таблицы работали корректно — не меняйте название вкладок. Вы можете изменить только название вкладок Проект 1 и Проект 2 в мастер-таблице.
"}},{"type":"header","cover":false,"hidden":false,"anchor":"obzor-master-tablici","data":{"style":"h2","text":"Обзор мастер-таблицы"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Открыв шаблон, вы увидите несколько основных вкладок:
"}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["Главная;","Автоправила;","Оптимизация;","Сводные отчёты;","Проект 1-2."],"type":"UL"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Вкладка «Главная»"}},{"type":"media","cover":false,"hidden":false,"anchor":"","data":{"items":[{"title":"","image":{"type":"image","data":{"uuid":"c7c76c14-ccc9-5e7e-9bb9-7b4dd7d3c11e","width":3370,"height":628,"size":53267,"type":"png","color":"dbdfe5","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAAKAAoDAREAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAQFCf/EAB8QAAICAQQDAAAAAAAAAAAAAAECAAMEERYhMVKj0v/EABQBAQAAAAAAAAAAAAAAAAAAAAD/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwDUmzFrusc21qysgU8nXsmAht3D8E9n3ArQCB//2Q=="}}}]}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Давайте разберем основные столбцы:
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"📂 Проект — название вашего проекта. Можно указать любое, удобное для вас.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"📊 Название цели Adveronix — здесь отображаются цели, которые подтягивает сервис Adveronix. После выгрузки статистики они могут выглядеть, например, так: Conversions_453045898_AUTO. Согласитесь, не очень понятно, что именно это за цель. Поэтому ниже есть столбец для «человеческого» названия.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"🎯 Название цели кабинет — здесь вы пишите название целей, которое будет понятна вам.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"📈 KPI — столбец необязательный. Он не влияет на работу скриптов, но если вам нужно вы можете указать основную стоимость лида по вашим KPI.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"🗓 Дата последнего обновления — здесь отображается дата и время, когда в последний раз во вкладке вашего проекта происходили какие-либо изменения.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"⚠ Ошибки — технический столбец. Здесь фиксируются возможные проблемы в работе скрипта, чтобы вам не пришлось искать их вручную в журнале.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"🔗 Ссылка на отчет — для каждого проекта указывается ссылка на отдельный отчёт с выгрузкой данных (тот самый шаблон, который я показывал выше). У каждого проекта должен быть свой файл с выгрузкой.
"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Вкладка «Автоправила»"}},{"type":"media","cover":false,"hidden":false,"anchor":"","data":{"items":[{"title":"","image":{"type":"image","data":{"uuid":"b9ad11f6-d829-5c89-9be9-60ee2d3b49b9","width":2348,"height":608,"size":82804,"type":"png","color":"171818","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAAKAAoDAREAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIECf/EABwQAAICAwEBAAAAAAAAAAAAAAEDAAIEETFhcf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwDULGxqoVjKsoXsKauzXSB0/TuBWEJAACqgDyA8Agf/2Q=="}}}]}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Эта вкладка отвечает за автоматизацию. Здесь вы указываете правила, по которым скрипт будет собирать данные в нужных отчётах.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Например:
"}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["📈 Статистика по кампаниям (текущий месяц)","🔍 Ключевая фраза (текущий месяц) и другие варианты."],"type":"UL"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Зачем это нужно? Автоправила помогают настроить аналитику один раз, а дальше система сама будет выгружать и обрабатывать данные по выбранным условиям. Это экономит время, снижает риск ошибок и позволяет сосредоточиться на оптимизации кампаний, а не на рутине.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"❗ Важно: все необходимые вкладки уже есть во второй таблице. Создавать их вручную в мастер-таблице не нужно — всё настроено заранее.
"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Вкладка «Оптимизация»"}},{"type":"media","cover":false,"hidden":false,"anchor":"","data":{"items":[{"title":"","image":{"type":"image","data":{"uuid":"d74510b3-d441-5f83-841b-6bbcbe89b66b","width":2098,"height":796,"size":53785,"type":"png","color":"d8d8e1","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAAKAAoDAREAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAQGCf/EACAQAAIBAwQDAAAAAAAAAAAAAAECAAQFEQMSITETFHH/xAAXAQADAQAAAAAAAAAAAAAAAAAAAgMB/8QAFhEBAQEAAAAAAAAAAAAAAAAAAAER/9oADAMBAAIRAxEAPwDSJKW5e4Tq01SNzHDLkqOB3kfZXYUo9tuzOx8FRySemmbAuZMwgH//2Q=="}}}]}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"После проверки кампаний по заданным автоправилам скрипт выгружает сюда все найденные совпадения. Благодаря этому у вас всегда под рукой список кампаний, которые требуют внимания.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"В этой таблице предусмотрена функция отправки уведомлений в Telegram. Это значит, что вся информация, которая попала в эту вкладку будет приходить вам напрямую в чат.Чтобы это работало, нужно немного подкорректировать готовый скрипт в Google Apps Script. Как именно это сделать — расскажу чуть позже.
"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Вкладка «Сводные отчеты»"}},{"type":"media","cover":false,"hidden":false,"anchor":"","data":{"items":[{"title":"","image":{"type":"image","data":{"uuid":"ed4d071a-4f2f-5601-be61-469231e05e90","width":2382,"height":418,"size":56414,"type":"png","color":"233b61","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAAKAAoDAREAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAUHCf/EACEQAAAFAwUBAAAAAAAAAAAAAAABAgMEBQYREhZSgZTS/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAID/8QAGREBAAIDAAAAAAAAAAAAAAAAAAJRARIT/9oADAMBAAIRAxEAPwDSCpUm5lSDaitR1sknGtDTaM9GeRp1neU6Rop2bcHF/wBavsOs7yaRpRhmoAP/2Q=="}}}]}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Здесь указываются критерии, по которым скрипт сводит отчёты с основной выгрузки.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Как это работает:
"}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["Вы создаёте «серую» выгрузку во вкладке проекта.","Скрипт обрабатывает её и переносит данные во второй шаблон, в нужную вкладку."],"type":"OL"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Таким образом, все данные автоматически распределяются по структуре отчётов — без ручной работы и лишних действий.
"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Вкладка «Проект 1» и «Проект 2»"}},{"type":"media","cover":false,"hidden":false,"anchor":"","data":{"items":[{"title":"","image":{"type":"image","data":{"uuid":"f73bd8e1-02d0-549e-8052-823fd42e7ff6","width":3356,"height":1486,"size":142292,"type":"png","color":"e6dada","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAAKAAoDAREAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAABQn/xAAjEAABBAAEBwAAAAAAAAAAAAABAAIDEQUSFSIxMjZxc5Gy/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAED/8QAGBEBAQEBAQAAAAAAAAAAAAAAAAECEQP/2gAMAwEAAhEDEQA/AKS4aZNVhjeCMsrxRFVtKmZyRp7WXd4dEba5G+lWYsdSDyO+EDI4Dsg//9k="}}}]}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Сюда необходимо настроить выгрузку из плагина adveronix для получения тех самых \"серых\" данных, т.е. данных, которые не распределены по вкладкам.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Ранее я писал как установить плагин adveronix в Google таблицу.
"}},{"type":"header","cover":false,"hidden":false,"anchor":"obzor-scriptov","data":{"style":"h2","text":"Обзор скриптов Google Apps script"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Вся суть проекта — это оптимизация. Сама по себе таблица не станет умной — её возможности раскрываются только благодаря встроенным скриптам. Именно они делают работу удобной.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Давайте познакомимся с ними поближе. Для этого перейдите в меню «Расширения → Apps Script».
"}},{"type":"media","cover":false,"hidden":false,"anchor":"","data":{"items":[{"title":"","image":{"type":"image","data":{"uuid":"6247ded3-b0b4-537a-8a26-5f2c0d849d13","width":3356,"height":1486,"size":369020,"type":"gif","color":"eff1f3","hash":"","external_service":[],"duration":7.35,"isVideo":false,"has_audio":false}}}]}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h3","text":"Изменение названий целей"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"function updateGoals() {\n const ss = SpreadsheetApp.getActiveSpreadsheet();\n const sheet = ss.getSheetByName(\"Главная\");\n if (!sheet) throw new Error(\"Не найден лист 'Главная'\");\n\n const data = sheet.getDataRange().getValues();\n const header = data[0];\n const projectCol = header.indexOf(\"📂 Проект\");\n const adveronixCol = header.indexOf(\"📊 Название цели Adveronix\");\n const cabinetCol = header.indexOf(\"🎯 Название цели кабинет\");\n\n if (projectCol === -1 || adveronixCol === -1 || cabinetCol === -1)\n throw new Error(\"Не найдены нужные заголовки столбцов\");\n\n let currentProject = null;\n const projectMap = {}; // project → { oldGoal: newGoal, ... }\n\n // собираем все цели по проектам\n for (let i = 1; i < data.length; i++) {\n if (data[i][projectCol]) currentProject = data[i][projectCol];\n const oldGoal = data[i][adveronixCol];\n const newGoal = data[i][cabinetCol];\n if (!currentProject || !oldGoal || !newGoal) continue;\n\n if (!projectMap[currentProject]) projectMap[currentProject] = {};\n projectMap[currentProject][oldGoal] = newGoal;\n }\n\n // заменяем только в первой строке каждой вкладки\n for (const projectName in projectMap) {\n const projectSheet = ss.getSheetByName(projectName);\n if (!projectSheet) {\n Logger.log(\"❌ Вкладка не найдена: \" + projectName);\n continue;\n }\n\n const firstRowRange = projectSheet.getRange(1, 1, 1, projectSheet.getLastColumn());\n const values = firstRowRange.getValues()[0];\n let changes = 0;\n\n for (let c = 0; c < values.length; c++) {\n const cell = values[c];\n if (cell && projectMap[projectName][cell]) {\n values[c] = projectMap[projectName][cell];\n changes++;\n }\n }\n\n if (changes > 0) {\n firstRowRange.setValues([values]);\n Logger.log(`✅ Внесено ${changes} замен в листе: ${projectName}`);\n } else {\n Logger.log(`ℹ️ Изменений нет в листе: ${projectName}`);\n }\n }\n}","lang":""}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["Берёт активную Google Таблицу и ищет вкладку «Главная».","Находит в этой вкладке столбцы: 📂 Проект 📊 Название цели Adveronix 🎯 Название цели кабинет","Собирает все проекты и соответствие между «старой» целью (Adveronix) и «новой» (кабинет).","Для каждой вкладки проекта (название вкладки = название проекта) проверяет первую строку.","Заменяет в этой строке все старые цели на новые по соответствию, собранному из «Главной» вкладки.","Логирует результаты: сколько замен внесено или если изменений нет."],"type":"OL"}},{"type":"media","cover":false,"hidden":false,"anchor":"","data":{"items":[{"title":"","image":{"type":"image","data":{"uuid":"25e96f7a-0ed0-5e65-8c62-858a7e1dfa29","width":3420,"height":1722,"size":488027,"type":"gif","color":"f1f4f5","hash":"","external_service":[],"duration":8.933333,"isVideo":false,"has_audio":false}}}]}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h3","text":"CPA и Total conversions"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"function addConversionMetricsFastFinal() {\n const CONFIG = {\n MAIN_SHEET_NAME: \"Главная\",\n ADVERONIX_COL_NAME: \"📊 Название цели Adveronix\",\n CABINET_COL_NAME: \"🎯 Название цели кабинет\",\n METRICS: {\n TOTAL_CONVERSIONS: \"Total conversions\",\n CPA: \"CPA\"\n },\n COST_COL_NAMES: [\"cost\", \"стоимость\", \"затраты\"],\n SKIP_SHEETS: [\"__CACHE__\", \"📊 Сводные отчеты\"]\n };\n\n const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();\n const mainSheet = spreadsheet.getSheetByName(CONFIG.MAIN_SHEET_NAME);\n if (!mainSheet) {\n console.log(\"❌ Главный лист не найден\");\n return;\n }\n\n // -------------------\n // 1. Получаем цели проектов\n // -------------------\n const mainData = mainSheet.getDataRange().getValues();\n const headers = mainData[0];\n const projectCol = headers.indexOf(\"📂 Проект\");\n const adveronixCol = headers.indexOf(CONFIG.ADVERONIX_COL_NAME);\n const cabinetCol = headers.indexOf(CONFIG.CABINET_COL_NAME);\n\n const projectGoals = {};\n let currentProject = \"\";\n\n for (let i = 1; i < mainData.length; i++) {\n const row = mainData[i];\n if (row[projectCol]) currentProject = row[projectCol].toString().trim();\n if (!currentProject) continue;\n\n if (!projectGoals[currentProject]) projectGoals[currentProject] = new Set();\n\n if (adveronixCol !== -1 && row[adveronixCol]) {\n row[adveronixCol].toString().split(',').forEach(g => {\n const goal = g.trim();\n if (goal) projectGoals[currentProject].add(goal);\n });\n }\n\n if (cabinetCol !== -1 && row[cabinetCol]) {\n row[cabinetCol].toString().split(',').forEach(g => {\n const goal = g.trim();\n if (goal) projectGoals[currentProject].add(goal);\n });\n }\n }\n\n Object.keys(projectGoals).forEach(p => {\n projectGoals[p] = Array.from(projectGoals[p]);\n });\n\n // -------------------\n // 2. Обрабатываем листы\n // -------------------\n spreadsheet.getSheets().forEach(sheet => {\n const sheetName = sheet.getName();\n if (CONFIG.SKIP_SHEETS.includes(sheetName) || sheetName === CONFIG.MAIN_SHEET_NAME) return;\n\n const goals = projectGoals[sheetName];\n if (!goals || goals.length === 0) {\n console.log(`⏭️ Пропускаем \"${sheetName}\" - цели не найдены`);\n return;\n }\n\n console.log(`🔍 Обрабатываем лист: \"${sheetName}\"`);\n\n const lastRow = sheet.getLastRow();\n const lastCol = sheet.getLastColumn();\n if (lastRow < 2) {\n console.log(` ⏭️ Пропускаем \"${sheetName}\" - нет данных`);\n return;\n }\n\n // Получаем все данные\n const data = sheet.getRange(1, 1, lastRow, lastCol).getValues();\n let headersRow = data[0].map(h => h ? h.toString().trim() : '');\n\n // -------------------\n // 3. Удаляем старые колонки метрик (если есть)\n // -------------------\n let totalConvCol = headersRow.indexOf(CONFIG.METRICS.TOTAL_CONVERSIONS);\n let cpaCol = headersRow.indexOf(CONFIG.METRICS.CPA);\n\n if (cpaCol !== -1) {\n sheet.deleteColumn(cpaCol + 1);\n if (totalConvCol > cpaCol) totalConvCol--; // сдвиг после удаления\n }\n if (totalConvCol !== -1) sheet.deleteColumn(totalConvCol + 1);\n\n // Перечитываем заголовки после удаления\n headersRow = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0].map(h => h ? h.toString().trim() : '');\n\n // -------------------\n // 4. Находим последний «настоящий» столбец заголовка\n // -------------------\n let lastFilledCol = headersRow.length - 1;\n while (\n lastFilledCol >= 0 &&\n (headersRow[lastFilledCol] === '' ||\n headersRow[lastFilledCol] === CONFIG.METRICS.TOTAL_CONVERSIONS ||\n headersRow[lastFilledCol] === CONFIG.METRICS.CPA)\n ) {\n lastFilledCol--;\n }\n\n // -------------------\n // 5. Находим индексы колонок с целями\n // -------------------\n const goalIndices = goals.map(g => headersRow.indexOf(g)).filter(i => i !== -1);\n if (goalIndices.length === 0) {\n console.log(` ❌ Цели не найдены на листе`);\n return;\n }\n\n // -------------------\n // 6. Находим колонку затрат\n // -------------------\n const costCol = headersRow.findIndex(h => CONFIG.COST_COL_NAMES.includes(h.toLowerCase()));\n if (costCol === -1) {\n console.log(\" ❌ Столбец затрат не найден\");\n return;\n }\n\n // -------------------\n // 7. Считаем Total conversions и CPA для всех строк **одним массивом**\n // -------------------\n const dataRows = data.slice(1); // все строки кроме заголовка\n const totalConversionsArr = [];\n const cpaArr = [];\n\n dataRows.forEach(row => {\n const cost = parseFloat(row[costCol]) || 0;\n let totalConversions = 0;\n\n goalIndices.forEach(idx => {\n totalConversions += parseFloat(row[idx]) || 0;\n });\n\n totalConversionsArr.push([totalConversions]);\n cpaArr.push([totalConversions > 0 ? cost / totalConversions : 0]);\n });\n\n // -------------------\n // 8. Добавляем новые колонки метрик рядом с последним заполненным столбцом\n // -------------------\n sheet.insertColumnAfter(lastFilledCol + 1);\n sheet.getRange(1, lastFilledCol + 2).setValue(CONFIG.METRICS.TOTAL_CONVERSIONS);\n\n sheet.insertColumnAfter(lastFilledCol + 2);\n sheet.getRange(1, lastFilledCol + 3).setValue(CONFIG.METRICS.CPA);\n\n // -------------------\n // 9. Записываем значения **одним блоком**\n // -------------------\n if (totalConversionsArr.length > 0) {\n sheet.getRange(2, lastFilledCol + 2, totalConversionsArr.length, 1).setValues(totalConversionsArr);\n sheet.getRange(2, lastFilledCol + 3, cpaArr.length, 1).setValues(cpaArr);\n }\n\n console.log(` ✅ Лист \"${sheetName}\" обработан`);\n });\n\n console.log(\"✅ Скрипт успешно завершен!\");\n}","lang":""}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Скрипт автоматически добавляет на листы проектов две метрики: Total Conversions и CPA.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Как работает:
"}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["Берёт цели проектов с вкладки «Главная».","На каждом листе проекта находит столбцы с целями и затратами.","Удаляет старые колонки с метриками (если есть).","Считает для каждой строки: Total Conversions — сумма всех целей, CPA — стоимость / Total Conversions.","Добавляет новые колонки с результатами рядом с последним заполненным столбцом."],"type":"OL"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Результат: метрики автоматически посчитаны и готовы к анализу, без ручного ввода.
"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h3","text":"Сведение внешних отчетов"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"/**\n * @fileoverview Скрипт для автоматического сведения отчетов в Google Sheets.\n */\n\n// === 1. Глобальные настройки и константы ===\nconst DEBUG_MODE = false; // 🔹 переключатель для логов и верификации\n\nconst MASTERTABLE_SHEET_NAME = 'Главная';\nconst RULES_SHEET_NAME = 'Сводные отчеты';\n\nconst MASTERTABLE_COLS = {\n PROJECT_NAME: '📂 Проект',\n ADVERONIX_TARGET: '📊 Название цели Adveronix',\n CABINET_TARGET: '🎯 Название цели кабинет',\n KPI: '📈 KPI',\n LAST_UPDATE: '🗓️ Дата последнего обновления',\n ERRORS: '⚠️ Ошибки',\n REPORT_LINK: '🔗 Ссылка на отчет'\n};\n\nconst RULES_COLS = {\n REPORT_NAME: '📊 Сводные отчеты',\n GROUP_BY_FIELD: '🎯 Объект сведения',\n REQUIRED_COLUMNS: '❗️ Обязательные столбцы',\n DATE_FILTER: '📆 Дата'\n};\n\nconst DATE_FILTERS = {\n FULL_PERIOD: 'Нет',\n CURRENT_MONTH: 'Текущий месяц'\n};\n\nconst AGGREGATION_TYPES = {\n SUM: ['Cost', 'Clicks', 'Total conversions'],\n AVG: ['Bounce Rate'],\n CALCULATED: ['CPC', 'CPA']\n};\n\nconst FORBIDDEN_COLUMNS = ['Day', 'Campaign Name', 'Campaign ID', 'Ad Group Id', 'Ad Id', 'Criterion', 'Criterion Type', 'Placement', 'Device', 'Mobile Platform', 'Gender', 'Age'];\n\n\n// === 2. Модуль логирования ===\nfunction logInfo(message) {\n if (DEBUG_MODE) console.log(`[INFO] ${message}`);\n}\n\nfunction logError(message, error) {\n if (DEBUG_MODE) console.error(`[ERROR] ${message}. Stacktrace: ${error ? error.stack : 'N/A'}`);\n}\n\n// === 3. Модуль чтения данных ===\nfunction readSheetData(sheet) {\n if (!sheet) throw new Error('Лист не найден.');\n try {\n const data = sheet.getDataRange().getValues();\n if (!data || !Array.isArray(data) || data.length === 0) throw new Error('Данные на листе пусты или невалидны.');\n logInfo(`Прочитано ${data.length} строк данных с листа \"${sheet.getName()}\".`);\n return data;\n } catch (e) {\n throw new Error(`Ошибка чтения данных с листа \"${sheet.getName()}\": ${e.message}`);\n }\n}\n\nfunction readRules(rulesSheet) {\n const data = readSheetData(rulesSheet);\n const headers = data.shift();\n const rules = [];\n data.forEach(row => {\n const rule = {};\n headers.forEach((header, i) => {\n const value = row[i];\n if (header === RULES_COLS.REQUIRED_COLUMNS) {\n rule[header] = value ? value.split(',').map(s => s.trim()) : [];\n } else {\n rule[header] = value;\n }\n });\n if (rule[RULES_COLS.REPORT_NAME]) rules.push(rule);\n });\n return rules;\n}\n\n// === 4. Модуль агрегации данных ===\nfunction parseNumber(value) {\n if (value === null || value === undefined || value === '') return 0;\n if (typeof value === 'number') return value;\n return parseFloat(value.toString().replace(/\\s/g, '').replace(',', '.')) || 0;\n}\n\nfunction formatNumber(value) {\n return value.toFixed(2).replace('.', ',');\n}\n\nfunction aggregateData(data, rule, targetMap) {\n if (!data || !Array.isArray(data) || data.length < 2) {\n logError('Входные данные невалидны или содержат менее 2 строк.', null);\n return [];\n }\n\n const headers = data[0];\n logInfo(`Заголовки листа: ${headers.join(', ')}`);\n const dataRows = data.slice(1);\n const groupByCol = headers.indexOf(rule[RULES_COLS.GROUP_BY_FIELD]);\n const dateCol = headers.indexOf('Day');\n\n if (groupByCol === -1) throw new Error(`Столбец группировки \"${rule[RULES_COLS.GROUP_BY_FIELD]}\" не найден.`);\n\n const requiredCols = rule[RULES_COLS.REQUIRED_COLUMNS].filter(col => col !== rule[RULES_COLS.GROUP_BY_FIELD]);\n logInfo(`Обязательные столбцы для агрегации: ${requiredCols.join(', ')}`);\n\n const goalIndices = {};\n let hasValidGoal = false;\n Object.entries(targetMap).forEach(([adveronixName, cabinetName]) => {\n let colIndex = headers.indexOf(adveronixName);\n if (colIndex === -1) colIndex = headers.indexOf(cabinetName);\n if (colIndex !== -1 && !goalIndices[cabinetName]) {\n goalIndices[cabinetName] = colIndex;\n hasValidGoal = true;\n logInfo(`Цель \"${cabinetName}\" найдена в столбце ${colIndex}`);\n }\n });\n\n if (!hasValidGoal && requiredCols.includes('\"ЦЕЛЬ\"')) {\n logError('Ни одна цель из targetMap не найдена в заголовках.', null);\n return [];\n }\n\n const stringColumns = ['Day','Campaign Name','Campaign ID','Ad Group Name','Ad Group Id','Ad Id','Criterion','Criterion Type','Placement','Device','Mobile Platform','Gender','Age'];\n\n const colIndices = {};\n requiredCols.forEach(col => colIndices[col] = headers.indexOf(col));\n\n let filteredRows = dataRows.filter(row => row[groupByCol] && row[groupByCol].toString().trim() !== '');\n if (rule[RULES_COLS.DATE_FILTER] === DATE_FILTERS.CURRENT_MONTH && dateCol !== -1) {\n const currentMonth = new Date().getMonth();\n const currentYear = new Date().getFullYear();\n filteredRows = filteredRows.filter(row => {\n const rowDate = new Date(row[dateCol]);\n return rowDate.getMonth() === currentMonth && rowDate.getFullYear() === currentYear;\n });\n }\n\n const aggregatedData = {};\n filteredRows.forEach(row => {\n const campaignCol = headers.indexOf('Campaign Name');\n const key = (campaignCol !== -1 ? row[campaignCol] + ' | ' : '') + row[groupByCol];\n if (!aggregatedData[key]) {\n aggregatedData[key] = {};\n // строки\n stringColumns.forEach(col => {\n if (requiredCols.includes(col) || col === rule[RULES_COLS.GROUP_BY_FIELD]) {\n const idx = headers.indexOf(col);\n aggregatedData[key][col] = idx !== -1 ? row[idx] : 0;\n }\n });\n // цели\n if (requiredCols.includes('\"ЦЕЛЬ\"')) {\n Object.keys(goalIndices).forEach(cabinetName => aggregatedData[key][cabinetName] = 0);\n }\n // числовые метрики\n requiredCols.forEach(col => {\n if (!aggregatedData[key][col] && col !== '\"ЦЕЛЬ\"') aggregatedData[key][col] = 0;\n });\n\n // служебные поля для Bounce Rate\n aggregatedData[key].__brSum = 0;\n aggregatedData[key].__brClicksSum = 0;\n }\n\n // наполнение\n requiredCols.forEach(col => {\n if (col === '\"ЦЕЛЬ\"') {\n Object.entries(goalIndices).forEach(([cabinetName, idx]) => {\n aggregatedData[key][cabinetName] += parseNumber(row[idx]);\n });\n } else if (!stringColumns.includes(col)) {\n const idx = colIndices[col];\n if (idx !== -1) {\n if (col === 'Bounce Rate') {\n const br = parseNumber(row[idx]); // % из отчета\n const clicksIdx = colIndices['Clicks'];\n const clicks = clicksIdx !== -1 ? parseNumber(row[clicksIdx]) : 0;\n aggregatedData[key].__brSum += br * clicks;\n aggregatedData[key].__brClicksSum += clicks;\n } else {\n aggregatedData[key][col] += parseNumber(row[idx]);\n }\n }\n }\n });\n });\n\n // вычисляем CPC, CPA, Total conversions и Bounce Rate\nObject.values(aggregatedData).forEach(item => {\n const cost = item['Cost'] || 0;\n const clicks = item['Clicks'] || 0;\n if ('CPC' in item) item['CPC'] = clicks > 0 ? cost / clicks : 0;\n\n let totalConversions = 0;\n Object.keys(goalIndices).forEach(cabinetName => totalConversions += item[cabinetName] || 0);\n item['Total conversions'] = totalConversions;\n if ('CPA' in item) item['CPA'] = totalConversions > 0 ? cost / totalConversions : 0;\n\n // считаем Bounce Rate как средневзвешенный по кликам\n if (item.__brClicksSum > 0) {\n item['Bounce Rate'] = Math.round(item.__brSum / item.__brClicksSum);\n } else {\n item['Bounce Rate'] = 0;\n }\n\n delete item.__brSum;\n delete item.__brClicksSum;\n});\n \n return formatAggregatedData(aggregatedData, rule, targetMap);\n}\n\nfunction formatAggregatedData(aggregatedData, rule, targetMap) {\n const requiredCols = rule[RULES_COLS.REQUIRED_COLUMNS];\n const groupByField = rule[RULES_COLS.GROUP_BY_FIELD];\n\n // 1️⃣ Строковые колонки\n const stringOrder = ['Day', 'Campaign Name', 'Campaign ID', 'Ad Group Id', 'Ad Id', 'Criterion', 'Criterion Type', 'Placement', 'Device', 'Mobile Platform', 'Gender', 'Age'];\n\n // 2️⃣ Числовые метрики\n const numericOrder = ['Cost', 'Clicks', 'CPC', 'Bounce Rate'];\n\n // 3️⃣ Итоговые конверсии\n const totalsOrder = ['Total conversions', 'CPA'];\n\n const finalHeaders = [];\n\n // Добавляем строки\n stringOrder.forEach(col => {\n if (requiredCols.includes(col) || col === groupByField) finalHeaders.push(col);\n });\n\n // Добавляем числовые метрики\n numericOrder.forEach(col => {\n if (requiredCols.includes(col)) finalHeaders.push(col);\n });\n\n // Добавляем цели\n if (requiredCols.includes('\"ЦЕЛЬ\"')) {\n Object.values(targetMap).forEach(cabinetName => finalHeaders.push(cabinetName));\n }\n\n // Добавляем итоговые конверсии\n totalsOrder.forEach(col => {\n if (requiredCols.includes(col)) finalHeaders.push(col);\n });\n\n // Формируем строки\n const resultRows = [finalHeaders];\n Object.keys(aggregatedData).forEach(key => {\n const row = [];\n finalHeaders.forEach(header => {\n const value = aggregatedData[key][header];\n if (value === undefined || value === null || value === '') row.push(0);\n else if (!isNaN(value) && AGGREGATION_TYPES.CALCULATED.includes(header)) row.push(formatNumber(value));\n else if (!isNaN(value)) row.push(Number(value));\n else row.push(value);\n });\n resultRows.push(row);\n });\n\n return resultRows;\n}\n\n\n\n// === 6. Верификация данных ===\nfunction verifyAggregation(rawData, aggregatedData, rule, targetMap) {\n logInfo('--- Начало проверки правильности сведения данных ---');\n\n if (!rawData || !Array.isArray(rawData) || !aggregatedData || !Array.isArray(aggregatedData)) {\n logError('Исходные или агрегированные данные невалидны.', null);\n return;\n }\n\n const headers = rawData[0];\n const dataRows = rawData.slice(1);\n const groupByCol = headers.indexOf(rule[RULES_COLS.GROUP_BY_FIELD]);\n const requiredCols = rule[RULES_COLS.REQUIRED_COLUMNS].filter(col => col !== rule[RULES_COLS.GROUP_BY_FIELD]);\n\n const stringColumns = ['Day', 'Campaign Name', 'Campaign ID', 'Ad Group Id', 'Ad Id', 'Criterion', 'Criterion Type', 'Placement', 'Device', 'Mobile Platform', 'Gender', 'Age'];\n FORBIDDEN_COLUMNS.forEach(col => {\n if (requiredCols.includes(col) && !stringColumns.includes(col)) {\n logError(`Столбец \"${col}\" включен в агрегацию, хотя не должен суммироваться.`, null);\n }\n });\n\n // Кэш целей\n const goalIndices = {};\n const usedColumns = new Set();\n Object.entries(targetMap).forEach(([adveronixName, cabinetName]) => {\n let colIndex = headers.indexOf(adveronixName);\n if (colIndex !== -1 && !usedColumns.has(colIndex)) {\n goalIndices[cabinetName] = colIndex;\n usedColumns.add(colIndex);\n } else {\n colIndex = headers.indexOf(cabinetName);\n if (colIndex !== -1 && !usedColumns.has(colIndex)) {\n goalIndices[cabinetName] = colIndex;\n usedColumns.add(colIndex);\n }\n }\n });\n}\n\n// === 7. Запись и обновление данных ===\nfunction writeData(sheet, data) {\n if (!sheet || !data || data.length === 0) return;\n sheet.clearContents();\n sheet.getRange(1, 1, data.length, data[0].length).setValues(data);\n}\n\nfunction updateMasterTable(masterSheet, rowIndex, status, errorMessage) {\n const headers = masterSheet.getRange('1:1').getValues()[0];\n const lastUpdateColIndex = headers.indexOf(MASTERTABLE_COLS.LAST_UPDATE) + 1;\n const errorsColIndex = headers.indexOf(MASTERTABLE_COLS.ERRORS) + 1;\n \n if (status === 'success') {\n masterSheet.getRange(rowIndex, lastUpdateColIndex).setValue(new Date());\n masterSheet.getRange(rowIndex, errorsColIndex).setValue('');\n } else {\n masterSheet.getRange(rowIndex, errorsColIndex).setValue(errorMessage);\n masterSheet.getRange(rowIndex, lastUpdateColIndex).setValue(new Date());\n }\n}\n\n// === 8. Главная функция ===\nfunction runReportAggregation() {\n logInfo('--- Начинаем процесс сведения отчетов ---');\n \n const mainSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();\n const masterSheet = mainSpreadsheet.getSheetByName(MASTERTABLE_SHEET_NAME);\n const rulesSheet = mainSpreadsheet.getSheetByName(RULES_SHEET_NAME);\n if (!masterSheet || !rulesSheet) return;\n\n const masterData = masterSheet.getDataRange().getValues();\n const masterHeaders = masterData.shift();\n const rules = readRules(rulesSheet);\n\n const reportLinkIndex = masterHeaders.indexOf(MASTERTABLE_COLS.REPORT_LINK);\n const projectNameIndex = masterHeaders.indexOf(MASTERTABLE_COLS.PROJECT_NAME);\n const adveronixTargetIndex = masterHeaders.indexOf(MASTERTABLE_COLS.ADVERONIX_TARGET);\n const cabinetTargetIndex = masterHeaders.indexOf(MASTERTABLE_COLS.CABINET_TARGET);\n\n const projects = {};\n let currentProject = null;\n masterData.forEach((row, i) => {\n const projectName = row[projectNameIndex];\n if (projectName) {\n currentProject = projectName;\n projects[currentProject] = { mainRow: row, rows: [row], rowIndex: i + 2 };\n } else if (currentProject) {\n projects[currentProject].rows.push(row);\n }\n });\n\n const spreadsheetCache = {};\n Object.keys(projects).forEach(projectName => {\n const project = projects[projectName];\n const masterTableRowIndex = project.rowIndex;\n const reportUrl = project.rows[0][reportLinkIndex];\n const targetMap = {};\n project.rows.forEach(row => {\n const adveronixName = row[adveronixTargetIndex];\n const cabinetName = row[cabinetTargetIndex];\n if (adveronixName && cabinetName) targetMap[adveronixName] = cabinetName;\n });\n\n try {\n if (!reportUrl) throw new Error('Отсутствует ссылка на отчет.');\n const sourceSheet = mainSpreadsheet.getSheetByName(projectName);\n if (!sourceSheet) throw new Error(`Не найдена исходная вкладка \"${projectName}\".`);\n\n const rawData = readSheetData(sourceSheet);\n rules.forEach(rule => {\n const targetSheetName = rule[RULES_COLS.REPORT_NAME];\n if (!spreadsheetCache[reportUrl]) spreadsheetCache[reportUrl] = SpreadsheetApp.openByUrl(reportUrl);\n const targetSpreadsheet = spreadsheetCache[reportUrl];\n const targetSheet = targetSpreadsheet.getSheetByName(targetSheetName);\n if (!targetSheet) throw new Error(`Не найдена целевая вкладка \"${targetSheetName}\".`);\n const aggregatedData = aggregateData(rawData, rule, targetMap);\n if (aggregatedData.length) writeData(targetSheet, aggregatedData);\n });\n\n updateMasterTable(masterSheet, masterTableRowIndex, 'success', '');\n } catch (e) {\n updateMasterTable(masterSheet, masterTableRowIndex, 'error', e.message);\n }\n });\n\n logInfo('--- Процесс завершен ---');\n}","lang":""}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Скрипт сводит данные с вкладки вашего проекта, берет условия сведения данных из вкладки «Сводные отчеты» и распределяет их в вашем отчете который указан ссылкой в столбце 🔗 Ссылка на отчет на вкладке «Главная»
"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h3","text":"Автоправила"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"function getProjectsAndReports(enableLogs = true) {\n const ss = SpreadsheetApp.getActiveSpreadsheet();\n const mainSheet = ss.getSheetByName(\"Главная\");\n if (!mainSheet) return [];\n\n const data = mainSheet.getDataRange().getValues();\n const projects = [];\n\n for (let i = 1; i < data.length; i++) { // пропускаем заголовок\n const projectName = data[i][0]; // 📂 Проект\n const reportUrl = data[i][6]; // 🔗 Ссылка на отчет\n if (reportUrl && reportUrl.toString().trim() !== \"\") {\n projects.push({ projectName, reportUrl });\n if (enableLogs) Logger.log(`[INFO] Найден проект: ${projectName}`);\n }\n }\n if (enableLogs) Logger.log(`[INFO] Всего проектов с отчетами: ${projects.length}`);\n return projects;\n}\n\nfunction getAutoRules(enableLogs = true) {\n const ss = SpreadsheetApp.getActiveSpreadsheet();\n const rulesSheet = ss.getSheetByName(\"Автоправила\");\n if (!rulesSheet || rulesSheet.getLastRow() < 2) return [];\n\n const data = rulesSheet.getDataRange().getValues();\n const headers = data[0];\n const idx = {\n name: headers.indexOf(\"Правило\"),\n logic: headers.indexOf(\"Логика\"),\n color: headers.indexOf(\"Цвет фона\"),\n targetSheets: headers.indexOf(\"Целевые листы\"),\n displayObjects: headers.indexOf(\"Объекты для вывода\"),\n project: headers.indexOf(\"Проект\") // новый столбец\n };\n\n const rules = [];\n for (let i = 1; i < data.length; i++) {\n const row = data[i];\n if (!row[idx.name]) continue;\n\n const logic = (row[idx.logic] || \"AND\").toString().toUpperCase();\n const color = row[idx.color] ? row[idx.color].toString().trim() : \"\";\n const displayObjects = (row[idx.displayObjects] || \"\").toString().split(\",\").map(s => s.trim()).filter(s => s);\n const targetSheets = (row[idx.targetSheets] || \"\").toString().split(\",\").map(s => s.trim()).filter(s => s);\n const project = row[idx.project] ? row[idx.project].toString().trim() : \"\"; // читаем проект\n\n const conditions = [];\n for (let n = 1; n <= 3; n++) {\n const colIdx = headers.indexOf(`Столбец ${n}`);\n const opIdx = headers.indexOf(`Оператор ${n}`);\n const valIdx = headers.indexOf(`Значение ${n}`);\n if (row[colIdx] && row[opIdx] && row[valIdx] !== undefined && row[valIdx] !== \"\") {\n conditions.push({\n column: row[colIdx].toString().trim(),\n operator: row[opIdx].toString().trim(),\n value: row[valIdx]\n });\n }\n }\n\n if (conditions.length > 0) {\n rules.push({ name: row[idx.name].toString().trim(), conditions, logic, color, targetSheets, displayObjects, project });\n if (enableLogs) Logger.log(`[INFO] Правило загружено: ${row[idx.name]} (Проект: ${project || \"Все\"})`);\n }\n }\n\n if (enableLogs) Logger.log(`[INFO] Всего правил загружено: ${rules.length}`);\n return rules;\n}\n\n\nfunction compareValues(value1, operator, value2) {\n // Для корректного сравнения числовых значений преобразуем их\n const num1 = Number(value1);\n const num2 = Number(value2);\n const isNumberComparison = !isNaN(num1) && !isNaN(num2) && !isNaN(value1) && !isNaN(value2);\n\n switch (operator.trim()) {\n case '==':\n // Специальная обработка для дат, чтобы сравнивать их как числа (timestamp)\n if (value1 instanceof Date && value2 instanceof Date) {\n return value1.getTime() == value2.getTime();\n }\n // Если оба значения - числа, сравниваем их как числа\n if (isNumberComparison) {\n return num1 == num2;\n }\n return value1 == value2;\n case '!=':\n if (isNumberComparison) {\n return num1 != num2;\n }\n return value1 != value2;\n case '>':\n if (isNumberComparison) {\n return num1 > num2;\n }\n return value1 > value2;\n case '<':\n if (isNumberComparison) {\n return num1 < num2;\n }\n return value1 < value2;\n case '>=':\n if (isNumberComparison) {\n return num1 >= num2;\n }\n return value1 >= value2;\n case '<=':\n if (isNumberComparison) {\n return num1 <= num2;\n }\n return value1 <= value2;\n default:\n Logger.log(`[ERROR] Неизвестный оператор: ${operator}`);\n return false;\n }\n}\n\n/**\n * Writes the grouped optimization data to the specified sheet.\n * @param {GoogleAppsScript.Spreadsheet.Sheet} sheet The target sheet.\n * @param {object} data The grouped data object.\n */\nfunction writeGroupedOptimizationData(sheet, groupedData) {\n sheet.clear();\n let currentRow = 1;\n\n for (const sheetName in groupedData) {\n for (const ruleName in groupedData[sheetName]) {\n const group = groupedData[sheetName][ruleName];\n const headers = Object.keys(group[0]);\n const displayHeaders = [\"Проект\", \"Правило\"].concat(headers);\n\n // 🔹 Заголовок блока\n sheet.getRange(currentRow, 1, 1, displayHeaders.length)\n .setValues([displayHeaders])\n .setFontWeight(\"bold\")\n .setBackground(\"#d9dff0\"); \n currentRow++;\n\n const startDataRow = currentRow;\n\n // 🔹 Данные с визуальными подсказками\n group.forEach(dataRow => {\n const values = [sheetName, ruleName];\n headers.forEach(header => {\n let value = dataRow[header];\n if (value === null || value === \"\") value = 0;\n\n // Добавляем emoji для метрик\n const h = header.toString().toLowerCase();\n if (h.includes(\"cpa\") && value > 8000) value += \" 🔥\";\n if (h.includes(\"ctr\") && value < 4) value += \" 📉\";\n if ((h.includes(\"bounce\") || h.includes(\"отказы\")) && value > 30) value += \" ⚠️\";\n\n values.push(value);\n });\n\n sheet.getRange(currentRow, 1, 1, values.length).setValues([values]);\n currentRow++;\n });\n\n const endDataRow = currentRow - 1;\n\n // 🔹 Сетка: рамка вокруг блока\n sheet.getRange(startDataRow - 1, 1, endDataRow - startDataRow + 2, displayHeaders.length)\n .setBorder(true, true, true, true, true, true, \"#cccccc\", SpreadsheetApp.BorderStyle.SOLID_MEDIUM);\n\n // 🔹 Пустая строка после блока\n currentRow++;\n }\n }\n\n // 🔹 Авторазмер колонок и фиксированные первые 2 колонки\n const lastColumn = sheet.getLastColumn();\n if (lastColumn > 0) {\n sheet.autoResizeColumns(1, lastColumn);\n sheet.setFrozenColumns(2); // Проект + Правило всегда видны\n }\n}\n\n\nfunction runAutoRules(enableLogs = true) {\n const ss = SpreadsheetApp.getActiveSpreadsheet();\n const optimizationSheetName = \"Оптимизация\";\n\n const optimizationSheet = ss.getSheetByName(optimizationSheetName) || ss.insertSheet(optimizationSheetName);\n optimizationSheet.clear();\n\n if (enableLogs) Logger.log(\"[START] Скрипт запущен\");\n\n const projects = getProjectsAndReports(enableLogs);\n const rules = getAutoRules(enableLogs);\n\n if (projects.length === 0 || rules.length === 0) {\n optimizationSheet.getRange(\"A1\").setValue(\"Нет проектов или правил для обработки\");\n if (enableLogs) Logger.log(\"[STOP] Нет проектов или правил\");\n return;\n }\n\n let optimizationData = {};\n\n projects.forEach(project => {\n if (enableLogs) Logger.log(`\\n[PROJECT] Начинаем обработку проекта: '${project.projectName}'`);\n\n let reportSpreadsheet;\n try {\n reportSpreadsheet = SpreadsheetApp.openByUrl(project.reportUrl);\n if (enableLogs) Logger.log(` [INFO] Открыт отчет по ссылке: ${project.reportUrl}`);\n } catch (e) {\n if (enableLogs) Logger.log(` [ERROR] Не удалось открыть отчет по ссылке: ${project.reportUrl}`);\n return;\n }\n\n reportSpreadsheet.getSheets().forEach(reportSheet => {\n const sheetName = reportSheet.getName();\n if (enableLogs) Logger.log(` [INFO] Обрабатываем лист: '${sheetName}'`);\n\n const lastRow = reportSheet.getLastRow();\n const lastCol = reportSheet.getLastColumn();\n if (lastRow < 2) {\n if (enableLogs) Logger.log(` - Лист '${sheetName}' пустой или содержит только заголовок`);\n return;\n }\n\n const sheetHeaders = reportSheet.getRange(1, 1, 1, lastCol).getValues()[0];\n const sheetData = reportSheet.getRange(2, 1, lastRow - 1, lastCol).getValues();\n\n const activeRules = rules.filter(rule =>\n (rule.targetSheets.length === 0 || rule.targetSheets.includes(sheetName)) &&\n (!rule.project || rule.project === project.projectName) // проверка проекта\n );\n\n if (enableLogs) Logger.log(` [INFO] Найдено правил для листа '${sheetName}': ${activeRules.length}`);\n\n activeRules.forEach(rule => {\n if (enableLogs) Logger.log(` > Применяем правило '${rule.name}' (логика: ${rule.logic})`);\n\n const displayColumns = new Set([...rule.displayObjects, ...rule.conditions.map(c => c.column)]);\n\n sheetData.forEach((row, i) => {\n const conditionResults = rule.conditions.map(cond => {\n const colIndex = sheetHeaders.findIndex(h => h.toString().trim().toLowerCase() === cond.column.toLowerCase());\n if (colIndex === -1) {\n if (enableLogs) Logger.log(` - Столбец '${cond.column}' не найден в листе '${sheetName}'`);\n return false;\n }\n const result = compareValues(row[colIndex], cond.operator, cond.value);\n if (enableLogs) Logger.log(` - Проверка строки ${i + 2}, столбец '${cond.column}': ${row[colIndex]} ${cond.operator} ${cond.value} => ${result}`);\n return result;\n });\n\n const isMatch = rule.logic === \"OR\" ? conditionResults.some(Boolean) : conditionResults.every(Boolean);\n\n if (isMatch) {\n const matchedValues = {};\n displayColumns.forEach(header => {\n const colIndex = sheetHeaders.findIndex(h => h.toString().trim().toLowerCase() === header.toLowerCase());\n matchedValues[header] = colIndex !== -1 ? row[colIndex] : \"\";\n });\n\n if (!optimizationData[project.projectName]) optimizationData[project.projectName] = {};\n if (!optimizationData[project.projectName][rule.name]) optimizationData[project.projectName][rule.name] = [];\n optimizationData[project.projectName][rule.name].push(matchedValues);\n\n if (enableLogs) Logger.log(` - Совпадение найдено! Строка ${i + 2}, данные: ${JSON.stringify(matchedValues)}`);\n }\n });\n });\n });\n });\n\n // ✅ Исправленный вызов функции\n writeGroupedOptimizationData(optimizationSheet, optimizationData);\n\n if (enableLogs) Logger.log(\"[END] Скрипт завершен\");\n}","lang":""}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Автоматизирует проверку проектов и отчётов по заранее заданным правилам:
"}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["Собирает проекты с «Главной» таблицы и ссылки на отчёты.","Читает автоправила из вкладки «Автоправила» (условия, целевые листы, логика AND/OR).","Проверяет каждую строку отчётов по правилам: сравнивает значения по условиям; учитывает выбранные столбцы для отображения; применяет логику AND/OR для всех условий.","Сохраняет совпадения с визуальными подсказками (emoji) в отдельную вкладку «Оптимизация».","Форматирует таблицу: авторазмер колонок, рамки, фиксированные первые 2 столбца."],"type":"OL"}},{"type":"media","cover":false,"hidden":false,"anchor":"","data":{"items":[{"title":"","image":{"type":"image","data":{"uuid":"2fc08396-e31b-5b19-a58f-09ab75dac0e6","width":1920,"height":1080,"size":320282,"type":"gif","color":"f9f9f9","hash":"","external_service":[],"duration":13.1131,"isVideo":false,"has_audio":false}}}]}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h3","text":"Чат-бот"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"// Данные для Telegram\nconst TELEGRAM_BOT_TOKEN = 'ваш токен';\nconst CHAT_ID = 'Ваш чатID';\n\n// Название листа, из которого берутся данные\nconst SHEET_NAME = 'Оптимизация';\n\nfunction sendUpdatesToTelegram() {\n Logger.log('--- Скрипт запущен ---');\n const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();\n const sheet = spreadsheet.getSheetByName(SHEET_NAME);\n\n if (!sheet) {\n Logger.log(`🚫 Лист с названием \"${SHEET_NAME}\" не найден.`);\n return;\n }\n\n const allValues = sheet.getDataRange().getValues();\n const HEADER_KEYWORDS = [\n 'правило', 'лист', 'campaign', 'ad group', 'placement', 'проект',\n 'cost', 'conversions', 'clicks', 'bounce rate'\n ];\n\n const blocks = parseBlocks(allValues, HEADER_KEYWORDS);\n if (blocks.length === 0) {\n Logger.log('⚠️ Не найдено ни одного блока данных.');\n return;\n }\n Logger.log(`✅ Найдено ${blocks.length} блоков.`);\n\n const properties = PropertiesService.getScriptProperties();\n const previousDataJson = properties.getProperty('previousOptimizationData');\n const previousData = previousDataJson ? JSON.parse(previousDataJson) : [];\n\n // 🔹 Оптимизация: используем Set для быстрого поиска\n const previousSet = new Set(previousData.map(row => row.join('|')));\n const allNewRows = [];\n\n // Группировка сообщений по проекту и правилу\n const groupedMessages = {};\n\n blocks.forEach(block => {\n const { headers, rows } = block;\n\n const newRows = rows.filter(row => !previousSet.has(row.join('|')));\n\n newRows.forEach(row => {\n const project = extractProject(row, headers);\n const rule = extractRule(row, headers);\n const message = formatMessage(row, headers);\n\n if (!groupedMessages[project]) groupedMessages[project] = {};\n if (!groupedMessages[project][rule]) groupedMessages[project][rule] = [];\n groupedMessages[project][rule].push(message);\n\n allNewRows.push(row);\n });\n });\n\n // Отправка сообщений группами по проекту и правилу\n for (const [project, rules] of Object.entries(groupedMessages)) {\n for (const [rule, messages] of Object.entries(rules)) {\n let combined = `📊 **Отчет по оптимизации**\\n\\n👾 **Проект**: ${project}\\n💡 **Правило**: ${rule}\\n\\n`;\n\n messages.forEach(msg => {\n const body = msg.split('\\n').slice(3).join('\\n'); // убираем дублирующий заголовок\n combined += body + '\\n\\n';\n });\n\n // Делим сообщение по лимиту Telegram (4096 символов)\n const chunks = splitMessage(combined, 4000);\n chunks.forEach(chunk => sendMessage(chunk));\n }\n }\n\n // Сохраняем историю\n if (allNewRows.length > 0) {\n const updatedData = previousData.concat(allNewRows);\n properties.setProperty('previousOptimizationData', JSON.stringify(updatedData));\n Logger.log(`💾 История обновлена (${updatedData.length} строк).`);\n }\n\n Logger.log('--- Скрипт завершен ---');\n}\n\n/**\n * Вытаскивает значение \"Правило\" из строки.\n */\nfunction extractRule(row, headers) {\n for (let i = 0; i < headers.length; i++) {\n if (headers[i].toLowerCase().includes('правило')) {\n return row[i] ? row[i].toString() : 'Без правила';\n }\n }\n return 'Без правила';\n}\n\n/**\n * Вытаскивает значение \"Проект\" из строки.\n */\nfunction extractProject(row, headers) {\n for (let i = 0; i < headers.length; i++) {\n if (headers[i].toLowerCase().includes('проект')) {\n return row[i] ? row[i].toString() : 'Без проекта';\n }\n }\n return 'Без проекта';\n}\n\n/**\n * Разбивает таблицу на блоки (каждая мини-таблица = headers + rows).\n */\nfunction parseBlocks(allValues, HEADER_KEYWORDS) {\n const blocks = [];\n let headers = null;\n let rows = [];\n\n for (let i = 0; i < allValues.length; i++) {\n const row = allValues[i];\n const isHeaderCandidate = row.some(cell =>\n typeof cell === 'string' &&\n HEADER_KEYWORDS.some(keyword => cell.toLowerCase().includes(keyword))\n );\n\n if (isHeaderCandidate) {\n if (headers && rows.length > 0) {\n blocks.push({ headers, rows });\n }\n headers = row.map(h => h.toString().trim());\n rows = [];\n } else if (headers && row.some(cell => cell)) {\n rows.push(row);\n }\n }\n\n if (headers && rows.length > 0) {\n blocks.push({ headers, rows });\n }\n\n return blocks;\n}\n\n/**\n * Форматирует строку данных в сообщение для Telegram.\n */\nfunction formatMessage(row, headers) {\n const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();\n const tableName = spreadsheet.getName();\n\n let message = `📊 **Отчет по оптимизации** (${tableName})\\n\\n`;\n\n let rule = '';\n let campaignMessage = '';\n let metricsMessage = 'Метрики:\\n';\n\n function escapeMarkdown(text) {\n if (text === null || text === undefined) return '';\n return String(text).replace(/([_*`])/g, '\\\\$1');\n }\n\n for (let i = 0; i < headers.length; i++) {\n const header = headers[i];\n const value = row[i];\n const escapedValue = escapeMarkdown(value);\n\n if (escapedValue === '') continue;\n\n const lowerHeader = header.toLowerCase();\n\n if (lowerHeader.includes('правило')) {\n rule = escapedValue;\n } else if (\n lowerHeader.includes('campaign') ||\n lowerHeader.includes('ad group') ||\n lowerHeader.includes('placement')\n ) {\n campaignMessage += `├─ **${escapeMarkdown(header)}**: ${escapedValue}\\n`;\n } else {\n if (header.trim() !== '') {\n metricsMessage += `├─ **${escapeMarkdown(header)}**: ${escapedValue}\\n`;\n }\n }\n }\n\n message += `💡 **Правило**: ${rule}\\n\\n`;\n\n if (campaignMessage.trim() !== '') {\n message += 'Кампания:\\n' + campaignMessage + '\\n';\n }\n\n if (metricsMessage !== 'Метрики:\\n') {\n message += metricsMessage;\n }\n\n return message;\n}\n\n\n/**\n * Делим длинные сообщения на части, не обрывая строки.\n */\nfunction splitMessage(message, maxLength) {\n if (message.length <= maxLength) return [message];\n\n const parts = [];\n let current = '';\n const lines = message.split('\\n');\n\n lines.forEach(line => {\n if ((current + line + '\\n').length > maxLength) {\n parts.push(current);\n current = line + '\\n';\n } else {\n current += line + '\\n';\n }\n });\n\n if (current.trim() !== '') {\n parts.push(current);\n }\n return parts;\n}\n\n/**\n * Отправка сообщения в Telegram.\n */\nfunction sendMessage(message) {\n const url = `https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage`;\n const options = {\n 'method': 'post',\n 'payload': {\n 'chat_id': CHAT_ID,\n 'text': message,\n 'parse_mode': 'Markdown'\n }\n };\n\n try {\n const response = UrlFetchApp.fetch(url, options);\n Logger.log(response.getContentText());\n } catch (e) {\n Logger.log('🚫 Ошибка при отправке сообщения в Telegram: ' + e.toString());\n }\n}","lang":""}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Автоматически отправляет отчёты по оптимизации из Google Sheets в Telegram.
"}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["Берёт данные из листа Оптимизация.","Разбивает таблицу на блоки (каждый блок = заголовок + строки с данными).","Сравнивает с предыдущими отправленными данными (сохраняются в ScriptProperties), чтобы отправлять только новые строки.","Формирует сообщения для Telegram: группирует по проекту и правилу, добавляет emoji для визуальных подсказок, выделяет кампании, метрики и правило.","Делит длинные сообщения на части ≤4000 символов (Telegram ограничение).","Отправляет в Telegram через API бота.","Обновляет историю отправленных данных, чтобы не дублировать строки при следующем запуске."],"type":"OL"}},{"type":"media","cover":false,"hidden":false,"anchor":"","data":{"items":[{"title":"","image":{"type":"image","data":{"uuid":"79f2ae4c-88be-5f62-ae6a-10a7d981d4d6","width":3420,"height":2090,"size":2295709,"type":"gif","color":"25282a","hash":"","external_service":[],"duration":7.333333,"isVideo":false,"has_audio":false}}}]}},{"type":"header","cover":false,"hidden":false,"anchor":"sozdaem-svoi-proekt","data":{"style":"h2","text":"Создаем свой проект на базе мастер-таблицы"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Теперь я расскажу о порядке действий, которые необходимо вам провести, чтобы ваши Google таблицы заработали.
"}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["После того как вы сделали копии шаблонов таблиц, вам нужно переименовать таблицы (убарать \"копия\") и вкладки с проектами.","Затем откройте вкладку с вашим первым проектом и авторизуйтесь в расширении Adveronix, выбрав в качестве источника Яндекс.Директ.","Далее создайте выгрузку по следующему шаблону:"],"type":"OL"}},{"type":"media","cover":false,"hidden":false,"anchor":"","data":{"items":[{"title":"","image":{"type":"image","data":{"uuid":"13899f20-1192-5c12-8b25-f0265f31b7e8","width":190,"height":775,"size":26558,"type":"jpg","color":"ededed","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAQDAwQDAwQEAwQFBAQFBgoHBgYGBg0JCggKDw0QEA8NDw4RExgUERIXEg4PFRwVFxkZGxsbEBQdHx0aHxgaGxr/2wBDAQQFBQYFBgwHBwwaEQ8RGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhr/wAARCAAKAAoDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAwQFCP/EACAQAAIBAwQDAAAAAAAAAAAAAAEDAgARIQQFMVETIjL/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A29tW0oRrn61ZM3SkR93AvzjFXfH2aElK4j1XAXN8RHPdMUH/2Q=="}}}]}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"4. После того как вы получили выгрузку, вернитесь на вкладку \"Главная\" и заполните таблицу:
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"📂 Проект — введите название вашего проекта. Оно должно точно совпадать с названием вкладки, куда вы сделали выгрузку.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"📊 Название цели Adveronix — укажите цели из выгрузки статистики рекламных кампаний. Названия должны быть в формате, например: Conversions_453045898_AUTO.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"🎯 Название цели кабинет — укажите, как вы хотите, чтобы цель отображалась в выгрузке. Чтобы найти соответствующее название, откройте Яндекс.Метрику и найдите цель по её ID. Например, в Conversions_453045898_AUTO число 453045898 — это ID цели в Метрике.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"🔗 Ссылка на отчет — вставьте ссылку на внешний отчет (второй шаблон) с правами на редактирование.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"5. Отредактируйте вкладку «Автоправила» при необходимости.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"6. Перейдите в настройки скриптов Apps Script (расширения -> Apps Scripts) в скрипт под названием «Чат-бот». В самом начале скрипта вы увидите
"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"// Данные для Telegram\nconst TELEGRAM_BOT_TOKEN = '';\nconst CHAT_ID = '';","lang":""}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Вам необходимо записать сюда свои значения.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Чтобы получить токен бота в Telegram необходимо создать его.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Инструкция по созданию тут
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Чтобы узнать свой chat ID найдите в Telegram бота @myidbot и отправьте ему запрос /getid. Добавьте chatID и сохраните изменения.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"7. Теперь необходимо настроить автоматический запуск всех команд, чтобы скрипты работали в автоматическом режиме. В боковой панели найдите триггеры -> кнопка «Добавление триггера» -> в появившимся окно выберите функцию runAllScriptsSequentially -> выберите источник мероприятия «Триггер по времени» -> настройте срабатывания триггера по вашему усмотрению -> Сохраните
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"8. Последний шаг — настройка внешнего отчета. Я не буду подробно разбирать все вкладки, так как очевидно, что туда будут выгружаться разные данные в зависимости от среза.
Когда я создавал отчет через Adveronix, столкнулся с проблемой: не получилось настроить выгрузку ключевых фраз и поисковых запросов в едином окне — постоянно возникала ошибка. Поэтому этот блок нужно сделать вручную.
Перейдите во внешний отчет, найдите вкладку 👀 Поисковой запрос (текущий месяц) и настройте выгрузку отчета по поисковым фразам с помощью adveronix в данную вкладку.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"✌ Готово, теперь вы можете пользоваться своими Google таблицами.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Буду рад обратной связи, надеюсь это решение поможет вам оптимизировать время на анализ ваших рекламных кампаний.
"}}],"summaryContent":null,"isExistSummaryContent":false,"warningFromEditor":null,"warningFromEditorTitle":null,"counters":{"comments":0,"favorites":1,"reposts":0,"views":217,"hits":140,"reads":null,"online":0},"dateFavorite":0,"hitsCount":140,"isCommentsEnabled":true,"isLikesEnabled":true,"isRemovedByUserRequest":false,"isFavorited":false,"isPinned":false,"repostId":null,"repostData":null,"subscribedToTreads":false,"isEditorial":false,"isAudioAvailable":false,"audioUrl":null,"isAudioAvailableToGenerate":false,"commentEditor":{"enabled":true,"who":null,"text":"","until":null,"reason":null,"type":"everybody"},"isBlur":false,"isPublished":true,"isDisabledAd":false,"withheld":[],"ogTitle":null,"ogDescription":"Оптимизация Яндекс Директ, автоматизация отчетов в Google Таблицах, использование Apps Script, создание мастер-таблицы, упрощение аналитики.","url":"https://vc.ru/marketing/2163428-optimizatsiya-reklamy-yandeks-direkt-s-google-tablitsami","author":{"id":779649,"name":"Максим Вознюк","nickname":null,"description":"Интернет-маркетолог. Рассказываю о том, как автоматизировать процесс работы рекламных кампаний и не только 👋","uri":"","avatar":{"type":"image","data":{"uuid":"5b113363-0041-5c16-bd2f-23ffa5171ad0","width":855,"height":855,"size":409712,"type":"png","color":"993c06","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQIAHAAcAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAAKAAoDAREAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAABwUI/8QAJhAAAQMDAwIHAAAAAAAAAAAAAQIDBAAFEQYSISIxExQjMlFhYv/EABYBAQEBAAAAAAAAAAAAAAAAAAYEBf/EACIRAAEDBAICAwAAAAAAAAAAAAEAAgMEBREhMVESgSJBYf/aAAwDAQACEQMRAD8AwFpiFbvLXNmbHQ46mBvj4QVuBf4APcn6PArIu1fOJoH07iAHAHeB+5SCxWmlNNUsrGBzi0kay4deO0cLkyN6spQDk8baQeQO8owGAawlXQXpToshrod8RPWnhXv+e9C718g5p469J9YdRl4579qtcoUNVxlKVEZJL6ySWxkncahgleImgE8BWywxl7iWjk/S/9k="}},"cover":{"cover":{"type":"image","data":{"uuid":"4963838f-7454-5b9a-b626-90d521d531a9","width":4896,"height":3264,"size":329702,"type":"jpg","color":"638eca","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCAAKAAoDASEAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAwUGCP/EACYQAAIBAwIEBwAAAAAAAAAAAAECAwAEBREhBgciQRIVFzFRYYH/xAAVAQEBAAAAAAAAAAAAAAAAAAAGBf/EABwRAAICAwEBAAAAAAAAAAAAAAEDAAIEISISof/aAAwDAQACEQMRAD8AJn+YuPsbUpl7nh2FgCQsEYeTbt0Lt+1HeufCK9PkEz6beIIu/wB+9Lr5ik87P2HqY7GdTPeelle7nZ5HZmcliWJJOvelup+aOMJ9GWqDU//Z"}},"cover_y":60},"achievements":[{"title":"Год на vc.ru","code":"registration_1_year","description":"Первый год с vc.ru. Получена 24 июля 2025.","previewUuid":"0d11c244-49de-50e7-894e-b9b27945d42b","formats":{"glb":"https://static.vc.ru/achievements/fish.glb","usdz":"https://static.vc.ru/achievements/fish.usdz"},"viewData":{"contentColor":"#C67AA3","textMaxWidth":0.634765625,"textX":0.5888671875,"textY":0.54296875,"logoX":0.5859375,"logoY":0.6669921875,"logoXNoText":0.6044921875,"logoYNoText":0.5439453125},"id":4657386,"userId":779649,"count":0,"shareImage":"https://api.vc.ru/achievements/share/4657386"},{"title":"3 года на vc.ru","code":"registration_3_years","description":"Провёл 3 года вместе с vc.ru. Получена 23 июля 2025.","previewUuid":"d9d72ac5-bcb5-55e0-8c72-b99251e5cdd9","formats":{"glb":"https://static.vc.ru/achievements/shark.glb","usdz":"https://static.vc.ru/achievements/shark.usdz"},"viewData":{"contentColor":"#8E6F09","textMaxWidth":0.66796875,"textX":0.5205078125,"textY":0.341796875,"logoX":0.5205078125,"logoY":0.4609375,"logoXNoText":0.5,"logoYNoText":0.3662109375},"id":1033299,"userId":779649,"count":0,"shareImage":"https://api.vc.ru/achievements/share/1033299"}],"lastModificationDate":1764993820,"isSubscribed":false,"isSubscribedToNewPosts":false,"isMuted":false,"isAvailableForMessenger":true,"badgeId":null,"isDonationsEnabled":false,"isPlusGiftEnabled":true,"isUnverifiedBlogForCompanyWithoutPro":false,"isRemovedByUserRequest":false,"isFrozen":false,"isDisabledAd":false,"isPlus":false,"isVerified":false,"isPro":false,"yandexMetricaId":null,"badge":null,"isOnline":false,"tgChannelShortname":null,"isUnsubscribable":true,"type":1,"subtype":"personal_blog"},"subsite":{"id":199113,"name":"Маркетинг","description":"Рекламные кейсы из России и других стран, советы по продвижению, маркетинг и digital.","uri":"/marketing","avatar":{"type":"image","data":{"uuid":"d66009fe-9bf0-52da-bdbf-4c758eba39e7","width":2400,"height":2400,"size":841299,"type":"jpg","color":"f97373","hash":"0c1cf06cf0d010","external_service":[]}},"cover":{"type":"image","data":{"uuid":"5488a646-f32d-57a6-a31f-d290afc4388a","width":960,"height":280,"size":177,"type":"png","color":"fc7c7c","hash":"","external_service":[]}},"lastModificationDate":1661337194,"isSubscribed":false,"isSubscribedToNewPosts":false,"isMuted":false,"isAvailableForMessenger":false,"isDisabledAd":false,"nickname":"marketing","isUnsubscribable":true,"badge":null,"badgeId":null,"isDonationsEnabled":false,"isOnline":false,"isPlus":false,"isUnverifiedBlogForCompanyWithoutPro":false,"isVerified":false,"isRemovedByUserRequest":false,"isFrozen":false,"isPro":false,"type":2,"subtype":"community"},"reactions":{"counters":[{"id":1,"count":1}],"reactionId":0},"isNews":false,"source":null,"clusters":[],"donations":{"amount":0,"isDonated":false},"commentsSeenCount":null}},{"type":"entry","data":{"id":2095040,"customUri":"kastomnaya-tsel-optimizatsiya-reklamnykh-kampanij","subsiteId":779649,"title":"Настраиваем пользовательские цели на основе поведения посетителей сайта","date":1752342421,"dateModified":1752495446,"blocks":[{"type":"media","cover":true,"hidden":false,"anchor":"","data":{"items":[{"title":"","image":{"type":"image","data":{"uuid":"f6ac00f6-23c9-5b61-b417-815edbf28bcf","width":1237,"height":617,"size":331007,"type":"jpg","color":"7f5343","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wAARCAAKAAoDAREAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAACQcK/8QAKxAAAQQAAwQLAQAAAAAAAAAAAwECBAUABgkIERRhBxITFSEjMTRBQlOR/8QAFwEBAQEBAAAAAAAAAAAAAAAABwgEBv/EACkRAAIBAgQFAwUAAAAAAAAAAAECEQMSAAQhQQUGEyIxMlFhBxQVQlL/2gAMAwEAAhEDEQA/AKNsN5Wr48XMx6SDV52t6qsu5mWsspOC2bd2tbAlHqqw8hokjRGW84AIg5CFc0bZLSOaitVEl6ry1T4hxOiKzTlmcKxBJIUGCxAEaLJiTJg7giu6ufq5bIZipSpt10osygixXaO1ASbgZAmQdzPua0vVA1cQSpIZWz7XZakhkGFIy6un/tD3K0BxkcwtKtwG5UNstURHQe8hKo53YcUxVaVFwqL9NeTwqgZV3hQLvvUW6B6rbe2fMbTGBR+eeby7S9huaU/H5s2GTKyHg2+JGhiRhDdMwpE6RHIhHonXF4I9271b8b+a/wBXGfh6JbT7F8j9R/Q+MLvECehVEmNNJ08ttjVDEIThIvmP9uH7O/NvPHZIBYug9K7D2GDaoSKjgExe2/ycf//Z"}}}]}},{"type":"link","cover":false,"hidden":false,"anchor":"","data":{"link":{"type":"link","data":{"url":"https://api.vc.ru/v2.8/redirect?to=https%3A%2F%2Ft.me%2FMaxOVo&postId=2095040","title":"Maxim Voznyuk","description":"рџ“€Marketing","image":{"type":"image","data":{"uuid":"0c5ec522-6456-5837-a7a9-efa6a12645d2","width":180,"height":180,"size":4016,"type":"png","color":"26a5e4","hash":"","external_service":[]}},"v":1,"hostname":"t.me"}}}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Всем привет 👋
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Прошел почти месяц с момента публикации моего проекта по автоматической оптимизации рекламных кампаний в Яндекс Директ — вот ссылка на пост.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"К сожалению, пост не получил достаточного отклика, чтобы я начал записывать подробную инструкцию по настройке, но всё ещё в силе: как только он наберёт 100 лайков — я обязательно подготовлю и опубликую полноценное руководство.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"А пока что — немного новостей и полезностей.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Сейчас я работаю над новым проектом, который опубликую здесь, как только доведу его до ума. Он полностью решит проблему с обучаемостью рекламных кампаний — раз и навсегда.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Но уже сегодня хочу поделиться простым скриптом, который также помогает справляться с этой проблемой. Это временное решение — менее гибкое, чем то, над которым я сейчас работаю, но оно вполне рабочее и может быть полезно прямо сейчас.
"}},{"type":"delimiter","cover":false,"hidden":false,"anchor":"","data":{"type":"default"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Что делает скрипт?"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Он создаёт 3 цели, которые автоматически заполняются в зависимости от того, насколько \"качественным\" оказался пользователь, зашедший на сайт. Затем эти цели можно использовать в качестве конверсий для оптимизации в Яндекс Директ — это позволит системе эффективнее обучаться и не останавливать обучение рекламной кампании.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Скрипт не является полностью моей разработкой, некоторую часть я позаимствовал у одного специалиста. Ссылочку на автора исходного скрипта оставлю здесь:
"}},{"type":"link","cover":false,"hidden":false,"anchor":"","data":{"link":{"type":"link","data":{"url":"https://api.vc.ru/v2.8/redirect?to=https%3A%2F%2Ft.me%2Fbest_direkt&postId=2095040","title":"Несносный дед PRO-Директ","description":"Не официальный канал про Яндекс Директ Переучиваю после бесплатных курсов Яндекс Чат канала https://goo.su/lcju3z Личка @Boris_Sindyankin Вопросы по рекламе в канале @Boris_Sindyankin","image":{"type":"image","data":{"uuid":"0c5ec522-6456-5837-a7a9-efa6a12645d2","width":180,"height":180,"size":4016,"type":"png","color":"26a5e4","hash":"","external_service":[]}},"v":1,"hostname":"t.me"}}}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Итак, давайте сначала разберем принцип работы скрипта и каким проектам он будет полезен.
"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Принцип работы"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Принцип работы максимально простой: скрипт отслеживает поведение пользователя на сайте и по завершению сессии определяет, к какому из трёх сегментов он относится:
"}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["Качественный пользователь (low) - низкая заинтересованностьРаспределение по сегментам происходит на основе заранее заданных правил. Скрипт оценивает следующие параметры:
"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"var SEGMENT_RULES = {\n 'quality_user_high': { minTimeOnSiteMs: 300000, minPageViews: 3, minScrollDepthPercentage: 30, minScrollPauses: 3 },\n 'quality_user_medium': { minTimeOnSiteMs: 60000, minPageViews: 2, minScrollDepthPercentage: 30, minScrollPauses: 2 },\n 'quality_user_low': { minTimeOnSiteMs: 0, minPageViews: 0, minScrollDepthPercentage: 0, minScrollPauses: 0 }\n }","lang":""}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["minTimeOnSiteMs - минимальное количество времени, который должен провести на сайте (в миллисекундах)","minPageViews - минимальное количество страниц, которое пользователь должен просмотреть во время сессии.Отдельно стоит отметить: скрипт умеет определять, является ли посетитель сайта ботом. Если пользователь распознан как бот — никакие цели ему не присваиваются.
"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Для каких проектов будет полезно?"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"В первую очередь такой скрипт будет полезен проектам в перегретых нишах, где:
"}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["Высокая конкуренция","дорогой CPL (стоимость лида)Чтобы внедрить скрипт на сайт и начать отслеживать поведение пользователей для последующей сегментации, потребуется следующее:
"}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["Скрипт — сам код, который будет анализировать поведение и отправлять цели в Метрику","Доступ к Яндекс Тег Менеджеру — если нет возможности напрямую редактировать HTML-код сайта","Доступ к Яндекс Метрике — минимальный уровень доступа: Аналитика, чтобы была возможность создать цели для скрипта."],"type":"UL"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Ниже опубликован сам скрипт:
"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"","lang":""}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Найдите следующую строчку
"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"ym(НОМЕР_ВАШЕГО_СЧЕТЧИКА, 'reachGoal', segment)","lang":""}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Замените \"НОМЕР_ВАШЕГО_СЧЕТЧИКА\" на актуальный номер счетчика яндекс метрики, перед тем, как установить скрипт на сайт.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Ниже — ключевые параметры скрипта, которые вы можете (и должны) настроить под особенности вашего сайта:
"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"var MAX_GOAL_COUNT_PER_DAY = 1","lang":""}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Ограничение на количество целей в сутки с одного пользователя. Позволяет избежать повторных засчитываний целей от одного и того же пользователя. По умолчанию — не больше одной цели в день.
"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"var SESSION_END_INACTIVITY_THRESHOLD = 180000","lang":""}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Порог бездействия для завершения сессии (в миллисекундах). Если пользователь не проявлял активности более 3 минут (180 000 мс), сессия считается завершённой — скрипт оценивает поведение и отправляет цель.
"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"var MIN_SESSION_DURATION_FOR_GOAL_MS = 10000","lang":""}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Минимальная продолжительность сессии, чтобы засчитать цель. Если пользователь пробыл на сайте меньше 10 секунд — поведение считается недостаточным для сегментации, и цель не отправляется.
"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"var SCROLL_PAUSE_DURATION = 3000","lang":""}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Длительность паузы между скроллами (в миллисекундах). Используется для оценки \"вдумчивого\" чтения. Если пользователь останавливается во время скролла хотя бы на 3 секунды — засчитывается пауза.
"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"var SEGMENT_CHECK_INTERVAL_MS = 5000","lang":""}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Интервал проверки сегментации (в миллисекундах). Скрипт каждые 5 секунд анализирует активность пользователя, чтобы определить, достиг ли он нужного уровня вовлечённости.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Условия (правила) для распределения пользователя в тот или иной сегмент описаны выше.
"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Создаем цель в Яндекс Метрике"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Теперь, когда вы отредактировали скрипт, нужно создать соответствующие цели в интерфейсе Яндекс Метрики.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Переходим в нужный счётчик → раздел «Цели» → «Добавить цель», и создаём 3 цели типа \"JavaScript-событие\" с идентификаторами:
"}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["quality_user_low","quality_user_mediumНиже записал видео как пример создания цели quality_user_low
"}},{"type":"media","cover":false,"hidden":false,"anchor":"","data":{"items":[{"title":"","image":{"type":"image","data":{"uuid":"06bababd-9d3e-54f8-8d4e-13def5d9a63c","width":2848,"height":1336,"size":1093919,"type":"gif","color":"1f2220","hash":"","external_service":[],"duration":28.45,"isVideo":false,"has_audio":false}}}]}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Установка скрипта с помощью Яндекс Тег Менеджера"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Если у вас нет доступа к HTML-коду сайта, вы можете установить скрипт через Яндекс Тег Менеджер (ЯТМ). Это удобно, быстро и не требует участия разработчиков.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Чтобы начать работу с ЯТМ, нужно сначала убедиться, что:
"}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["Тег Менеджер активирован — это можно сделать в настройках счётчика Яндекс Метрики. 👉 Важно: активировать Тег Менеджер может только владелец счётчика.","У вас есть доступ к контейнеру — для полноценной работы (просмотр, редактирование и добавление скриптов) необходим доступ с правами:","«Просмотр контейнера»","«Редактирование контейнера»","«Создание контейнера»"],"type":"UL"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Внутри интерфейса ЯТМ перейдите в раздел «Теги» и нажмите на кнопку «Добавить тег», откроется окно создания тега со следующим содержимым:
"}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["Название — придумайте название тегу, оно может быть произвольным, например «Качественный пользователь»","Шаблон тега — в выпадающем списке выберите «Пользовательский HTML» и вставьте подготовленный скрипт внутрь появившегося окна","Триггеры — пока оставьте пустымСохраните ваш тег.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Перейдите в раздел «Триггеры» и нажмите на кнопку «Добавить триггер», откроется окно создания тега со следующим содержимым:
"}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["Название — придумайте название тегу, оно может быть произвольным, например «Качественный пользователь»","Тип триггера — в выпадающем списке выберите «Просмотр страницы»","Условия активации триггера — все события"],"type":"UL"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Сохраните ваш триггер.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"После создания триггера вернитесь в раздел «Теги», откройте ранее созданный тег и выберите нужный триггер в соответствующем поле. В конечном счете у вас должно быть примерно вот так:
"}},{"type":"media","cover":false,"hidden":false,"anchor":"","data":{"items":[{"title":"","image":{"type":"image","data":{"uuid":"b255a464-4053-5e29-b1a9-42f4ca5b205b","width":1348,"height":1734,"size":131682,"type":"png","color":"343983","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAAKAAoDAREAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAQFCf/EAB8QAAIBBAIDAAAAAAAAAAAAAAECAwAEESExYSJS0f/EABYBAQEBAAAAAAAAAAAAAAAAAAEAA//EABkRAQEBAAMAAAAAAAAAAAAAAAABEQISYf/aAAwDAQACEQMRAD8A0ws7pVmkSe8kTLkKq+Qx2DW3O5JMVxYFtoYmk49V+Vn28Qso0MSkopOTvHdFEMHmgP/Z"}}}]}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Не забудьте опубликовать изменения, без этого скрипт не заработает на сайте.
"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Проверка работоспособности"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Теперь, когда вы опубликовали тег в интерфейсе ЯТМ осталось проверить его работоспособность. Для этого перейдите на сайт, откройте режим разработчика и перейдите во вкладку «Console». Вы должны увидеть, что скрипт начал исполняться, соответствующие сообщения вы должны увидеть здесь.
"}},{"type":"media","cover":false,"hidden":false,"anchor":"","data":{"items":[{"title":"","image":{"type":"image","data":{"uuid":"b7d69c0f-4d4b-591a-8d51-45d68398def1","width":3420,"height":2014,"size":1006820,"type":"png","color":"e4e0da","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAAKAAoDAREAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAACQQI/8QAJBAAAgEDAgYDAAAAAAAAAAAAAQIDBAURAAYIEhQWIWETImL/xAAWAQEBAQAAAAAAAAAAAAAAAAAFBAb/xAAgEQABAwMFAQAAAAAAAAAAAAABAAIDBBFxBSExMmGx/9oADAMBAAIRAxEAPwCxuCt7Nc6Wsu2y6ea2xFusMMpccuD9h4JznHgA6z8cmoNdZ4uPiSjhpzE6SVwBHDdyT5twsjXCgsUFfUwpDBGsczqEYgFQGIwfenm3IBujTZJRu/c+5e3oF7huePmIx1cn696M1AAQDKSoCTOcIqtxMz7gubMxLGsmJJPknnOko+gwoJO5yv/Z"}}}]}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"[SegTracker] Скрипт инициализирован.\n[SegTracker] Первая страница в сессии.\n[SegTracker] Проверка сегмента: Время на сайте (мс): 100, Просмотры страниц: 1, Прокрутка (%): 0.00 (макс. пикселей: 0), Паузы скролла: 0\n[SegTracker] Текущий сегмент: quality_user_low\n[SegTracker] Обнаружен и сохранен новый сегмент: quality_user_low. Предыдущий сегмент: не определен\n[SegTracker] Проверка сегмента: Время на сайте (мс): 5002, Просмотры страниц: 1, Прокрутка (%): 0.00 (макс. пикселей: 0), Паузы скролла: 0","lang":""}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Эти сообщения, которые выводятся в консоли говорят о том, что скрипт запустился и начал свою работу.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Поскольку цель отправляется только после завершения сессии — либо по таймауту в 3 минуты бездействия, либо при закрытии вкладки или браузера — для отладки рекомендую использовать режим дебага.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Откройте сайт с параметром отладки, например:
"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"www.washsaite.ru?_ym_debug=2","lang":""}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Параллельно откройте инструменты разработчика (F12) → вкладка Console. Выполните какие-либо действия на сайте (пролистывания, переходы, задержитесь на странице), и наблюдайте, что выводится в консоль — скрипт покажет, какой сегмент был назначен.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Когда увидите сообщение о присвоении сегмента (например, Обнаружен и сохранен новый сегмент: quality_user_low. ), вручную отправьте срабатывание цели, выполнив в консоли команду:
"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"sendFinalGoal();","lang":""}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"После того как отправите команду в консоль, откройте вкладку «Events» в дебаггере Метрики — вы должны увидеть, что цель, соответствующая вашему сегменту, сработала. Это значит, что скрипт работает корректно и цели успешно передаются в Метрику.
"}},{"type":"media","cover":false,"hidden":false,"anchor":"","data":{"items":[{"title":"","image":{"type":"image","data":{"uuid":"506b5483-d3f3-5a65-a52a-9264cb8929ef","width":3420,"height":1856,"size":1705250,"type":"gif","color":"e8eeef","hash":"","external_service":[],"duration":17.15,"isVideo":false,"has_audio":false}}}]}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Теперь, когда стало понятно, что скрипт работает корректно, можно переходить к следующему шагу — добавлением соответствующих целей в настройках рекламных кампаний. Это позволит алгоритму Яндекса получать больше конверсий и поддерживать обучаемость алгоритмов даже в условиях небольшого бюджета или высокой стоимости лида.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"✌ Надеюсь этот скрипт поможет в оптимизации ваших рекламных кампаний. Если будут вопросы, замечания, предложения — пишите, всегда открыт для всех.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Ну а если вам нужна настройка рекламных кампаний, аудит или консультация, можете написать мне в телеграм 😊
"}},{"type":"link","cover":false,"hidden":false,"anchor":"","data":{"link":{"type":"link","data":{"url":"https://api.vc.ru/v2.8/redirect?to=http%3A%2F%2Ft.me%2FmaxOvo&postId=2095040","title":"Maxim Voznyuk","description":"рџ“€Marketing","image":{"type":"image","data":{"uuid":"0c5ec522-6456-5837-a7a9-efa6a12645d2","width":180,"height":180,"size":4016,"type":"png","color":"26a5e4","hash":"","external_service":[]}},"v":1,"hostname":"t.me"}}}}],"summaryContent":null,"isExistSummaryContent":false,"warningFromEditor":null,"warningFromEditorTitle":null,"counters":{"comments":4,"favorites":5,"reposts":0,"views":402,"hits":241,"reads":null,"online":0},"dateFavorite":0,"hitsCount":241,"isCommentsEnabled":true,"isLikesEnabled":true,"isRemovedByUserRequest":false,"isFavorited":false,"isPinned":false,"repostId":null,"repostData":null,"subscribedToTreads":false,"isEditorial":false,"isAudioAvailable":false,"audioUrl":null,"isAudioAvailableToGenerate":false,"commentEditor":{"enabled":true,"who":null,"text":"","until":null,"reason":null,"type":"everybody"},"isBlur":false,"isPublished":true,"isDisabledAd":false,"withheld":[],"ogTitle":null,"ogDescription":"Скрипт для сегментации пользователей, создание целей в Яндекс Метрике, оптимизация рекламных кампаний, повышение эффективности в Яндекс Директ","url":"https://vc.ru/marketing/2095040-kastomnaya-tsel-optimizatsiya-reklamnykh-kampanij","author":{"id":779649,"name":"Максим Вознюк","nickname":null,"description":"Интернет-маркетолог. Рассказываю о том, как автоматизировать процесс работы рекламных кампаний и не только 👋","uri":"","avatar":{"type":"image","data":{"uuid":"5b113363-0041-5c16-bd2f-23ffa5171ad0","width":855,"height":855,"size":409712,"type":"png","color":"993c06","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQIAHAAcAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAAKAAoDAREAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAABwUI/8QAJhAAAQMDAwIHAAAAAAAAAAAAAQIDBAAFEQYSISIxExQjMlFhYv/EABYBAQEBAAAAAAAAAAAAAAAAAAYEBf/EACIRAAEDBAICAwAAAAAAAAAAAAEAAgMEBREhMVESgSJBYf/aAAwDAQACEQMRAD8AwFpiFbvLXNmbHQ46mBvj4QVuBf4APcn6PArIu1fOJoH07iAHAHeB+5SCxWmlNNUsrGBzi0kay4deO0cLkyN6spQDk8baQeQO8owGAawlXQXpToshrod8RPWnhXv+e9C718g5p469J9YdRl4579qtcoUNVxlKVEZJL6ySWxkncahgleImgE8BWywxl7iWjk/S/9k="}},"cover":{"cover":{"type":"image","data":{"uuid":"4963838f-7454-5b9a-b626-90d521d531a9","width":4896,"height":3264,"size":329702,"type":"jpg","color":"638eca","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCAAKAAoDASEAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAwUGCP/EACYQAAIBAwIEBwAAAAAAAAAAAAECAwAEBREhBgciQRIVFzFRYYH/xAAVAQEBAAAAAAAAAAAAAAAAAAAGBf/EABwRAAICAwEBAAAAAAAAAAAAAAEDAAIEISISof/aAAwDAQACEQMRAD8AJn+YuPsbUpl7nh2FgCQsEYeTbt0Lt+1HeufCK9PkEz6beIIu/wB+9Lr5ik87P2HqY7GdTPeelle7nZ5HZmcliWJJOvelup+aOMJ9GWqDU//Z"}},"cover_y":60},"achievements":[{"title":"Год на vc.ru","code":"registration_1_year","description":"Первый год с vc.ru. Получена 24 июля 2025.","previewUuid":"0d11c244-49de-50e7-894e-b9b27945d42b","formats":{"glb":"https://static.vc.ru/achievements/fish.glb","usdz":"https://static.vc.ru/achievements/fish.usdz"},"viewData":{"contentColor":"#C67AA3","textMaxWidth":0.634765625,"textX":0.5888671875,"textY":0.54296875,"logoX":0.5859375,"logoY":0.6669921875,"logoXNoText":0.6044921875,"logoYNoText":0.5439453125},"id":4657386,"userId":779649,"count":0,"shareImage":"https://api.vc.ru/achievements/share/4657386"},{"title":"3 года на vc.ru","code":"registration_3_years","description":"Провёл 3 года вместе с vc.ru. Получена 23 июля 2025.","previewUuid":"d9d72ac5-bcb5-55e0-8c72-b99251e5cdd9","formats":{"glb":"https://static.vc.ru/achievements/shark.glb","usdz":"https://static.vc.ru/achievements/shark.usdz"},"viewData":{"contentColor":"#8E6F09","textMaxWidth":0.66796875,"textX":0.5205078125,"textY":0.341796875,"logoX":0.5205078125,"logoY":0.4609375,"logoXNoText":0.5,"logoYNoText":0.3662109375},"id":1033299,"userId":779649,"count":0,"shareImage":"https://api.vc.ru/achievements/share/1033299"}],"lastModificationDate":1764993820,"isSubscribed":false,"isSubscribedToNewPosts":false,"isMuted":false,"isAvailableForMessenger":true,"badgeId":null,"isDonationsEnabled":false,"isPlusGiftEnabled":true,"isUnverifiedBlogForCompanyWithoutPro":false,"isRemovedByUserRequest":false,"isFrozen":false,"isDisabledAd":false,"isPlus":false,"isVerified":false,"isPro":false,"yandexMetricaId":null,"badge":null,"isOnline":false,"tgChannelShortname":null,"isUnsubscribable":true,"type":1,"subtype":"personal_blog"},"subsite":{"id":199113,"name":"Маркетинг","description":"Рекламные кейсы из России и других стран, советы по продвижению, маркетинг и digital.","uri":"/marketing","avatar":{"type":"image","data":{"uuid":"d66009fe-9bf0-52da-bdbf-4c758eba39e7","width":2400,"height":2400,"size":841299,"type":"jpg","color":"f97373","hash":"0c1cf06cf0d010","external_service":[]}},"cover":{"type":"image","data":{"uuid":"5488a646-f32d-57a6-a31f-d290afc4388a","width":960,"height":280,"size":177,"type":"png","color":"fc7c7c","hash":"","external_service":[]}},"lastModificationDate":1661337194,"isSubscribed":false,"isSubscribedToNewPosts":false,"isMuted":false,"isAvailableForMessenger":false,"isDisabledAd":false,"nickname":"marketing","isUnsubscribable":true,"badge":null,"badgeId":null,"isDonationsEnabled":false,"isOnline":false,"isPlus":false,"isUnverifiedBlogForCompanyWithoutPro":false,"isVerified":false,"isRemovedByUserRequest":false,"isFrozen":false,"isPro":false,"type":2,"subtype":"community"},"reactions":{"counters":[{"id":1,"count":3}],"reactionId":0},"isNews":false,"source":null,"clusters":[],"donations":{"amount":0,"isDonated":false},"commentsSeenCount":null}},{"type":"entry","data":{"id":2043077,"customUri":"avtomatizatsiya-reklamnykh-kampanij-yandeks-direkt-telegram-api","subsiteId":779649,"title":"Создаем кнопку бабло 🫰: Автоматическая оптимизация рекламных кампаний с помощью Direct и Telegram API","date":1749911416,"dateModified":1749913417,"blocks":[{"type":"media","cover":true,"hidden":false,"anchor":"","data":{"items":[{"title":"","image":{"type":"image","data":{"uuid":"c7387380-7f29-5e27-b7b8-e808a6d3dc9c","width":1237,"height":617,"size":808030,"type":"jpg","color":"4493d0","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wAARCAAKAAoDAREAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAACQYH/8QAIRAAAwEBAQACAQUAAAAAAAAAAQIDBAUGABESCAkhMkH/xAAWAQEBAQAAAAAAAAAAAAAAAAAHCAn/xAApEQACAgECAgoDAAAAAAAAAAABAgMEBgURACEHEhMUIjFBRlJkFSYy/9oADAMBAAIRAxEAPwBQ/N/qY7fOzcrs8T1g6W3qdFMwlp2Ys+SQvYTz0pddNFlIfkjX0WM4yX8m/ohY2XLj9exqdrT72nd2rVIpJZJhHIerHCheVjuqggKpIAPpzIB5RkMssVtOr6jT1DvNizKkccXXTxPK4WMeFmO7MVB5Hfcgb+fGmZf3Iey2bOw9D5twYSIdexFlYGakMrKCrKw/kMpIIIIJB+/hFJkvRArurR5F1ldlO2l1iNwSDse/8xuOR9fPhlix7pdaONlTHyrIhUnULgJBUEEj8ZyJHmPTgFcWzW3hGm2rS0znIKG9ShBRQQVLfiQQSCPr6IJH+/NHa1CjLkk6S06kiStJHKsleF1kjcOrxyKyEOjqSrKwKspIIIO3GaN6/ehxuCSG5bikiMUkTxWJo3jkRkZHjZXDI6MAyspDKQCCCOLLie09jk4vIy5fWelzZc3LwZ82bP3epGGeEckpxhCM9SzlGU1Wc5zVUmiqqqFAHwqkwDBO0f8ASsS/tvbej/I/S4YIukDPDFGTm2Xb9mnuTWfiPu8f/9k="}}}]}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Признаюсь честно, я долго не решался писать на эту тему. Никогда не учился кодить, и мне бывает сложно использовать профессиональный сленг, объясняя простыми словами то, что сам понимаю скорее интуитивно. Однако возможности автоматической оптимизации всегда меня крайне сильно интересовали. Ведь это значительно экономит время, освобождает внимание, и, в отличие от человека, автоматика практически никогда не ошибается. Я уверен, если научиться использовать этот инструмент — перед вами открываются безграничные возможности для ведения и оптимизации рекламных кампаний, а время на оптимизацию сократится в десятки раз, что позволит вести больше клиентов единовременно.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"С помощью бота в Telegram и Яндекс Директ API вы сможете автоматизировать проверку рекламных кампаний своих клиентов. Прямо в чате Telegram вы сможете добавлять минус-слова и площадки РСЯ, получать статистику и управлять необходимыми настройками. Также можно настроить проверку кампаний по расписанию.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"На реализацию кода у меня ушло около трех недель, было более 5 попыток и в конце концов все получилось. Чтобы подготовить максимально подробную инструкцию нужно очень много времени. Пока я не понимаю насколько вам будет это интересно и поэтому в этой статье мы просто рассмотрим функционал который я смог реализовать. Если этот пост наберет много реакций, то в следующей статье я напишу детальную инструкцию по реализации вашего бота, который вы можете развернуть локально или на облачном сервере.
"}},{"type":"media","cover":false,"hidden":false,"anchor":"","data":{"items":[{"title":"","image":{"type":"image","data":{"uuid":"06c37020-8edc-551d-8145-d4f2a23dacf1","width":3410,"height":1992,"size":6010662,"type":"gif","color":"1e1f23","hash":"","external_service":[],"duration":39.016667,"isVideo":false,"has_audio":false}}}]}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Возможности бота"}},{"type":"media","cover":false,"hidden":false,"anchor":"","data":{"items":[{"title":"Приветственное сообщение в боте после команды /start","image":{"type":"image","data":{"uuid":"260fd1e9-8261-5ab8-9789-7671752c2e26","width":874,"height":354,"size":18899,"type":"png","color":"3a3a3f","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAAKAAoDAREAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAABAUGCP/EACQQAAIBAwEJAQAAAAAAAAAAAAECAwAEEQUSFCMyM1FhcZHR/8QAFwEAAwEAAAAAAAAAAAAAAAAAAQIDAP/EAB8RAAEDAwUAAAAAAAAAAAAAAAABAgMREhMhMTJRYf/aAAwDAQACEQMRAD8AzbLpzklY2tEY4O0LZDjHt8VVIuxFfRdAJoNQRiq3FmQDgHdov2ji9BeM1llynEbpd/AoRcDO3J0yPnnb7VhT/9k="}}}]}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Мой бот уже умеет следующее:
"}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["Искать стоп-слова в поисковых кампаниях и автоматически добавлять их в настройки кампаний.","Запрещать показы на РСЯ-площадках, используя заранее настроенные автоправила.При запуске этой функции бот запрашивает список клиентов и активных поисковых кампаний, после чего приступает к анализу поисковых запросов за весь период их работы. Для корректной работы требуется заранее подготовленный список минус-слов. При обнаружении совпадения бот отправляет уведомление в Telegram и автоматически добавляет найденное слово в минус-фразы.
"}},{"type":"media","cover":false,"hidden":false,"anchor":"","data":{"items":[{"title":"","image":{"type":"image","data":{"uuid":"e95c3c90-6a61-58fc-998f-1f7e5b4414c9","width":2478,"height":1314,"size":475957,"type":"png","color":"1f1f1f","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAAKAAoDAREAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAgQGCP/EACEQAAICAQIHAAAAAAAAAAAAAAECAAMEESEUIjFBU3GR/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/EABURAQEAAAAAAAAAAAAAAAAAAAAR/9oADAMBAAIRAxEAPwDK+VmZFJCrWEA6swO0ULcfZ5a/ggV9/K+i7Ar29wAgf//Z"}}}]}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"После проверки бот направит сообщение
"}},{"type":"media","cover":false,"hidden":false,"anchor":"","data":{"items":[{"title":"","image":{"type":"image","data":{"uuid":"fd565771-7ccc-5b1a-b8d6-604d6f792fca","width":938,"height":94,"size":27726,"type":"png","color":"333333","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAAKAAoDAREAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAQUGCP/EACUQAAECBgEDBQAAAAAAAAAAAAIBAwAEBRESIQYHEyIxQlFSkf/EABUBAQEAAAAAAAAAAAAAAAAAAAEE/8QAHhEAAwEAAAcAAAAAAAAAAAAAAAERBAIDBRJBUWH/2gAMAwEAAhEDEQA/AM/TPT+gSfCnOeHJuDKylQSTelHKmDjzl09qACJbyHyy1vSxA+octa1jj7mr89kT3cC1LLHZb4EwVjpMICLnDqyZIiIRJUUS6/NsdReWkH3XccO4WPra+oIrQitBkX2X9hE//9k="}}}]}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Запрет показов РСЯ"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"При выполнении данной команды запускаются автоправила для анализа рекламных площадок по каждому клиенту. В случае соответствия площадки установленному правилу, она будет автоматически исключена из показа объявлений в соответствующих рекламных кампаниях. Структура автоправил представлена ниже:
"}},{"type":"media","cover":false,"hidden":false,"anchor":"","data":{"items":[{"title":"","image":{"type":"image","data":{"uuid":"d7cb6014-c9cc-5c5d-9165-e0f78f3e7b00","width":1278,"height":768,"size":30527,"type":"png","color":"1c1c1c","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAAKAAoDAREAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAQI/8QAGxAAAgIDAQAAAAAAAAAAAAAAAQMAAgURIWH/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8AwNk2Mu++3hlDbgGua8ECOAgIH//Z"}}}]}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"После анализа бот отправит вам список площадок с опцией ручного добавления в запрет показов. Я намеренно отключил автодобавление, чтобы обеспечить более точный контроль над каждой площадкой индивидуально.
"}},{"type":"media","cover":false,"hidden":false,"anchor":"","data":{"items":[{"title":"","image":{"type":"image","data":{"uuid":"f40f220b-c448-5816-9342-6d2531b7aa1c","width":822,"height":390,"size":76077,"type":"png","color":"343435","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAAKAAoDAREAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAwUGCP/EACcQAAECAwUJAAAAAAAAAAAAAAECAwAEQQUSEyNxFSEiMTJSYZTR/8QAFwEBAQEBAAAAAAAAAAAAAAAAAQIDBP/EABkRAQEBAAMAAAAAAAAAAAAAAAABAhEyQf/aAAwDAQACEQMRAD8AyJM2q6M1pyTJO4pS0Dz1SIrVzesE59D2/Pdsr67fyJK7dabury01ppHUxKnkIxl8I6jTzCH/2Q=="}}}]}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Автоматический сбор, сведение и выгрузка статистики по всем площадкам."}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Используя эту функцию, бот собирает данные по всем площадкам всех клиентов, анализирует ключевые показатели эффективности и представляет их в виде структурированной таблицы, которую затем отправляет пользователю в формате Excel.
"}},{"type":"media","cover":false,"hidden":false,"anchor":"","data":{"items":[{"title":"После проверки бот присылает таблицу с выгрузкой","image":{"type":"image","data":{"uuid":"c9d8cd0d-90c7-5c1b-846a-02e617406bec","width":990,"height":1352,"size":81359,"type":"png","color":"2e2e2e","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAAKAAoDAREAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAABgUI/8QAIhAAAgECBQUAAAAAAAAAAAAAAQMCAAQFERJCUSEyM0Fx/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/xAAVEQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEQMRAD8AyFA526iTsFAfu2SF04Az8kvR5+0RcxYlVmCo6MhHLT0q0gm9rS5hLZ9x3Hmor//Z"}}}]}},{"type":"media","cover":false,"hidden":false,"anchor":"","data":{"items":[{"title":"А вот так выглядит сама таблица","image":{"type":"image","data":{"uuid":"1e9fe06f-12c1-5452-ab3a-1c9d6a8edba1","width":2146,"height":1692,"size":157044,"type":"png","color":"cecfd0","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAAKAAoDAREAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAQJ/8QAJRAAAAQEBQUAAAAAAAAAAAAAAAECAwQUMlEREyEkQ1Nhk7HR/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/8QAGBEBAAMBAAAAAAAAAAAAAAAAAAESUQL/2gAMAwEAAhEDEQA/ANGGYKFmF7dmk+JFk9hq3WpWMJOG6DPiR8C3WlYxS2Z569TpP0kZUxO5gP/Z"}}}]}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Расписание"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Отдельно реализована функция автозапуска первой и второй функции. Бот отправляет запрос каждые 6 часов, получает статистику и направляет пользователю результаты проверки.
"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Итог"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Затратив немало времени и сил, я успешно разработал функционал бота, который теперь стал незаменимым инструментом в моей повседневной работе. Хотя ручная оптимизация все еще требуется, бот позволил сократить трудозатраты в десятки раз. Проект является бесплатным, обладает большим потенциалом для расширения функционала, и я намерен продолжать его развитие.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Я буду рад обратной связи, как и говорил ранее, если будут реакции под этой статьей я постараюсь выложить инструкцию чтобы каждый смог создать своего бота и использовать его в повседневных задачах. Благодарю за внимание.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Ну а если вам нужна настройка рекламных кампаний в яндекс директ, пишите мне в телеграм
"}},{"type":"link","cover":false,"hidden":false,"anchor":"","data":{"link":{"type":"link","data":{"url":"https://api.vc.ru/v2.8/redirect?to=https%3A%2F%2Ft.me%2FMaxOVo&postId=2043077","title":"Maxim Voznyuk","description":"рџ“€Marketing","image":{"type":"image","data":{"uuid":"0c5ec522-6456-5837-a7a9-efa6a12645d2","width":180,"height":180,"size":4016,"type":"png","color":"26a5e4","hash":"","external_service":[]}},"v":1,"hostname":"t.me"}}}}],"summaryContent":null,"isExistSummaryContent":false,"warningFromEditor":null,"warningFromEditorTitle":null,"counters":{"comments":0,"favorites":1,"reposts":0,"views":475,"hits":209,"reads":null,"online":0},"dateFavorite":0,"hitsCount":209,"isCommentsEnabled":true,"isLikesEnabled":true,"isRemovedByUserRequest":false,"isFavorited":false,"isPinned":false,"repostId":null,"repostData":null,"subscribedToTreads":false,"isEditorial":false,"isAudioAvailable":false,"audioUrl":null,"isAudioAvailableToGenerate":false,"commentEditor":{"enabled":true,"who":null,"text":"","until":null,"reason":null,"type":"everybody"},"isBlur":false,"isPublished":true,"isDisabledAd":false,"withheld":[],"ogTitle":null,"ogDescription":"Автоматизация рекламных кампаний, бот в Telegram, Яндекс Директ API, проверка минус-слов, сбор статистики, оптимизация рекламы","url":"https://vc.ru/marketing/2043077-avtomatizatsiya-reklamnykh-kampanij-yandeks-direkt-telegram-api","author":{"id":779649,"name":"Максим Вознюк","nickname":null,"description":"Интернет-маркетолог. Рассказываю о том, как автоматизировать процесс работы рекламных кампаний и не только 👋","uri":"","avatar":{"type":"image","data":{"uuid":"5b113363-0041-5c16-bd2f-23ffa5171ad0","width":855,"height":855,"size":409712,"type":"png","color":"993c06","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQIAHAAcAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAAKAAoDAREAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAABwUI/8QAJhAAAQMDAwIHAAAAAAAAAAAAAQIDBAAFEQYSISIxExQjMlFhYv/EABYBAQEBAAAAAAAAAAAAAAAAAAYEBf/EACIRAAEDBAICAwAAAAAAAAAAAAEAAgMEBREhMVESgSJBYf/aAAwDAQACEQMRAD8AwFpiFbvLXNmbHQ46mBvj4QVuBf4APcn6PArIu1fOJoH07iAHAHeB+5SCxWmlNNUsrGBzi0kay4deO0cLkyN6spQDk8baQeQO8owGAawlXQXpToshrod8RPWnhXv+e9C718g5p469J9YdRl4579qtcoUNVxlKVEZJL6ySWxkncahgleImgE8BWywxl7iWjk/S/9k="}},"cover":{"cover":{"type":"image","data":{"uuid":"4963838f-7454-5b9a-b626-90d521d531a9","width":4896,"height":3264,"size":329702,"type":"jpg","color":"638eca","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCAAKAAoDASEAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAwUGCP/EACYQAAIBAwIEBwAAAAAAAAAAAAECAwAEBREhBgciQRIVFzFRYYH/xAAVAQEBAAAAAAAAAAAAAAAAAAAGBf/EABwRAAICAwEBAAAAAAAAAAAAAAEDAAIEISISof/aAAwDAQACEQMRAD8AJn+YuPsbUpl7nh2FgCQsEYeTbt0Lt+1HeufCK9PkEz6beIIu/wB+9Lr5ik87P2HqY7GdTPeelle7nZ5HZmcliWJJOvelup+aOMJ9GWqDU//Z"}},"cover_y":60},"achievements":[{"title":"Год на vc.ru","code":"registration_1_year","description":"Первый год с vc.ru. Получена 24 июля 2025.","previewUuid":"0d11c244-49de-50e7-894e-b9b27945d42b","formats":{"glb":"https://static.vc.ru/achievements/fish.glb","usdz":"https://static.vc.ru/achievements/fish.usdz"},"viewData":{"contentColor":"#C67AA3","textMaxWidth":0.634765625,"textX":0.5888671875,"textY":0.54296875,"logoX":0.5859375,"logoY":0.6669921875,"logoXNoText":0.6044921875,"logoYNoText":0.5439453125},"id":4657386,"userId":779649,"count":0,"shareImage":"https://api.vc.ru/achievements/share/4657386"},{"title":"3 года на vc.ru","code":"registration_3_years","description":"Провёл 3 года вместе с vc.ru. Получена 23 июля 2025.","previewUuid":"d9d72ac5-bcb5-55e0-8c72-b99251e5cdd9","formats":{"glb":"https://static.vc.ru/achievements/shark.glb","usdz":"https://static.vc.ru/achievements/shark.usdz"},"viewData":{"contentColor":"#8E6F09","textMaxWidth":0.66796875,"textX":0.5205078125,"textY":0.341796875,"logoX":0.5205078125,"logoY":0.4609375,"logoXNoText":0.5,"logoYNoText":0.3662109375},"id":1033299,"userId":779649,"count":0,"shareImage":"https://api.vc.ru/achievements/share/1033299"}],"lastModificationDate":1764993820,"isSubscribed":false,"isSubscribedToNewPosts":false,"isMuted":false,"isAvailableForMessenger":true,"badgeId":null,"isDonationsEnabled":false,"isPlusGiftEnabled":true,"isUnverifiedBlogForCompanyWithoutPro":false,"isRemovedByUserRequest":false,"isFrozen":false,"isDisabledAd":false,"isPlus":false,"isVerified":false,"isPro":false,"yandexMetricaId":null,"badge":null,"isOnline":false,"tgChannelShortname":null,"isUnsubscribable":true,"type":1,"subtype":"personal_blog"},"subsite":{"id":199113,"name":"Маркетинг","description":"Рекламные кейсы из России и других стран, советы по продвижению, маркетинг и digital.","uri":"/marketing","avatar":{"type":"image","data":{"uuid":"d66009fe-9bf0-52da-bdbf-4c758eba39e7","width":2400,"height":2400,"size":841299,"type":"jpg","color":"f97373","hash":"0c1cf06cf0d010","external_service":[]}},"cover":{"type":"image","data":{"uuid":"5488a646-f32d-57a6-a31f-d290afc4388a","width":960,"height":280,"size":177,"type":"png","color":"fc7c7c","hash":"","external_service":[]}},"lastModificationDate":1661337194,"isSubscribed":false,"isSubscribedToNewPosts":false,"isMuted":false,"isAvailableForMessenger":false,"isDisabledAd":false,"nickname":"marketing","isUnsubscribable":true,"badge":null,"badgeId":null,"isDonationsEnabled":false,"isOnline":false,"isPlus":false,"isUnverifiedBlogForCompanyWithoutPro":false,"isVerified":false,"isRemovedByUserRequest":false,"isFrozen":false,"isPro":false,"type":2,"subtype":"community"},"reactions":{"counters":[{"id":1,"count":6}],"reactionId":0},"isNews":false,"source":null,"clusters":[],"donations":{"amount":0,"isDonated":false},"commentsSeenCount":null}},{"type":"entry","data":{"id":1922477,"customUri":"kastomnye-tseli-v-yandeks-metrike","subsiteId":779649,"title":"Создаем кастомную цель в Яндекс Метрике на основе поведения пользователей.","date":1744484093,"dateModified":1749848749,"blocks":[{"type":"media","cover":true,"hidden":false,"anchor":"","data":{"items":[{"title":"","image":{"type":"image","data":{"uuid":"33107723-27c4-5180-b11f-8c3c5bb4160e","width":1237,"height":617,"size":341906,"type":"jpg","color":"ebf5fa","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wAARCAAKAAoDAREAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAACgb/xAAmEAACAgAFAwQDAAAAAAAAAAABAgMEBQYHESIAEhMIFSExJEPS/8QAFwEAAwEAAAAAAAAAAAAAAAAABggJB//EACsRAAIBAgQEBAcAAAAAAAAAAAECAwQRAAUGEgcTITEUFiKTUVJTVJHR0v/aAAwDAQACEQMRAD8Aa5nzH82WNPs0n26c4xFhN2egIaN2itmXwSGGtHDZaRzMZFCk+VWbvXaNRsW0HKKPJ4tQ5Si1cYo5K6njqS9TT1DQx715krPCFXYFNwOWQLH1NcgBmsKapqdP5jEhdHendA8akOoYFWZQd1mUG4ve9uxHTB2repvqga1ZYZR1ZiDWJmEa6UZxkWMGRiEWRGKSKm/aHXiwHcvwR1TCHR/BsQxDzFpN7RRjcdZZCpaygbirR7lLdyrdQTY9RhQ5uCWjZJZX8+6/XfI77VzDLgq7mJsoOTEhRewBJIFrk4Tni/NHV+an4KtyUjf62O46kbTkirBBIPp7Ej5fhh6pwGikDAMNp6EAj8HEmKdPYfi1vofoi/jom5831pfcf94HfC0328Hsx/zj/9k="}}}]}},{"type":"text","cover":true,"hidden":false,"anchor":"","data":{"text":"Приветствую вас! Сегодня я хочу поделиться подходом к созданию кастомных целей, основанных на действиях пользователей на сайте. В случаях, когда я работаю со сложным или дорогостоящим продуктом, количество прямых конверсионных действий может быть недостаточным для эффективного обучения рекламных кампаний.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Чтобы лучше понимать, какая аудитория проявляет интерес на промежуточных этапах, необходимо выявить определенные закономерности в поведении пользователей. Это позволит глубже анализировать маркетинговую воронку и использовать микро конверсию для обучения рекламных кампаний. Сегодня я покажу, как объединять несколько пользовательских действий в одну составную цель и использовать ее для оптимизации и обучения рекламных кампаний.
"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Подготовка"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"В первую очередь нам необходимо установить счетчики яндекс метрики и GTM (google tag manager) на сайт, а также проверить правильность их установки.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Для GTM:
"}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["Скачайте расширение \"Tag Assistant\" для вашего браузера.","Перейдите на сайт и откройте установленное расширение: если все установлено правильно, в окне расширения появится ваш установленный счетчик."],"type":"UL"}},{"type":"media","cover":false,"hidden":false,"anchor":"","data":{"items":[{"title":"","image":{"type":"image","data":{"uuid":"f13da09d-de4d-517e-9b51-7acd87b87374","width":372,"height":556,"size":39481,"type":"png","color":"3b3f44","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQIAJQAlAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAAKAAoDAREAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAABQYHCf/EACMQAAEDBAIBBQAAAAAAAAAAAAECAwQABREhEkExFSI0YbL/xAAYAQACAwAAAAAAAAAAAAAAAAACAwABBP/EAB8RAAIBAgcAAAAAAAAAAAAAAAABAgMhBBESExRBUf/aAAwDAQACEQMRAD8A0XmSot1Ibl2d+QhCUjCmQpHRGivB8DrqtDwr7ESqQqR0yVgHcLwhU+SpbDgUXlkjAG+R+6nHl6HuooMD3FvlvDaPNLi3kW1cT7qB6pM0PkOfo0sM/9k="}}}]}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Для яндекс метрики:
"}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["Перейдите в \"настройки\" -> \"счетчик\" -> пролистайте вниз до \"проверка счетчика\" -> нажмите кнопку \"проверить\".","После того, как вы нажмете кнопку, откроется ваш сайт и на экране должно появиться это:"],"type":"UL"}},{"type":"media","cover":false,"hidden":false,"anchor":"","data":{"items":[{"title":"","image":{"type":"image","data":{"uuid":"5f610b09-2aa6-5900-a5d1-268c30b250dd","width":1174,"height":64,"size":18689,"type":"png","color":"07b445","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQIAJQAlAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAAKAAoDAREAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAEGB//EAB8QAAIBBAIDAAAAAAAAAAAAAAECBwADBBEFBiFBov/EABcBAQEBAQAAAAAAAAAAAAAAAAAGBQj/xAAhEQACAgECBwAAAAAAAAAAAAAAAQIFA1OSBBQ1RJGh0f/aAAwDAQACEQMRAD8Ap7shSXbDMJf5RgFJGuWc+qh3xOfVfk5ZldW0e+lvY179IrKGM9ZA2N6OflePmnM59b2wrm0a6k90/hllZ5IBQH//2Q=="}}}]}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Определяем ключевые действия пользователей на сайте"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"На этом этапе важно определить ключевые действия, которые с высокой вероятностью совершает пользователь перед тем, как совершить целевое действие (конверсию). Для выявления этих закономерностей необходимо проанализировать путь пользователей, предшествующий успешной конверсии.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Для примера я выбрал следующие цели:
"}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["Пользователь был на сайте больше 1 минуты.","Просмотрел более 1 страницы.","Скролл более 60% страницы."],"type":"UL"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Давайте приступим к созданию цели.
"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Шаг 1: Создание цели в Яндекс.Метрике"}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["Зайдите в ваш счетчик Яндекс.Метрики.","Перейдите в раздел \"Цели\".Нам понадобятся переменные для хранения ID счетчика Метрики и отслеживания количества просмотренных страниц.
"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Переменная для ID счетчика Метрики:
"}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["В GTM перейдите в \"Переменные\".","В разделе \"Пользовательские переменные\" нажмите \"Создать\".Переменная для отслеживания просмотров страниц (с помощью Cookie):
"}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["Перейдите в \"Переменные\".","В разделе \"Пользовательские переменные\" нажмите \"Создать\".Примечание: Мы будем устанавливать и обновлять этот cookie с помощью тега на Шаге 3.
"}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Шаг 3: Создаем тег для подсчета просмотров страниц"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"Этот тег будет срабатывать на каждой странице и увеличивать значение в cookie. В GTM перейдите в \"Теги\".
"}},{"type":"list","cover":false,"hidden":false,"anchor":"","data":{"items":["Нажмите \"Создать\".","Назовите тег, например, HTML - Increment Page View Cookie.