<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Yukihiro Kimura</title>
    <description>The latest articles on DEV Community by Yukihiro Kimura (@yukihirokimura).</description>
    <link>https://dev.to/yukihirokimura</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3649123%2F5bf83919-48c7-4116-a58f-879a654be1e6.png</url>
      <title>DEV Community: Yukihiro Kimura</title>
      <link>https://dev.to/yukihirokimura</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yukihirokimura"/>
    <language>en</language>
    <item>
      <title>I automated my weight logging into Notion, and gave myself a new daily chore</title>
      <dc:creator>Yukihiro Kimura</dc:creator>
      <pubDate>Fri, 31 Jul 2026 21:28:27 +0000</pubDate>
      <link>https://dev.to/yukihirokimura/i-automated-my-weight-logging-into-notion-and-gave-myself-a-new-daily-chore-2coa</link>
      <guid>https://dev.to/yukihirokimura/i-automated-my-weight-logging-into-notion-and-gave-myself-a-new-daily-chore-2coa</guid>
      <description>&lt;h2&gt;
  
  
  What I wanted
&lt;/h2&gt;

&lt;p&gt;I'm building a system where all my daily records live in Notion, so I can point an AI at it and get feedback. Goals, tasks, daily logs, finances — those are all manual entry, and that's fine. But one day it hit me that &lt;strong&gt;weight&lt;/strong&gt; would be nice to sync automatically.&lt;/p&gt;

&lt;p&gt;The requirements were simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every morning, my weight and body fat percentage get appended to a Notion database as one row&lt;/li&gt;
&lt;li&gt;No manual typing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's it. My scale is a Withings Body Smart.&lt;/p&gt;

&lt;h2&gt;
  
  
  The design I picked first
&lt;/h2&gt;

&lt;p&gt;This one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Scale → vendor app → Apple Health → iOS Shortcut → Notion API
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I chose Apple Health as the hub for these reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It doesn't depend on the scale model.&lt;/strong&gt; As long as the data lands in Health, the same implementation works for any vendor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No server required.&lt;/strong&gt; A time-based Shortcuts automation handles it end to end — no always-on machine, no cron.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free.&lt;/strong&gt; No extra subscription.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extensible later.&lt;/strong&gt; Anything that's already in Health — steps, sleep, heart rate — could be added the same way (if I ever wanted to).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Generic, zero cost, extensible. The design looked sound to me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;Here's what the Shortcut looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Find Health Samples          [Weight] latest, limit 1
2. Get Details of Health Sample [Value]      → variable Kg
3. Get Details of Health Sample [Start Date] → variable SampleDate
4. Format Date                  yyyy-MM-dd   → variable Ymd
5. If Ymd == today
6.   Text                       ← build the JSON
7.   Get Contents of URL        ← POST to the Notion API
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 5 matters. Without it, on a day you don't step on the scale, &lt;strong&gt;yesterday's weight gets appended under today's date&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here's the JSON built in step 6:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"parent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"database_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@@YMD@@"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Measured"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@@YMD@@"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Weight kg"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"number"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@@KG@@&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Body fat %"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"number"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@@FAT@@&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(My real database uses Japanese property names. What matters is that they match your database exactly.)&lt;/p&gt;

&lt;p&gt;I write this as a plain string in a Text action and hand it to the POST action.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up the Notion side
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Use an access token, not OAuth
&lt;/h3&gt;

&lt;p&gt;Notion offers two auth methods for a connection: an internal access token, and OAuth. &lt;strong&gt;OAuth is meant for apps that get installed into other people's workspaces, or listed on the Marketplace&lt;/strong&gt; — so for this I went with the access token.&lt;/p&gt;

&lt;h3&gt;
  
  
  I attached the connection at the parent page
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Notion permissions are inherited by child pages.&lt;/strong&gt; If you connect an integration at a parent page, everything underneath it becomes reachable.&lt;/p&gt;

&lt;p&gt;In my case I may want to auto-sync things other than weight later, so I granted access at the parent page that holds my personal data.&lt;/p&gt;

&lt;p&gt;Note: if you're doing this at work, you'd want to scope it down to the minimum necessary permissions.&lt;/p&gt;

&lt;h2&gt;
  
  
  I hit a 400 twice
&lt;/h2&gt;

&lt;h3&gt;
  
  
  First: it says there's no &lt;code&gt;parent&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"validation_error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Provide a `parent.page_id` or `parent.database_id` parameter to create a page,
              or use a public integration with `insert_content` capability.
              Internal integrations aren't owned by a single user, so creating
              workspace-level private pages is not supported."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My JSON &lt;em&gt;has&lt;/em&gt; a &lt;code&gt;parent&lt;/code&gt;. And I still got this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The cause was that I never wired the JSON into the request body.&lt;/strong&gt; When I set up the POST action in Shortcuts, I hadn't configured it to actually take the JSON — so I was POSTing an empty body. Yeah.&lt;/p&gt;

&lt;h3&gt;
  
  
  Second: &lt;code&gt;invalid_json&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"invalid_json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Error parsing JSON body."&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Weight was appending fine, so I went to add body fat percentage. When I added the property, I forgot the trailing comma on the previous line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;"Weight kg"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"number"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;67.878&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="err"&gt;←&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;no&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;comma&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Body fat %"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"number"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;16.058&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Shortcuts has no syntax highlighting and no linter&lt;/strong&gt;, so I walked right past it.&lt;/p&gt;

&lt;h3&gt;
  
  
  The only debugging tool you get
&lt;/h3&gt;

&lt;p&gt;Drop a &lt;strong&gt;Quick Look&lt;/strong&gt; action immediately after the Text action. It shows you the expanded JSON exactly as it will be sent, so you can confirm the variables actually resolved to values.&lt;/p&gt;

&lt;p&gt;In Shortcuts development this is effectively your only debugging tool. When you're stuck, look at the payload.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rounding the numbers
&lt;/h2&gt;

&lt;p&gt;The weight coming out of Health was something like &lt;code&gt;67.87800598144531&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I first tried to round it inside Shortcuts, but &lt;strong&gt;somehow I could not get it to work&lt;/strong&gt;, so I rounded on the Notion side instead.&lt;/p&gt;

&lt;p&gt;Add one formula column to the weight database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Weight kg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then hide the raw column in the view and show only the rounded one. Much easier to read.&lt;/p&gt;

&lt;p&gt;As a side effect this turned out to be the better design anyway: the raw value stays in the database, and rounding is a display concern.&lt;/p&gt;

&lt;h2&gt;
  
  
  It works. And then I noticed something
&lt;/h2&gt;

&lt;p&gt;It ran. Rows appeared in Notion.&lt;/p&gt;

&lt;p&gt;But there was one problem left.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Apple Health doesn't get the data unless I open the Withings app.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Stepping on the scale every morning isn't enough. If I want a row every day, I have to open the Withings app every day. Background App Refresh is on, and even then there's no guarantee it syncs daily.&lt;/p&gt;

&lt;p&gt;So the actual workflow is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Step on the scale&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open the Withings app&lt;/strong&gt; ← New!&lt;/li&gt;
&lt;li&gt;The Shortcut runs (I changed the trigger to "when the Withings app is closed"...)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The appending is automated now, but a daily manual step survived. What I actually wanted was for stepping on the scale to be the whole interaction.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I got wrong
&lt;/h2&gt;

&lt;p&gt;Apple Health is a bucket that &lt;strong&gt;gets written to when a connected app launches&lt;/strong&gt; — it isn't necessarily something that goes and fetches data on its own. I thought I was picking a hub. What I actually put in the middle of the path was a bucket waiting for the Withings app to open.&lt;/p&gt;

&lt;p&gt;Meanwhile, Withings has a public API. The scale is on Wi-Fi and presumably pushes measurements straight to the cloud, so a path like this might work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Scale --Wi-Fi--&amp;gt; Withings cloud --webhook--&amp;gt; my own endpoint --&amp;gt; Notion
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;A row appears in Notion the moment I step on the scale. There's no app to open.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I picked Health because I wanted the design to be generic — but &lt;strong&gt;the scale I actually own is one of the models that can skip that generic layer and be called directly&lt;/strong&gt;. By choosing "a design that works with any scale," I missed the better path that only my scale had.&lt;/p&gt;

&lt;h2&gt;
  
  
  The lesson
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;When you design an automation path, check up front whether each hop can push data forward on its own.&lt;/strong&gt; If even one hop is pull-based — it only moves data when something comes asking — that's where a human eventually ends up doing the work.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published in Japanese on Zenn: &lt;a href="https://zenn.dev/yukihirokimuraj/articles/afe22b0e3ffd97" rel="noopener noreferrer"&gt;体重を自動でNotionに記録したかったが、毎朝アプリを開く仕事が残った&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>automation</category>
      <category>ios</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
