【Twitter API v2】過去30日のツイートのインプレッション・エンゲージメントを取得する（Google Apps Script）

## はじめに
企業Twitterを運用しており、毎月のパフォーマンスを投稿数やインプレッション、エンゲージメント[^1]等を指標にして記録しています。

毎月死んだ魚の目でTwitterアナリティクスから転記することに飽きてきたので、Twitter APIで自動化できないか調べてみました。

Twitterには、その名もずばり[Twitter Engagement API](https://developer.twitter.com/en/docs/twitter-api/enterprise/engagement-api/overview)というAPIが用意されていますが、これは法人向け。今回は、すぐに申請・利用可能な**Twitter API v2**でインプレッションとエンゲージメントを取得してみます。

[^1]:**インプレッション**：
「利用者のタイムラインまたは検索結果にツイートが表示された回数」
**エンゲージメント**：
「利用者がツイートに反応した合計回数。ツイートの任意の場所（リツイート、返信、フォロー、いいね、リンク、カード、ハッシュタグ、埋め込みメディア、ユーザー名、プロフィール画像、ツイートの詳細表示など）のクリック数」
(https://help.twitter.com/ja/managing-your-account/using-the-tweet-activity-dashboard)
本記事では、狭義的に「リンクのクリック数」と「プロフィールのクリック数」のみをエンゲージメントとして扱っています。

## 目標
自己アカウントの月間ツイートのインプレッション、エンゲージメントをTwitter API v2で取得し、スプレッドシートに記録する。

法人契約（Enterprise Level）が必要な[Twitter Engagement API](https://developer.twitter.com/en/docs/twitter-api/enterprise/engagement-api/overview)は用いず、アクセスレベル "Essential" で利用可能なAPIのみを使う。
<details>
<summary>Twitter APIのアクセスレベルについて</summary>
Twitter APIには利用機能枠の異なる Essential, Elevated, Academic Research のアクセスレベルがある。さらに別APIとして、法人向けにEnterprise APIsが用意されている。

（[公式ドキュメント](https://developer.twitter.com/en/docs/twitter-api/getting-started/about-twitter-api#v2-access-level)）

- 日本語の記事では「[【2022年 Twitter API】ツイート収集したい人向けのTwitter APIの種類と使い分け](https://qiita.com/guneco/items/d9237ab75262b1015b48)」がわかりやすい。
</details>

### 完成図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2722903/f3232749-e5c7-01e4-38a9-702011224741.png)
## 取得したいもの
- 月間ツイート数
- 月間インプレッション
- 月間エンゲージメント
集計対象は過去30日の投稿したツイート。それ以前のツイートは対象外。理由は後述。

## 使うもの
- Google Apps Script
  - スプレッドシートへの転記が容易なため、今回はこれにします。 
- [OAuth1 for Apps Script](https://github.com/googleworkspace/apps-script-oauth1)
  - Google Apps ScriptでOauth1を使うためのライブラリ 
- Twitter API v2
  - GET /2/users/me
  - GET /2/users/:id/tweets

## 目次
1. [TwitterのAPI Key, API Key Secretを取得](#1-twitter%E3%81%AEapi-key-api-key-secret%E3%82%92%E5%8F%96%E5%BE%97twitter-developer-portal)
1. [Google Apps ScriptでのOAuth1認証](#2-google-apps-script%E3%81%A7%E3%81%AEoauth1%E8%AA%8D%E8%A8%BC)
1. [Twitter API v2からデータを取得する](#3-twitter-api-v2%E3%81%8B%E3%82%89%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B)
1. [スプレッドシートへのデータの転記](#4-スプレッドシートへのデータの転記)

## 1. TwitterのAPI Key, API Key Secretを取得（Twitter Developer Portal）
[Twitter Developer Portal](https://developer.twitter.com/en/portal/dashboard)から利用申請、アプリの作成、各種シークレットの取得をします。手順は[こちらの記事](https://qiita.com/donraq/items/8f36ad7e7f3c5385e763)などをご参照ください。

以前は英作文の試験があったりとハードルが高かった[^2]ようですが、今では即日で利用申請ができるようになりました。

[^2]:Qiitaに残された先人たちの奮闘の記録。
[Twitter Developerのアプリ審査に通った文例](https://qiita.com/rev84/items/95592de627a581a49738)
[Twitter APIの申請が通らない！！！！](https://qiita.com/seiji1997/items/9b901351f741cf49e579)

シークレットは、API Key, API Key Secret, Bearer Tokenの三種類ありますが、今回は、**API Key**, **API Key Secret**の2種類を使用します。[^3]

[^3]:TwitterのAPI Keyの呼称は様々で、API Keyは**Consumer Key**や**App Key**、API Secret Keyは**Consumer Secret**や**App Key Secret**と同義。[公式ドキュメント](https://developer.twitter.com/en/docs/authentication/oauth-1-0a/obtaining-user-access-tokens) の"Terminology clarification"を参考のこと。

## 2. Google Apps ScriptでのOAuth1認証
### なぜOAuth1認証？
Twitter APIはBearer Token認証など、いくつか認証方式がありますが、**Twitterのインプレッション、エンゲージメントは公開指標ではない**ので、今回はOAuth1認証が必要になります。

>Since these fields [non-public metrics, organic metrics] are private (not available to view on Twitter.com), OAuth 1.0a User Context authorization is required for the request. 
(https://developer.twitter.com/en/docs/twitter-api/metrics)

>これらのフィールド（non public, orgnic metrics）はプライベートな（Twitter.comで閲覧できない）ため、リクエストにはOAuth 1.0a User Context認証が必要です。

:::note warn
**取得できるツイートは過去30日分まで**
非公開のプライベート指標を取得できるのは、過去30日分のツイートのみ。
>Non-public, organic, and promoted metrics are only available for Tweets that have been created within the last 30 days.
(https://developer.twitter.com/en/docs/twitter-api/metrics)

対して上述のEngagement APIだと90日分が対象になります。
（https://developer.twitter.com/en/docs/twitter-api/enterprise/engagement-api/overview）
:::

### ライブラリ（OAuth1 for Apps Script）の導入
OAuth1認証にあたり、今回はGoogle Apps Script向けのライブラリ、**OAuth1 for Apps Script**を使用します。

#### Google Apps Scriptのプロジェクトを作成
後々スプレッドシートに記録するのに都合がよいので、standaloneではなく、スプレッドシートを作成しエディタを開きます。
![qiita_twitterapi_createProject.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2722903/e9f641d5-5a85-0f45-c295-9cdd84b7873b.png)

#### スクリプトプロパティにTwitterのAPI Key, API Key Secretを登録
環境変数を登録するGoogle Apps Scriptのスクリプトプロパティ。新エディタになってGUIでの登録が廃止されたのですが、アップデートで復活しました。
https://qiita.com/Tyamamoto1007/items/c12af331eb62fb6e3051

せっかくなのでGUIで登録します。歯車アイコンの「プロジェクトの設定」から**Twitter_API_KEY**と**Twitter_API_KEY_SECRET**に、先ほど取得した値をセットします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2722903/13aa0eaf-8727-9e34-4821-51366aebc210.png)

#### OAuth1 for Apps ScriptのスクリプトIDを入力
続いてライブラリの登録です。
[ライブラリのREADME.md](https://github.com/googleworkspace/apps-script-oauth1)に記載の通り、スクリプトID `1CXDCY5sqT9ph64fFwSzVtXnbjpSfWdRymafDrtIZ7Z_hwysTY7IIhi7s`
を入力します。
![qiita_twitterapi_registerLibraryKey.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2722903/d12111ad-9edf-2968-1e67-2f52025023dc.png)

### Callback URLの設定（Twitter Developer Portal）
READMEに記載の通り、OAuth1 for Apps ScriptではCallback URLは常に以下を指定します。{SCRIPT ID}をGoogle Apps ScriptのIDに書き換えてください。
`https://script.google.com/macros/d/{SCRIPT ID}/usercallback`

IDはスクリプトプロパティと同じ「プロジェクトの設定」から確認できます。

再び、[Twitter Developer Portal](https://developer.twitter.com/en/portal/dashboard)から、PROJECT APPを開きます。
![qiita_twitter_projectapp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2722903/8a7c8469-742e-4953-bd81-bdfaeffd0c78.png)
歯車アイコンを押し…
![qiita_twitter_user_authenticate.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2722903/d938a9b3-cbc5-7290-94e7-5488073ec7d5.png)
Editに進み…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2722903/997e9006-c5ec-31ee-e637-8fdf65cba95a.png)
Oauth1.0aをアクティベートし…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2722903/dcb8ff74-d1a8-6ca8-b4a7-2fbc4da54911.png)
先述のCallback URLを設定します。
`https://script.google.com/macros/d/{SCRIPT ID}/usercallback`
以上でTwitter Developer Portalで行う作業は完了です。

### 認証用のGoogle Apps Scriptを書く
折よくもOAuth1 for Apps ScriptのREADMEにTwitter用のサンプルコードが掲載されているので拝借します。（[Source](https://github.com/googleworkspace/apps-script-oauth1)）

サンプルから書き換えるのは
- `.setConsumerKey()`
- `.setConsumerSecret()`

の部分。引数にスクリプトプロパティに保存した値を渡します。

#### Serviceクラスのインスタンスを作成
```js
function getTwitterService() {
  // Create a new service with the given name. The name will be used when
  // persisting the authorized token, so ensure it is unique within the
  // scope of the property store.
  return OAuth1.createService('twitter')
    // Set the endpoint URLs.
    .setAccessTokenUrl('https://api.twitter.com/oauth/access_token')
    .setRequestTokenUrl('https://api.twitter.com/oauth/request_token')
    .setAuthorizationUrl('https://api.twitter.com/oauth/authorize')
    // Set the consumer key and secret.
    .setConsumerKey(PropertiesService.getScriptProperties().getProperty('Twitter_API_KEY'))
    .setConsumerSecret(PropertiesService.getScriptProperties().getProperty('Twitter_API_KEY_SECRET'))
    // Set the name of the callback function in the script referenced
    // above that should be invoked to complete the OAuth flow.
    .setCallbackFunction('authCallback')
    // Set the property store where authorized tokens should be persisted.
    .setPropertyStore(PropertiesService.getUserProperties());
}
```

#### 認証URLを取得・表示
Google Apps Scriptはリダイレクトができないので、認証URLをコンソールに表示させます。（※サンプルではサイドバーへ表示させていますが、ここではコンソールに表示させています。）
認証URLはService.authorize()で生成されます。

```js
function showOauthLink() {
  const twitterService = getTwitterService();
  if (!twitterService.hasAccess()) {
    const authorizationUrl = twitterService.authorize();
    Logger.log(`For Authorization, Please Click ${authorizationUrl}`);
  } else {
    Logger.log("You Are Already Authorized")
  }
}
```

#### コールバックのハンドラ関数
認証ページからのコールバックの処理用関数。こちらも[READMEのサンプル](https://github.com/googleworkspace/apps-script-oauth1)通り。

```js
function authCallback(request) {
  const twitterService = getTwitterService();
  const isAuthorized = twitterService.handleCallback(request);
  if (isAuthorized) {
    return HtmlService.createHtmlOutput('Success! You can close this tab.');
  } else {
    return HtmlService.createHtmlOutput('Denied. You can close this tab');
  }
}
```

#### showOauthLink()を実行
エディタのバーでshowOauthLink()」を指定し、実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2722903/d76f6a83-7439-433b-9424-6a7097b661cc.png)
ログのURLにアクセスし、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2722903/0198af08-23de-4958-eacb-4924f8d35859.png)
認証します。authCallback(request)が実行され、成功すると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2722903/5b94dbbd-70e1-93f8-2837-b00feb1adf51.png)
と表示されます。OauthTokenはGoogle Apps ScrptのUserPropertyに登録され、Serviceインスタンスにも保存されています。

これでGoogle Apps ScriptでのTwitterの認証は完了、APIを実行する準備が整いました。

## 3. Twitter API v2からデータを取得する
ここから実際にTwitterのAPIを使用していきます。手始めに
`GET /2/users/:id/tweets`
で必要になる自己アカウントのidを取得します。

### 自己アカウントのidを取得する（GET /2/users/me）
自己のアカウント情報は`GET /2/users/me`で取得できます。([公式ドキュメント](https://developer.twitter.com/en/docs/twitter-api/users/lookup/api-reference/get-users-me))
以下の関数を実行します。
```js
function findMyUserId() {
  const twitterService = getTwitterService()
  const response = twitterService.fetch('https://api.twitter.com/2/users/me')
  const userId = JSON.parse(response).data.id
  PropertiesService.getScriptProperties().setProperty('Twitter_MY_USER_ID',userId)
}
```
取得したidはスクリプトプロパティに保管しています。

### ツイートのインプレッションとエンゲージメントを取得する（GET /2/users/:id/tweets）
いよいよインプレッションとエンゲージメントを取得していきます。使うエンドポイントは`GET /2/users/:id/tweets`。（[公式ドキュメント](https://developer.twitter.com/en/docs/twitter-api/tweets/timelines/api-reference/get-users-id-tweets)）
ドキュメント記載のクエリパラメータのうち、以下の二つを指定します。
| クエリパラメータ | 内容 |
|:-:|:-:|
|tweet.fields=non_public_metrics| 'non_public_metrics'をレスポンス含める  |
|exclude=retweets| レスポンスからリツイートを除外する  |

```js
function getUserTweetsData() {
  const twitterService = getTwitterService()
  const twitterUserId = PropertiesService.getScriptProperties().getProperty('Twitter_MY_USER_ID')
  const baseUrl = 'https://api.twitter.com'
  const endpointUrl = `/2/users/${twitterUserId}/tweets`
  const queryParam = `?tweet.fields=non_public_metrics&exclude=retweets`
  let response = JSON.parse(twitterService.fetch(`${baseUrl}${endpointUrl}${queryParam}`))
  Logger.log(JSON.stringify(response))
}
```
実行すると以下を含むレスポンスが得られます。
- `user_profile_clicks`
- `impression_count`
- `url_link_clicks`

```response.json
{
    "data": [
        {
            "non_public_metrics": {
                "impression_count": 1660,
                "user_profile_clicks": 3,
                "url_link_clicks": 19
            },
            "id": "15408367XXXXXXXXXXX",
            "text": "◆◆ツイート内容1◆◆"
        },
        {
            "non_public_metrics": {
                "impression_count": 5120,
                "user_profile_clicks": 8,
                "url_link_clicks": 29
            },
            "id": "15390627XXXXXXXXXXX",
            "text": "◆◆ツイート内容2◆◆"
        },
        (中略)
        {
            "non_public_metrics": {
                "impression_count": 3535,
                "user_profile_clicks": 12,
                "url_link_clicks": 52
            },
            "id": "15311564XXXXXXXXXXX",
            "text": "◆◆ツイート内容3◆◆"
        }
    ],
    "meta": {
        "next_token": "7140dibdnow9c7btw421t2ewenfp071jxnenj8gjljfoy",
        "result_count": 10,
        "newest_id": "154083673XXXXXXXXXXX",
        "oldest_id": "153115644XXXXXXXXXXX"
    }
}

```
:::note warn
**'start_time', 'end_time'の指定**
"non_public_metrics"が取得可能なツイートは過去30日間のものに限られますが、'start_time', 'end_time'を含めるとさらに取得期間を限定でき、たとえば過去一週間分だけを取得することもできます。
形式は`YYYY-MM-DDTHH:mm:ssZ (ISO 8601/RFC 3339)`。Google Apps Scriptの場合は、さらに`encodeURIComponent`でエンコードする必要があります。
エンコードをしないと401エラーが返ります。[（参考）](https://twittercommunity.com/t/recent-search-queries-with-start-time-parameter-and-user-context-authentication-fail-with-401-unauthorized/142104/3)
:::

### paginationを追加する
Twitter APIでは、クエリパラメータ`max_results`（デフォルトは10。最大100）で指定した数を越えるツイートを取得する場合は、**pagination**の処理が必要になります。

先ほどのresponseに含まれていた、
` "next_token": "7140dibdnow9c7btw421t2ewenfp071jxnenj8gjljfoy"`
を、今度は**リクエスト（GET /2/users/:id/tweets）の`pagination_token`に追加**することで、ページ送りができます。
```markdown:リクエストURLの例
https://api.twitter.com/2/users/${twitterUserId}/tweets?tweet.fields=non_public_metrics&exclude=retweets&pagination_token=7140dibdnow9c7btw421t2ewenfp071jxnenj8gjljfoy
```
これを踏まえてpaginationの処理を加えたコード。エラー処理も加えました。また、`tweet.field`に`created_at`も追加しています。
```js
function getUserTweetsData() {
  const twitterService = getTwitterService()
  const twitterUserId = PropertiesService.getScriptProperties().getProperty('Twitter_MY_USER_ID')
  const baseUrl = 'https://api.twitter.com'
  const endpointUrl = `/2/users/${twitterUserId}/tweets`
  const queryParam = `?tweet.fields=non_public_metrics,created_at&exclude=retweets`
  let response = JSON.parse(twitterService.fetch(`${baseUrl}${endpointUrl}${queryParam}`))
  if (!response.data) {
    Logger.log('No tweet found')
    return
  }

  let tweetDataArr = response.data
  let nextToken = response.meta.next_token

  while (nextToken) {
    response = JSON.parse(twitterService.fetch(`${baseUrl}${endpointUrl}${queryParam}&pagination_token=${nextToken}`))
    if (!response.data) {
      break
    }
    tweetDataArr.push(...response.data)
    nextToken = response.meta.next_token
  }
  //ToDo: Twitter APIのデータ(tweetDataArr)をスプレッドシート用の二重配列に変換
  //ToDo:　その月の新しいシートを作成し、変換したデータをセットする
}
```
これで、ツイートのデータが入ったobjectが`tweetDataArr`に配列で格納されました。スプレッド構文を使った`.push`で破壊的に追加する点、注意です。（[参考](https://qiita.com/Nossa/items/e6f503cbb95c8e6967f8)）
残るはスプレッドシートへの転記のみ。

参考：[公式ドキュメント](https://developer.twitter.com/en/docs/twitter-api/pagination)

## 4. スプレッドシートへのデータの転記
最後にスプレッドシート周りのGoogle Apps Scriptを書きます。
### データの二次元配列への整形
スプレッドシートに値を入れる.setValues()は引数に二次元配列を取ります。[^4]
[^4]:.setValue()よりも.setValues()の方がAPIの呼び出し回数が少なく処理が軽いので、.setValues()を用います。

そこでTwitter APIで取得したデータから必要なプロパティを抽出し、二次元配列に整えます。

`response.data`の配列を引数に二次元配列を返す関数を以下のように定義します。
```js
/**
  *Twitter APIからのレスポンスを配列にして返す関数。
  *@param {object[]}
  *@return {(number | string)[][]}
  */
function formatTwitterResponse(tweetDataArr) {
  return tweetDataArr.map((tweet) => {
    //url_link_clicks, user_profile_clicksの合計をエンゲージメントとする。
    const engagements = (url_link_clicks, user_profile_clicks) => {
      if (!url_link_clicks) {
        url_link_clicks = 0
      }
      else if (!user_profile_clicks) {
        user_profile_clicks = 0
      }
      return url_link_clicks + user_profile_clicks
    }
    return [tweet.id, tweet.created_at, tweet.text, tweet.non_public_metrics.impression_count, engagements(tweet.non_public_metrics.url_link_clicks, tweet.non_public_metrics.user_profile_clicks)]
  })
}
```

### スプレッドシートにデータを落とし込む関数を作成
最後にスプレッドシートにデータを落とし込みます。以下の手順で作成します。
1. テンプレートシートをコピー。集計対象の年月をシート名に指定。
2. データを新しいシートにセットする。(**setValues()**) 
3. 各指標の総和を追加

#### テンプレートシートを作成
シート名は 'template'とします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2722903/90a71e1d-e7e5-9bd3-467e-f8f0ff74a1fe.png)

#### Google Apps Scriptを書く
```js
/**
  *テンプレートからスプレッドシートを作成し、引数の値をセットする関数。
  *@param {(number | string)[][]}
*/
function createMonthlySheeet(data) {
  const monthlyTwitterSpreadsheet = SpreadsheetApp.getActiveSpreadsheet()
  const templateSheet = monthlyTwitterSpreadsheet.getSheetByName('template')
  const newSheet = templateSheet.copyTo(monthlyTwitterSpreadsheet)
  const now = new Date()
  const yesterday = new Date(now.setDate(now.getDate() - 1))
  newSheet.setName(Utilities.formatDate(yesterday, 'JST', "YYYY/MM"))

  newSheet.getRange(2, 1, data.length, data[0].length).setValues(data)
  
  //総和を追加
  const lastRow = newSheet.getLastRow()
  newSheet.getRange(2,6,1,3).setFormulas([[`=COUNTA(A2:A${lastRow})`,`=Sum(D2:D${lastRow})`,`=Sum(E2:E${lastRow})`]])
}
```

## まとめ
これらを先ほどのコードに追加し、完成です。
```js:完成コード
function getUserTweetsData() {
  const twitterService = getTwitterService()
  const twitterUserId = PropertiesService.getScriptProperties().getProperty('Twitter_MY_USER_ID')
  const baseUrl = 'https://api.twitter.com'
  const endpointUrl = `/2/users/${twitterUserId}/tweets`
  const queryParam = `?tweet.fields=non_public_metrics,created_at&exclude=retweets`
  let response = JSON.parse(twitterService.fetch(`${baseUrl}${endpointUrl}${queryParam}`))
  if (!response.data) {
    Logger.log('No tweet found')
    return
  }

  let tweetDataArr = response.data
  let nextToken = response.meta.next_token

  while (nextToken) {
    response = JSON.parse(twitterService.fetch(`${baseUrl}${endpointUrl}${queryParam}&pagination_token=${nextToken}`))
    if (!response.data) {
      break
    }
    tweetDataArr.push(...response.data)
    nextToken = response.meta.next_token
  }
  const spreadsheetData = formatTwitterResponse(tweetDataArr)
  createMonthlySheeet(spreadsheetData)
}

/**
  *Twitter APIからのレスポンスを配列にして返す関数。
  *@param {object[]}
  *@return {(number | string)[][]}
  */
function formatTwitterResponse(tweetDataArr) {
  return tweetDataArr.map((tweet) => {
    //url_link_clicks, user_profile_clicksの合計をエンゲージメントとする。
    const engagements = (url_link_clicks, user_profile_clicks) => {
      if (!url_link_clicks) {
        url_link_clicks = 0
      }
      else if (!user_profile_clicks) {
        user_profile_clicks = 0
      }
      return url_link_clicks + user_profile_clicks
    }
    return [tweet.id, tweet.created_at, tweet.text, tweet.non_public_metrics.impression_count, engagements(tweet.non_public_metrics.url_link_clicks, tweet.non_public_metrics.user_profile_clicks)]
  })
}

/**
  *テンプレートからスプレッドシートを作成し、引数の値をセットする関数。
  *@param {(number | string)[][]}
*/
function createMonthlySheeet(data) {
  const monthlyTwitterSpreadsheet = SpreadsheetApp.getActiveSpreadsheet()
  const templateSheet = monthlyTwitterSpreadsheet.getSheetByName('template')
  const newSheet = templateSheet.copyTo(monthlyTwitterSpreadsheet)
  const now = new Date()
  const yesterday = new Date(now.setDate(now.getDate() - 1))
  newSheet.setName(Utilities.formatDate(yesterday, 'JST', "YYYY/MM"))

  newSheet.getRange(2, 1, data.length, data[0].length).setValues(data)
  
  //総和を追加
  const lastRow = newSheet.getLastRow()
  newSheet.getRange(2,6,1,3).setFormulas([[`=COUNTA(A2:A${lastRow})`,`=Sum(D2:D${lastRow})`,`=Sum(E2:E${lastRow})`]])
}
```
これを毎月1日、00:00~にトリガ実行をするように設定すれば、前月のツイート情報の自動取得ができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2722903/9dccb484-ba71-471d-3125-8a79de4badaa.png)

注意点としては31日の月は1日のツイートが取得できないこと、過去一ヶ月のツイートのみが取得対象となるため、それ以前のツイートのデータは月間パフォーマンスに含まれないこと。もしアカウントの全てのツイートの過去1か月のパフォーマンスを集計したい場合は、先述のEngagement APIが必要です。

また、集計は1日時点のデータになるので、指標が月初のツイートに偏重します。（31日のツイートは1日分のデータのみになる。）これはたとえば、クエリパラメータに'start_time', 'end_time'を変数で指定し、30日前のツイートを取得、トリガの実行間隔を1日単位にすることで対処できそうです。

## さいごに
本記事ではインプレッション、エンゲージメントの取得を題材にTwitter APIへの申請からGoogle Apps ScriptでのOAuth1認証、Twitter APIからのデータの取得、データの整形、そしてスプレッドシートへの落とし込みまで一通り行いました。

`non-public metrics`でインプレッション、エンゲージメントが取れることに触れた日本語の記事が乏しく、記事にしました。いつかどなたかの参考になれば幸いです。