【Fitbit API×Make×GAS】Notionへデータを自動集約し、ライフログを可視化する
「毎日アプリを開くのが面倒」を解決!Fitbitで計測した歩数・睡眠・体重を、MakeとGASを使ってNotionへ自動記録する方法をステップバイステップで紹介します。セルフケアを仕組み化し、客観的なデータで自分の体調や気分の波を可視化したい方必見です。
1. はじめに(今回作るもの)
毎日アプリを開いて入力する手間を省き、自分のライフログをNotionに自動集約して、気分の波(躁鬱)との相関を可視化するためのツールです。クレジット登録が必要なサービスもありますが、無料枠で利用するためお金はかかりません。

システム全体のアーキテクチャ
このシステムは、Notion、Fitbit、GAS、OpenWeather、Makeの5つのサービスを連携させています。
- Notionのデータベースに、毎晩20:00にその日のログが1行ずつ追加されます。
- 一度作れば「完全放置」でライフログが蓄積されます。
2. 事前準備(必要なもの)
- Notion:フリープラン(もしうまくいかない場合はアップグレードしてください)
- Fitbit:デバイスとアカウント(データ元)
- Googleアカウント:Google Apps Script(GAS)作成用
- Make (旧Integromat):サービス同士を繋ぐハブ(無料プランでOK)
- Fitbit Developerアカウント:APIキーの取得用
- OpenWeatherアカウント:APIキーの取得用(クレジットカードの登録が必要)
3. 実装手順
全体の流れ
Step1:Notion データベースの構築
ここで作成したデータベースにライフログが蓄積されていきます。Notionテンプレートをこちらで配布しているのでご利用ください。
ログ記録用DB
毎晩20:00にこのDB(データベース)に記録されていきます。
- 名前:日付が入力されます
- 日付:こちらにも日付が入力されます。フィルター用です
- 気分:毎日の気分を0〜10の11段階で入力します。必要に応じて入力してください
- 数値化された気分:気分で入力したものを数値に変換しています。チャート表示をした際に気分を可視化します
- 天気:設定マスタDB [都市名] プロパティの設定に対応した都市の天気が記録されます。
- 最高気温:設定マスタDB [都市名] プロパティの設定に対応した都市の最高気温が記録されます
- 最低気温:設定マスタDB [都市名] プロパティの設定に対応した都市の最低気温が記録されます。
- 湿度:設定マスタDB [都市名] プロパティの設定に対応した都市の湿度が記録されます。
- 歩数:Fitbitに記録された20:00時点での歩数が記録されます
- 消費カロリー:Fitbitに記録された20:00時点での消費カロリーが記録されます
- 睡眠時間:Fitbitに記録された昨日の睡眠時間が記録されます
- 入眠:Fitbitに記録された昨日の入眠時間が記録されます
- 起床::Fitbitに記録された本日の起床時間が記録されます
設定マスタDB
GASやMakeのシナリオ内に機密情報を直接書き込まず、Notion上で一括管理します。
- 都市名: [ Tokyo,JP ] の形で都市名を入力します。OpenWeatherは全世界の気象データをカバーしているため、たいていの場所は取得が可能です。Geminiなどで確認して入力してください
- Notion_API_Key:別ツール(今回はMake)からNotionページの読み取り・書き込みなどを行うために必要です
- DATABASE_ID:DBの設定>リンクをコピーから取得できるURLの一部です。https://www.notion.so/から?vまでの32桁の文字列です
- Weather_API_Key:OpenWeatherのサイトして取得する無料のAPIキーです
自分の住んでいる都市名を検索するためのプロンプト(AIへの指示)
[ ここに住所や都市名を入力 ] を、OpenWeather APIの「City,CountryCode」形式に変換してください。 もし複数の候補(同名の都市など)がある場合は、最も一般的なものを上位に3つほどリストアップしてください
Notion_API_Keyの取得方法

右上の3点リーダーより接続>インテグレーションを開発をクリック。

内部インテグレーション>新しいインテグレーションを作成をクリック。

インテグレーション名を選択し、ワークスペースを選択。

内部インテグレーションシークレットに記載されている文字列をコピーします。

右上の3点リーダーより接続をクリックし、作成したインテグレーションを接続します。
接続したら設定マスタDBのNotion_API_Keyに先ほどコピーした文字列を入力します。
DATABASE_IDの取得方法

右上の3点リーダーよりビューのリンクをコピークリック。
下記のようなURLがコピーされるので、赤文字部分(32文字)をコピーしてDATEBASE_IDに入力します。
https://www.notion.so/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX?v=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&source=copy_link
Weather_API_Keyの取得方法

OpenWeatherにアクセスにアカウントを作成します。
作成が完了したら、右上のアカウント名>My API Keysをクリック。

Keyという項目に入力されている文字列をコピーし、設定マスタDBのWeather_API_Keyに入力します。

One Call API 3.0に登録します。クレジットカードの登録が必要になりますが、無料枠の範囲で済むので利用料金はかかりません。これで先ほどコピーした文字列(APIキー)が機能するようになります。
Step2:GAS (Google Apps Script) の実装

新規>その他>Google App Scritpから新規ファイルを作成します。
作成したファイルに下記のコードを貼り付けます。
function fetchAndRecordWeather(params) {
const { city, weather_key, notion_key, db_id, steps, calories, sleep_hours, sleep_start, sleep_end } = params;
// 1. 緯度・経度の取得
const geoUrl = `https://api.openweathermap.org/geo/1.0/direct?q=${encodeURIComponent(city)}&limit=1&appid=${weather_key}`;
const geoResponse = JSON.parse(UrlFetchApp.fetch(geoUrl).getContentText());
const lat = geoResponse[0].lat;
const lon = geoResponse[0].lon;
// 2. 本日の00:00のタイムスタンプを取得
const now = new Date();
const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate());
const dt = Math.floor(startOfDay.getTime() / 1000);
// 3. Time Machine APIで「今日」のデータを取得
const summaryUrl = `https://api.openweathermap.org/data/3.0/onecall/day_summary?lat=${lat}&lon=${lon}&date=${Utilities.formatDate(startOfDay, "GMT", "yyyy-MM-dd")}&appid=${weather_key}&units=metric&tz=+09:00`;
const summaryResponse = UrlFetchApp.fetch(summaryUrl);
const summaryData = JSON.parse(summaryResponse.getContentText());
const weatherUrl = `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${weather_key}&lang=ja&units=metric`;
const weatherResponse = UrlFetchApp.fetch(weatherUrl);
const weatherData = JSON.parse(weatherResponse.getContentText());
// 4. データの抽出
if (!summaryData || !summaryData.temperature) {
throw new Error("気象サマリーデータが取得できませんでした");
}
const tempMax = summaryData.temperature.max;
const tempMin = summaryData.temperature.min;
let weatherDescription = "不明";
if (weatherData.weather && weatherData.weather.length > 0) {
weatherDescription = weatherData.weather[0].description;
}
const humidity = (summaryData.humidity && summaryData.humidity.afternoon) ? summaryData.humidity.afternoon : 0;
const dateDisplay = Utilities.formatDate(now, "JST", "yyyy/MM/dd");
// 5. Notionペイロード構築
const payload = {
parent: { database_id: db_id },
properties: {
"名前": { title: [{ text: { content: dateDisplay} }] },
"天気": { rich_text: [{ text: { content: weatherDescription } }] },
"日付": { date: { start: now.toISOString() } },
"最高気温": { number: tempMax },
"最低気温": { number: tempMin },
"湿度": { number: humidity },
"街": { rich_text: [{ text: { content: city } }] },
"歩数": { number: Number(steps || 0) },
"消費カロリー": { number: Number(calories || 0) },
"睡眠時間": { number: Number(sleep_hours || 0) },
"入眠": { rich_text: [{ text: { content: sleep_start || "-" } }] },
"起床": { rich_text: [{ text: { content: sleep_end || "-" } }] },
}
};
const options = {
method: 'post',
headers: {
'Authorization': `Bearer ${notion_key}`,
'Content-Type': 'application/json',
'Notion-Version': '2022-06-28'
},
payload: JSON.stringify(payload)
};
UrlFetchApp.fetch('https://api.notion.com/v1/pages', options);
return { status: "success", steps: steps };
}
function doGet(e) {
const params = {
city: e.parameter.city,
weather_key: e.parameter.weather_key,
notion_key: e.parameter.notion_key,
db_id: e.parameter.db_id,
steps: e.parameter.steps ,
calories: e.parameter.calories,
sleep_hours: e.parameter.sleep_hours,
sleep_start: e.parameter.sleep_start,
sleep_end: e.parameter.sleep_end,
};
try {
const result = fetchAndRecordWeather(params);
return ContentService.createTextOutput(JSON.stringify(result)).setMimeType(ContentService.MimeType.JSON);
} catch (error) {
return ContentService.createTextOutput(JSON.stringify({status: "error", message: error.message})).setMimeType(ContentService.MimeType.JSON);
}
}
コードを貼り付けたら、右上のデプロイ>デプロイを管理をクリック。
画像で使われいてるコードは古いものなので、貼り付けるコードを画像のコードが一致しなくても問題ありません。


デプロイメントを作成>種類の選択>ウェブアプリをクリック。

アクセスできるユーザー>全員に変更してデプロイをクリック。


Google has'nt verified this appという画面になったら左下のAdvancedをクリック。Go to XXXXX(プロジェクト名)をクリックして完了画面になったら完了です。
ウェブアプリのURLをコピーしておいてください。Makeの設定で使います。
完了画面になる前にGoogleアカウントの画面が出たら許可してください。
Step3:Make による連携フローの作成
最終的に、以下のモジュールを直線的に配置します。
- Notion - Search Objects
- HTTP - Make a request(Fitbitのアクティビティを取得)
- HTTP - Make a request(Fitbit睡眠ログを取得)
- HTTP - Make a request(GASを叩く)

画像はHTTPモジュールが4つありますが、3つ並んでいれば問題ありません。
Notion - Search Objects

画面の空いているところで右クリック>Add a module

Notionで検索をかけてSearch Objectsを追加します。

Connection>AddでNotionと接続します。
- Connection type:Notion Internal
- Connection name:任意の名前
- Internal Integration Token: [ Notion_API_Key ] に入力した文字列

Data source IDのSearchをクリックし、検索するDB名を入力します。今回は設定マスタDBを接続するので設定などの単語で検索をかけます。XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXの形で入力されればOKです。
HTTP - Make a request

まず、Fitbit Developerアカウントを作成し、Client IDキーとClient Secretキーを取得します。

HTTP>Make a requestを選択してモジュールを作成

Authentication type>OAuth2.0を選択し、Credentials>Addをクリックします。



下記の項目を入力します。
- Connection name:任意の名前(例:Fitbitなど)
- Authorize URI:https://www.fitbit.com/oauth2/authorize
- Token URI:https://api.fitbit.com/oauth2/token
- Scope:activity sleep
- Client ID:Fitbit Developerに記載もの
- Client Secret:Fitbit Developerに記載もの
下記の項目は、左下のAdvanced settingsをオンにすると入力できます。
- Scope separator:COMMA
- Custom Headers - item1 - Key:Authorization
- *Custom Headers - item1 - Value:Basic 生成されたBase64文字列
- Custom Headers - item2 - Key:Content-Type
- Custom Headers - item2 - Value:application/x-www-form-urlencoded
Client ID と Client Secret を使用して、FitbitのBasic認証に必要なBase64文字列を生成してください。
- Client IDとClient Secretをコロンで繋ぐ(Client ID:Client Secret)
- その文字列をBase64エンコードする
- 最終的なBasic [Base64文字列] の形式で出力してください
Base64エンコードはツールを使っても良いですが、AIに特定のフォーマットで依頼するとミスがなくて楽です。
右下のSaveを押し、表示されるFitbitの項目へのアクセスを許可してエラーが出なければ成功です。


Credentialsに、いま作成したFitbitへの認証を設定します。HTTPモジュールを1つ複製し、URLに下記をそれぞれ入力します。
- 1つ目のHTTPモジュール:https://api.fitbit.com/1/user/-/activities/date/{{formatDate(now; "YYYY-MM-DD")}}.json
- 2つ目のHTTPモジュール:https://api.fitbit.com/1.2/user/-/sleep/date/{{formatDate(now; "YYYY-MM-DD")}}.json
最後に作成したHTTPモジュールで右クリック、Run this module onlyを行いエラーが出ないことを絶対に確認してください。
モジュールの設定はエラーが起きやすい箇所なので、うまくいかない場合はGeminiやChatGPTなどのAIを活用してください。
- Notion - Search Objects
- HTTP - Make a request(Fitbitのアクティビティを取得)
- HTTP - Make a request(Fitbit睡眠ログを取得)
- HTTP - Make a request(GASを叩く)
最後のGASとの連携に入ります。
新しくHTTPモジュールを作成し、URLにGASのウェブアプリURLを貼り付けてください。
次にQuery parametersを設定します。Query parameterには、作成した3つのモジュールで取得したNotionとFitbitのデータが入ります。前述のRun this module onlyを行っていないとうまく取得できないので、気をつけてください。
Notionモジュールで取得した値は黒、HTTPモジュールで取得した値は青で表示されます。


全部で9つのパラメータを設定します。下記に則って設定してください。
- city:{{num.properties_value.`都市名`[].plain_text}}
- notion_key:{{num.properties_value.Notion_API_Key[].plain_text}}
- weather_key:{{num.properties_value.Weather_API_Key[].plain_text}}
- db_id:{{num.properties_value.DATABASE_ID[].plain_text}}
- steps:{{num.data.summary.steps}}
- calories:{{num.data.summary.caloriesOut}}
- sleep_hours:{{round(num.data.sleep[].duration / 3600000 * 10) / 10}}
- sleep_start:{{formatDate(num.data.sleep[].startTime; " HH:mm")}}
- sleep_end:{{formatDate(num.data.sleep[].endTime; "HH:mm")}}
作成したGAS用のモジュールでRun this module onlyしてエラーが出なければOKです。

最後に、画面下部のトグルをクリックしてRun sceneario>Every day、Time>20:00に設定したら完了です。これで毎日20:00にNotionへライフログが蓄積されていきます。