自动化:按计划推送你的数据
Marrow 可以按你选择的频率,直接从手机把一份健康数据文件 POST 到你指定的任意 URL。本页是参考手册:如何设置一个自动化、每种负载长什么样,以及如何写出接收它的程序。
n8n、Zapier、Make、Home Assistant、Google Sheets 和 InfluxDB 的现成配置见连接页面.
所有 Marrow 指南: MCP · 自托管镜像 · 自动化 · 文件 · 支持
什么是自动化
保存在导出,自动中的一项任务:一种数据、一种格式、一个日期范围、一个 URL、一个频率。Marrow 用经过校验的存储生成文件,并在应用关闭的状态下 POST 到该 URL:每次同步提交之后,以及每次后台刷新时,只要频率设定的间隔已到。任何数据都不经过我们:手机直接与你的端点通信。
如何设置
- “导出”标签页,自动:先开启,再点按新建自动化。如果是从某个工具的页面创建(n8n、Zapier、Home Assistant 等,见连接),这个自动化会带上该工具的名称,并在每个字段旁边说明该工具要在那里填什么。
- 地址:它要 POST 到的 https URL。标题(请求头):接收端需要的任何内容(
Authorization承载令牌、X-Gitlab-Token等都行)。如果工具不需要,“添加标题”在“更多选项”里。 - 数据:健康指标、训练、力量日志、饮食日记,或症状与心情,格式为 JSON 或 CSV。一个自动化只传一种数据,所以想要几种就建几个。每个开启的自动化都算一个连接:免费版同时只能开启 1 个连接,Marrow Pro 最多 10 个,其中包括 AI 和服务器。
- 频率:每隔若干分钟、小时或天。日期范围、汇总方式和超时时间在更多选项里.
- 立即运行会发送第一份负载,这样你不用等到计划时间就能检查接收端。
日期范围
- 距离上次跑步(默认):自上一次成功运行以来的全部数据,再往前多取两天作为重叠。HealthKit 在一天结束后还会继续补充数据,所以重叠部分会重新发送刚结束的几天。你这边对每项指标每天只保留最新的值,重复就无害。接收端宕机一段时间后,第一次成功的运行会补上所有漏掉的日子。
- 今天、近 7 / 30 / 90 天、去年:固定的滚动窗口,每次运行都完整重发。如果你想要能自我修复的快照,而不是增量,就选这些。
负载格式
健康指标(每日总计,JSON)
结构与 Health Auto Export 的指标相同(一个 metrics 列表,包含 name、units 和带 qty 的 data),所以为那款应用写的接收端只需小改:这里的日期是普通的日期,不是时间戳,而下面的训练和力量负载是 Marrow 自己的格式。数值使用 units 中注明的存储单位(kg、m、mL、degC、kcal、count)。心率给出每天的 Avg、Min 和 Max,单位为 bpm,睡眠则按每晚给出各个阶段,单位为小时。如果你想要英制单位,请在你那边自行换算。
{"data": {"metrics": [
{"name": "body_mass", "units": "kg",
"data": [{"date": "2026-09-11", "qty": 81.3}]},
{"name": "step_count", "units": "count",
"data": [{"date": "2026-09-11", "qty": 8746}]},
{"name": "heart_rate", "units": "bpm",
"data": [{"date": "2026-09-11", "Avg": 71, "Min": 52, "Max": 148}]},
{"name": "sleep_analysis", "units": "h",
"data": [{"date": "2026-09-11", "totalSleep": 7.2, "asleep": 7.2, "deep": 1.1, "rem": 1.6, "core": 4.3, "awake": 0.2,
"sleepStart": "2026-09-10 23:36:00 -0400", "sleepEnd": "2026-09-11 07:02:00 -0400"}]}
]}}
原始样本(即原始样本分组)会发送每一条样本及其开始和结束时间,而不是每日总计。CSV 格式的指标是一张宽表,详见文件页面.
训练
{"data": {"workouts": [
{"activity": "Running", "start": "2026-09-11T18:43:41Z", "end": "2026-09-11T19:13:53Z",
"duration_min": 30.2, "kcal": 512, "distance_mi": 3.06, "avg_hr": 174, "source": "Apple Watch"}
]}}
力量日志
每一个正式组(不含热身组),外加每个动作的进步情况和每个肌群的训练量。重量使用你在设置,单位中选的单位,unit 字段会说明是哪种。每组的 set_type 是 work、failure 或 drop,如果你记录了保留次数,该组还会带有 rir。set_credits 统计计入某个肌群的组数,当一个动作训练多个肌群时,会以小数计。
{"data": {"unit": "lb",
"sets": [{"time": "2026-09-11T17:02:00Z", "session": "Push day", "exercise": "Bench Press",
"set": 1, "weight": 185, "reps": 8, "est_1rm": 229.6, "set_type": "work"}],
"exercises": [{"exercise": "Bench Press", "best_est_1rm": 229.6,
"sessions": [{"date": "2026-09-11T17:02:00Z", "sets": 3, "top_weight": 185, "top_reps": 8, "est_1rm": 229.6, "volume": 3885}]}],
"muscle_groups": [{"group": "Chest", "volume": 3108.0, "set_credits": 2.4}]
}}
饮食日记
{"data": {"days": [
{"day": "2026-09-11", "entries": [
{"meal": "breakfast", "name": "Oatmeal", "grams": 250, "kcal": 300,
"protein_g": 10, "carbs_g": 54, "fat_g": 5, "logged_at": "2026-09-11T12:10:00Z",
"nutrients": {"dietary_fiber": 8.0, "dietary_sugar": 1.2}}
]}
]}}
编写接收端
任何接受 HTTPS POST 并返回 2xx 的东西都行:webhook 服务、无服务器函数,或家用服务器上的脚本。遵守三条规则,就能让它稳健可靠:
- 以最新为准。按(指标,日期)或条目自身的标识为键保存数值,重复时直接覆盖。时间窗口本来就是有意重叠的。
- 先存档原始内容。然后再解析。解析器出错绝不该让你丢数据。
- 尽快响应。Marrow 最多等到你设置的超时时间(默认 60 秒),超时就把这次运行标记为失败。失败的运行会在下一个频率节点从上一个成功的时间窗口起重试。
一个十二行的 Python 接收端,会把每次 POST 存档:
from http.server import BaseHTTPRequestHandler, HTTPServer
import time
class H(BaseHTTPRequestHandler):
def do_POST(self):
body = self.rfile.read(int(self.headers.get("Content-Length", 0)))
with open(f"marrow-{int(time.time())}.json", "wb") as f:
f.write(body)
self.send_response(200)
self.end_headers()
HTTPServer(("0.0.0.0", 8798), H).serve_forever()
把它放到 HTTPS 后面(Cloudflare Tunnel、Tailscale Funnel 或任意反向代理),再让自动化指向它。如果你想要的是可查询的副本,而不是一个文件夹,自托管镜像就是已经写好的这种接收端。
值得了解
- 自动化只在 iOS 允许应用运行时才会运行:同步提交之后、前台刷新时,以及后台刷新期间。整天锁屏的手机会在下次解锁时发送。“距离上次跑步”的时间窗口会补上这段空档。
- 每次运行及其结果都会记录在该自动化的活动记录里(更多选项),所以 URL 配错了,在应用里就能看到,不只是在你的服务器上。
- 复制一个自动化,就能把它的标题(请求头)用到另一种数据上。
问题排查
用立即运行来测试。它下面那一行会说明发生了什么,更多选项,活动记录里则保留最近 30 次运行,每次都有同样的一行。检查期间,可以开启运行时通知(更多选项),让每次运行都通知你。
| Marrow 的显示 | 怎么办 |
|---|---|
已发送内容的摘要,比如 12 diary entries | 已送达:接收端返回了 2xx。如果它那边什么都没显示,请看下面最后几行。 |
Server answered 401 或 403 | 接收端需要一个标题(请求头),或者你添加的那个不对。检查它的名称和值,包括 Bearer 和它后面的空格。 |
Server answered 404 | 地址不对,或者接收端没有在监听。在 n8n 中,请使用 Production URL 并激活工作流。检查末尾是否漏了路径。 |
Server answered 405 | 这个地址不接受 POST。请指向专门用来接收数据的端点。 |
Server answered 413 | 负载对接收端来说太大了。请选更短的日期范围、更少的指标,或者用每日总计代替原始样本。 |
Server answered 500 或其他 5xx | 接收端在处理时出错了。去看它自己的日志。先存档原始内容,再解析。 |
| 请求超时(The request timed out) | 接收端用的时间超过了超时设置。先响应、后处理,或者在“更多选项”里调高超时(最多 300 秒)。 |
| 由于 App Transport Security 策略要求使用安全连接,所以无法加载资源(The App Transport Security policy requires the use of a secure connection) | 这个地址是互联网上的普通 http。请改用 https。iOS 只允许 Marrow 在你自己的网络中使用普通 http。 |
| 未能找到使用指定主机名的服务器(A server with the specified hostname could not be found) | 地址有拼写错误,或者是只有你家庭网络才认识的名称。请在手机的 Safari 里检查一下。 |
No valid URL - set an https endpoint first | 地址是空的,或者不是以 https:// 开头(在你自己的网络中也可以是 http://)。 |
Nothing to export in this range | 该日期范围内没有这种数据。请在“更多选项”里选更长的范围,或者先记录一些内容。 |
- 显示已送达,却什么都没收到。有些接收端即使丢掉了数据也会返回 200。Home Assistant 在 webhook id 错误时就是这样,Apps Script 配方在
?key=错误时也是这样。Zapier 和 Make 要等你在它们的编辑器里加载一个样本之后才会显示内容。请查看接收端自己的历史记录或日志。 - 运行延迟或根本不运行。后台运行的时机由 iOS 决定:同步之后、你打开 Marrow 时,以及后台刷新期间。请为 Marrow 保持开启“后台 App 刷新”(设置,通用,后台 App 刷新)。低电量模式会阻止后台运行,整天锁屏的手机会在下次解锁时发送。“距离上次跑步”会在下一次成功的运行中补上。
- 接收端在你的家庭网络里。Marrow 需要“本地网络”访问权限才能连上它:设置,隐私与安全性,本地网络。在 Marrow 打开的状态下点按一次“立即运行”,这样 iOS 才能询问你。在后台时,你回答之前 iOS 会不经询问直接拒绝。
- 被划掉了。你在应用切换器里把 Marrow 划掉之后,iOS 可能不会在后台唤醒它,直到你再次打开。
- 同样的日期收到了两次。这是有意的:“距离上次跑步”会重发最近两天,因为 Apple Health 会持续补充这些天的数据。请对每项指标每天只保留最新的值。
- 开不起来。每个开启的自动化都算一个连接。免费版同时只能开启 1 个连接,Marrow Pro 最多 10 个,AI、服务器和自动化合计。请先关掉另一个。
- 单位看起来不对。指标以
units中注明的存储单位送达(kg、m、mL、degC、kcal)。力量训练的组遵循“设置,单位”,unit字段会说明是哪种。
各个工具的解决办法见它们自己的页面:n8n、Zapier、Make、Home Assistant、Google Sheets、InfluxDB、任意 URL.