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

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

Привязанный (bound) скрипт — проект Apps Script, который живёт внутри конкретного документа: копируется вместе с ним, видит его через getActiveSpreadsheet() и удаляется вместе с ним.

Где живёт редактор

Устанавливать не нужно ничего. Откройте любую Google-таблицу и выберите в меню Расширения → Apps Script. В новой вкладке откроется полноценная среда разработки — она работает в браузере и хранит проект в облаке.

Что вы там увидите:

  • слева — файлы проекта. Файлы кода имеют расширение .gs (Google Script), но внутри — обычный JavaScript;
  • по центру — редактор с заготовкой function myFunction() {};
  • сверху — выпадающий список функций и кнопки Выполнить и Отладка;
  • снизу — журнал выполнения: сюда падают ваши логи и тексты ошибок;
  • в левой панели — разделы Триггеры (расписания) и Журнал выполнения (история всех запусков, включая ночные автоматические).

Привязанный скрипт против отдельного проекта

Проект можно завести двумя способами, и разница между ними объясняет добрую половину вопросов новичков.

Привязанный (bound)Отдельный (standalone)
Как создатьРасширения → Apps Script из документаscript.google.com → Новый проект
Видит документ-хозяинда, getActiveSpreadsheet() вернёт егонет, вернёт null
Копируется вместе с файломданет
Может добавить меню в таблицу (onOpen)данет
Как достучаться до таблицыgetActiveSpreadsheet()SpreadsheetApp.openById('...')
Когда выбиратьавтоматизация одной конкретной таблицыбиблиотека, веб-приложение, скрипт над многими файлами

Правило простое: скрипт про одну таблицу — делайте привязанным. Если один скрипт обслуживает десяток разных таблиц или это веб-приложение — берите отдельный проект и openById().

Самая частая жалоба новичка звучит так: «У меня getActiveSpreadsheet() возвращает null». В девяти случаях из десяти человек создал проект на script.google.com, а не из меню таблицы. Активной таблицы у такого проекта просто нет — и взяться ей неоткуда.

Первая функция

Сотрите заготовку и напишите вот это.

function privet() {
  const tablica = SpreadsheetApp.getActiveSpreadsheet();
  const imya = tablica.getName();

  Logger.log('Таблица называется: %s', imya);
  Logger.log('Листов внутри: %s', tablica.getSheets().length);
}

Результат:

10:24:31  Выполнение начато
10:24:32  Информация  Таблица называется: Заявки 2026
10:24:32  Информация  Листов внутри: 3
10:24:32  Выполнение завершено

Разберём построчно.

  • function privet() — имя латиницей. Кириллицу JavaScript формально допускает, но выпадающий список редактора и триггеры с ней дружат плохо. Не рискуйте.
  • SpreadsheetApp.getActiveSpreadsheet() — «дай таблицу, из которой открыт этот скрипт». Возвращает объект Spreadsheet, то есть книгу целиком, со всеми вкладками, а не отдельный лист. Это частая путаница.
  • getName() — имя книги, getSheets() — массив её листов.
  • Logger.log(...) — печать в журнал. Поддерживает подстановку через %s, так что склеивать строки плюсами необязательно.

Logger.log или console.log?

После перехода Apps Script на движок V8 работают оба, и оба пишут в журнал выполнения. Разница тонкая: console.log дополнительно уходит в Cloud Logging, поэтому его видно в истории выполнений даже для триггера, отработавшего ночью, а Logger.log исторически «локален» для текущего запуска. На практике: для отладки в редакторе годится любой, для скриптов на триггерах предпочитайте console.log.

А чего точно нет — так это alert(). Показать окно пользователю можно, но через сервис интерфейса:

function pokazatOkno() {
  SpreadsheetApp.getUi().alert('Готово! Отчёт обновлён.');
}

Работает это только тогда, когда скрипт запущен человеком из открытой таблицы — из меню или редактора. У скрипта, разбуженного триггером в три часа ночи, интерфейса нет, и такой вызов упадёт с ошибкой. Логи в этом случае — единственный способ узнать, что произошло.

Запуск и разрешения

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

В первый раз Google остановит вас окном авторизации. Скрипт собирается трогать вашу таблицу — платформа обязана спросить разрешение. Дальше по шагам:

  1. Окно «Требуется авторизация»Ознакомиться с разрешениями.
  2. Выбрать свой аккаунт Google.
  3. Экран «Google не проверил это приложение». Он пугает, но означает буквально следующее: этот код написали вы, и Google его не проверял, потому что он и не должен. Нажмите Дополнительные настройкиПерейти к проекту (небезопасно).
  4. Экран согласия перечисляет, что именно скрипт хочет: «Просмотр и управление таблицами в Google Диске». Нажмите Разрешить.

Это и есть OAuth-согласие: вы как владелец данных выдаёте своему же скрипту токен доступа. Спрашивают один раз на проект — до тех пор, пока список нужных прав не изменится. Допишете в код GmailApp.sendEmail — при следующем запуске Google снова попросит согласия, уже и на почту.

Откуда Google знает, какие права нужны? Он сканирует ваш код и находит упоминания сервисов. Увидел GmailApp — значит, нужен доступ к почте. Итоговый список прав можно посмотреть и зафиксировать вручную в манифесте appsscript.json (Настройки проекта → «Показывать файл манифеста appsscript.json»):

{
  "timeZone": "Europe/Moscow",
  "dependencies": {},
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "oauthScopes": [
    "https://www.googleapis.com/auth/spreadsheets.currentonly"
  ]
}

Поле timeZone выставьте сразу. От него зависит, в котором часу сработает триггер «каждый день в 9:00» и что вернёт new Date(). По умолчанию там вполне может оказаться американский часовой пояс — и отчёт «за вчера» начнёт приходить со сдвигом на день.

Как это работает

  • Проект Apps Script — это набор файлов .gs на серверах Google. У привязанного скрипта он хранится внутри документа (в его служебных данных), у отдельного — на вашем Диске.
  • Все файлы .gs одного проекта делят одну глобальную область видимости. Никаких import между ними не нужно: функция из Utils.gs просто вызывается из Main.gs. Обратная сторона — две одноимённые функции в разных файлах молча затрут друг друга.
  • Нажатие «Выполнить» — это HTTP-запрос: браузер просит сервер выполнить одну конкретную функцию, выбранную в выпадающем списке. Не «весь файл».
  • Токен OAuth привязан к паре «проект + пользователь». Коллега, который откроет вашу таблицу и запустит скрипт, пройдёт согласие заново — уже от своего имени и со своими правами. Ваши письма он при этом читать не сможет, а свои — сможет.

Частые ошибки

  • Запускается не та функция. Вы написали privet, а в списке сверху осталась myFunction — Google послушно выполнит пустую заготовку и бодро отрапортует «Выполнение завершено». Всегда проверяйте выпадающий список.
  • Забыли сохранить. Редактор не сохраняет сам. Ctrl+S (⌘+S) перед каждым запуском — рефлекс.
  • Функция с параметрами. Функцию вида function obrabotat(list) нельзя запустить кнопкой: аргумент взять неоткуда, и list окажется undefined. Сделайте отдельную функцию-обёртку без параметров.
  • Испугались экрана «приложение не проверено» и закрыли вкладку. Без согласия скрипт не получит доступ, и все вызовы SpreadsheetApp будут падать. Через «Дополнительные настройки» пройти нужно — это ваш собственный код.
  • Ждут getActiveSpreadsheet() в отдельном проекте. У проекта, созданного на script.google.com, активной таблицы нет. Только openById().
  • Ищут логи триггера в редакторе. Журнал внизу показывает только текущий ручной запуск. История автоматических — в разделе Журнал выполнения слева.

Итоги

  • Редактор открывается из таблицы: Расширения → Apps Script. Ставить ничего не нужно.
  • Привязанный скрипт живёт внутри документа и видит его через getActiveSpreadsheet(); отдельный проект — нет, ему нужен openById().
  • getActiveSpreadsheet() возвращает книгу целиком, а не лист.
  • Логи — Logger.log() или console.log(); для триггеров надёжнее console.log(). alert() не существует, есть SpreadsheetApp.getUi().alert().
  • Первый запуск требует OAuth-согласия. Экран «Google не проверил это приложение» — нормально: приложение написали вы.
  • Сохраняйте перед запуском и проверяйте, какая функция выбрана в выпадающем списке.
Проверьте себя
1. Вы создали проект на script.google.com, написали код, а getActiveSpreadsheet() возвращает null. В чём причина?
AНе выданы разрешения OAuth — нужно пройти экран согласия
BПроект отдельный (standalone), у него нет документа-хозяина; нужен привязанный скрипт или openById()
CЗабыли сохранить файл перед запуском
DВ таблице нет ни одного листа с данными
2. Что означает экран «Google не проверил это приложение» при первом запуске вашего скрипта?
AСкрипт содержит опасный код, и запускать его нельзя
BНужно оплатить проверку приложения в Google Cloud
CПриложение написали вы сами, и оно не проходило верификацию Google; через «Дополнительные настройки» можно продолжить
DУ аккаунта нет прав на выполнение скриптов — нужен Google Workspace