Preface
In the Shiro theme, there is a 「Personal Status Display」 feature that can display some customized statuses.
To fully utilize this feature, I wanted to sync the data of the phone's fitness rings and display it in the personal status. The effect is as follows:

Screenshot
Initially, I planned to implement this idea by writing a JavaScript script with the Scriptable app. However, after trying, I found that Scriptable does not support HealthKit, making it impossible to access health data. On Apple devices, apps need to use the HealthKit API to access health data, and Scriptable once tried to integrate HealthKit but was rejected by the App Store. So I had to settle for the next best option and use Apple's built-in Shortcuts to implement this functionality.
Update 2026.3.1: Due to too many limitations of Shortcuts, I have now switched to using my own self-written app + SideStore self-signing to implement automatic pushing.
Setting Up Status Display
By manually setting the personal status display, you can see in the console that the page sends a request via POST to https://{后端服务器}/api/v2/serverless/shiro/status:

Personal Status Display Request
The request body contains JSON in the following format:
{
"emoji": "😴", // 头像右下角的 Emoji
"desc": "消耗0千卡能量 锻炼0分钟 站立0小时", // 展开后的描述
"ttl": 60 // 状态的持续时间,单位为秒
}
To perform the update of the personal status, you need to first obtain an access token and construct the request header Authorization: bearer {token} to verify user permissions.
There are two ways to obtain an access token. The first is to make a login request before each time you set the status, and in the JSON returned by the login request, you can get an access token in the format xxxxx.xxxxxxxx.
The other is to create a new access token in the format xxxxxxxxxxxxxx via the backend Settings -> Security -> API Token, and this method is recommended.
After obtaining the access token, verify it in the console:
const token = "xxxxxxxxx";
fetch("https://server.vinking.top/api/v2/serverless/shiro/status", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: token,
},
body: JSON.stringify({
emoji: "✌️",
desc: "测试",
ttl: 60,
}),
})
.then((response) => {
if (response.ok) {
return response.text().then(() => {
console.log(`用户状态设置成功,状态码: ${response.status}`);
});
}
})
.catch((error) => console.error("用户状态设置错误:", error));
Status set successfully.

Setup Successful
Designing the Shortcut
To automatically sync health data to the personal status display, you need to design a shortcut that can obtain health data, construct the request, and call the API. When converting the flowchart into a shortcut, there are several pitfalls to note:
- If there is no record for a certain type of data on that day (e.g., no exercise), the shortcut will return an empty value instead of 0. You need to set an initial value of 0 in advance to avoid issues when concatenating the description text later.
- If you want the data to match the fitness record panel in Apple Health, pay special attention to the counting method of 「Stand Hours」(Stand Hours). It reflects the number of qualifying hours, not the actual standing duration. The calculation logic is: within each hour, as long as the cumulative standing time reaches or exceeds 1 minute, it counts as 1 qualifying hour. For example, standing at 08:00 - 08:01 and 09:30 - 09:31 will be recorded as 2 qualifying hours. In contrast, the 「Stand Minutes」(Stand Time) obtained by the shortcut is the actual number of minutes stood each time. Therefore, to count 「Stand Hours」, you need to count by counting the number of qualifying hours per hour, not by directly summing the stand minutes. This is expressed in the shortcut as follows:

Counting Qualifying Hours
- When the API successfully sets the status, it only returns a
204status code and no content. Additionally, Shortcuts itself does not support detailed judgment of HTTP status codes directly, so the only way to confirm success is by checking whether the size of the returned file is 0.
Because the shortcut is too long, I've placed it here: Shortcut.
The complete flowchart of the shortcut is as follows (super long image warning):
