GAS+TypescriptでGA(グーグルアナリティクス)のデータを毎朝slackに通知するbotを作ってみた

# 初めに

初めまして！
SO Technologiesで現在インターンをしてる大塚と申します。
今回インターンの一環として、弊社サービスサイトのサイト流入数・CV数・CVRをGoogle Analyticsから取得してSlackに通知してくれるBotを作ったので、その詳細を書こうと思います！


# 概要

###どんな機能？

タイマー機能を使って毎朝9~10時にGASからGoogle Analytics APIを叩く
↓
取得したGAデータをslackに通知する

### やったことまとめ

GASの新規プロジェクト作成
↓
slack APIを使ってGASからslackに通知を送る機能を作成
↓
Google Analytics APIを使ってGASからGAのデータを取得する機能を作成(Typescript)
↓
投稿用テキストを作成
↓
botの運用をスタート


# 事前準備

作業ディレクトリに移動、typescriptで新規プロジェクト作成

- clasp、google app scriptのインストール

```
# npmの場合
$ npm install @google/clasp
$ npm install @types/google-apps-script  
```
- claspログイン

```
$ npx clasp login
```
- Google Apps Script API (https://script.google.com/home/usersettings) をオンにする

# 1.GASの新規プロジェクト作成

claspで新規プロジェクトを作成する。
clasp...
Google が提供する、Google Apps Script（GAS）をローカルで管理するためのCLIツールです。
ローカルファイルとwebエディタのコードのpull,pushが簡単になりま

CLI...ブラウザ上でのGUI操作ではなく、ターミナル上でコマンド操作するためのツール

作業ディレクトリに移動、下記コマンドで新規プロジェクト作成

```
$ npx clasp create --title "Project名" --type standalone
```
事前準備ができていればここで、.clasp.josn、appsscript.jsonファイルが作成される。
(appsscript.jsonのtimezoneを"America/New_York"->"Asia/Tokyo"に変えておく)


index.tsファイルを作成し、実装はここに書いていく。

claspコマンドで使用するものは以下

```
//ローカルのコードをwebエディタに送る
$npx clasp push
//webエディタのコードをローカルに持ってくる
$npx clasp pull
//webエディタを開く
$npx clasp open
```


push,openをしてwebエディタが開けることを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506412/c0b49588-ecc9-2620-bda3-40e76ecf8884.png)
index.tsに書いたコードはpushするとここに反映される、逆にここで書いたコードはpullすればローカルのindex.tsに反映される、といった感じです。


# 2.slackAPIを使って、GASからslackチャンネルに「hello world」を通知してみる

## 2-1.slack app (https://api.slack.com/apps) でbotを作成
create new appボタンから通知用のbotを作成する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506412/468d5c79-04da-06a0-5cc8-d1b006475714.png)

## 2-2.webhookURLを発行
作成したbotを選択、webhooksをonにするとwebhookURLが発行できる。
1チャンネルにつき1URLなので、ここで投稿先のチャンネルを指定してURLを発行する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506412/2f34a82e-0332-d48c-0e2c-974a31a86d28.png)

##2.3 index.tsを編集、GASからslackに投稿してみる。

```index.ts
// 送信用メソッド
function postMessage(): void {
  const title = 'test'
  const messageBody = 'Hello World'
  postSlack(title, messageBody)
}

function postSlack(title: string, body: string): void {
  const webhookUrl = getWebhookUrl()
  const data = {
    attachments: [
      {
        color: '#D00000',
        fields: [
          {
            title: title,
            value: body
          }
        ]
      }
    ]
  }
  const payload = JSON.stringify(data)
  UrlFetchApp.fetch(webhookUrl, {
    method: 'post',
    contentType: 'application/json',
    payload: payload
  })
}

function getWebhookUrl(): string {
  const webhookurl = PropertiesService.getScriptProperties().getProperty(
    'slack_webhook'
  )
  return webhookurl
}

export { postSlack, postMessage }
```
8行目のwebhookUrlプロパティはGASのwebエディタ上で登録する必要がある。↓記載

pushしてwebエディタを開く

```
$npx clasp push
$npx clasp open 
```

右上「以前のエディタを使用」から旧エディタに変更、プロパティ登録は旧エディタじゃないとできない模様

ファイル->プロジェクトのプロパティからwebhookURLを登録する。
slack_webhook:(2.2で発行したtoken)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506412/b4a9e8a2-6925-e934-cebd-05f0e77cfe56.png)


「postMessage」メソッドを選択・実行して、指定のチャンネルに通知が飛べば成功。
上手くいかない場合は↓ログの出力ができるので問題点の発掘に便利

```
Logger.log(~~)
```

# 3.GoogleAnalyticsAPIを使ってGASからGAのデータを取得する

## 3-1.Google analyticsへのアクセス権限を付与
analyticsのアカウントユーザー管理から自分のグーグルアカウントを登録する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506412/34330bc7-2453-ac4e-531a-5912cd05247e.png)

## 3-2.Google Analytics Reporting APIの使用を許可
リソース->Googleの拡張サービスからAnalytics Reporting APIの使用を許可
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506412/dd515904-0c89-3492-5254-ccf226a2fa6a.png)


※なお、有効化した拡張サービスはappsscript.jsonに記載されるので、一度clasp pullでローカルのファイルを変更しておく。

## 3-3.GASからGAのデータを取得する
```
function getGaData(
  metrics: string,
  dimension?: string
): {
  const request: GoogleAppsScript.Analyticsreporting.Schema.ReportRequest = {
    viewId: '自身のサイトGAviewID',
    dateRanges: [{ startDate: '2020-01-01', endDate:'2021-12-31' }],
    metrics: [{ expression: metrics }]
  }
  if (dimension) {
    request.dimensions = [{ name: dimension }]
  }
  const response = Analyticsreporting.Reports.batchGet({
    reportRequests: [request]
  })
  Logger.log(response)
}
```
APIを叩くとき、metricsは取得するデータの種類を指定、dimensionsはデータの分類分けを指定できる。
Query explorerを使うと確認しやすい。
https://ga-dev-tools.appspot.com/query-explorer/

GetGaDataにmetrics、dimensionを指定して関数を実行、データがログにGAのデータが吐き出される。


# 4.データを整形して投稿用テキストを作る

↑で取得したGAデータは6次元くらいの多重hash構造になってるので、分解して欲しい数値or文字列のみを取得。response.reports[0].data.rows[0]くらいまで分解するといい感じになる？


欲しい値が取得できたら、section2で作成したslackPostメソッドと組み合わせる。
投稿用のテキスト作成は、slackAPIの公式ドキュメントを見ると色々乗っているので参考になる。https://api.slack.com/messaging/composing/layouts

かつてはattachmentしか使えず表現の自由度が低かったが、2019年2月にslackの新しいUIフレームワークとしてBlock Kitがリリースされたことにより自由度⤴︎

```
{
  "channel": "CBR2V3XEX",
  "blocks": [
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "Danny Torrence left the following review for your property:"
      }
    },
    .
    .
    .
    .
    .
    "attachments": [
        {
            "blocks": [
                {
                    "type": "section",
                    "text": {
                        "type": "mrkdwn",
                        "text": "*Alternative hotel options*"
                    }
                },
        .
        .
        .
        .

    ]
}
```


ここまで上手くできると、postSlackメソッド実行でいい感じに投稿できる。

毎朝投稿はGASのタイマー機能を使うことで制御できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506412/bbe5d13b-ac7f-f8ef-d67f-a65963fd0323.png)

👇が今作の完成形

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506412/32484ba4-5c69-3cde-8c55-e65262a7a163.png)

# 実務経験を通しての気づき・学び

### 言語化することの大切さ
インターンを初めてから、作業内容を文章化する機会が増えました。
初めの内は知らない言葉が多すぎるんですよね、あるあるだと思いますが...

調べる->ふわっと理解->すぐ忘れる

今までずっとこんな感じだったのが、この「ふわっと理解」を言語化する習慣を身につけることで三つのメリットがあると感じます。

1. 記憶が定着する
2. 他人に説明できる、「生きた知識」が身につく
3. チャットでの質問が苦にならない

1,2は言わずもがなだと思いますが、リモートワーク主流の現在では、3は大きなメリットだと思います。良くも悪くも対面だと言葉足らずでも察してくれるんですよね。「ここをこうしたら変なエラー起きたんですけど...」 とかいいながら画面見せたら大体伝わるじゃないですか笑

リモートだと、困った時に「わざわざzoom開いてもらうのもあれだな〜、でも疑問点を上手く文章化できね〜」っていう時ありますよね。そうした時に、どこで何に躓いているかをチャットで簡単に投げれるようになると楽ですよね！

因みに僕個人のやり方ですが

・3分で言語化できるものはチャットで質問
・無理ならビデオ通話の時間を取ってもらう
・ちょっとした疑問や質問は全部メモしておいて朝・夕会ついでにまとめて質問

と言った感じで、自分もすっきり&&相手の時間も極力奪わないやり方を心がけてます。

### チャットのレスは素早く
みんなチャットのレスがやたら早い...(自分が遅いだけ？?)
分報で適当に呟いたことにも数秒後にリプが来てたりして「早ぇぇ〜」と思いながらも、自分は数分後に返したりしてしまう。
普段教授からのメールも一日寝かせてから返信するようなタイプなので、これからは速度firstを心がけていきたい...

[即レスは絶対的に正義である](https://blog.inst-inc.com/quickresponseshouldbejustice/)

どうやら仕事ができる人ほどレスが早いらしい
脳死で即レス出来るようになりたい...

速度>>>>>>質>>>>>文章の美しさ

### フィードバックに感謝

完璧なつもりでプルリクを出しても結構コメントが返ってくる。
「これ自分一人じゃ一生気づかないだろうな〜」って思う指摘もあったりする。ありがたや〜

# まとめ
内定者インターンを初めて一ヶ月。
入社まで後二ヶ月あるので、その内また記事を書くと思います。

ここまで読んでくれてありがとうございました！
弊社So Technologiesに少しでも興味を持ってくれた方は是非こちらも確認してみてください👇
https://www.wantedly.com/companies/techloco


# 参考

https://qiita.com/mimizq/items/fdda4b944a9608a2b0a1
https://tech.plaid.co.jp/slack_api_spec_trend_2020/