Google Health API mengandalkan ekspresi filter untuk membatasi titik data yang ditampilkan saat memanggil metode pengambilan standar. Secara khusus, filter digunakan dengan:
- Endpoint
list: mengkueri titik data mentah. - Endpoint
reconcile: membuat kueri titik data streaming yang direkonsiliasi.
Panduan ini menjelaskan cara penerapan pemfilteran, sintaksis dan konvensi, serta memiliki contoh untuk setiap jenis rekaman.
Konvensi filter
Google Health API menerapkan filter yang mengikuti standar Google API Improvement Proposals (AIP-160).
Parameter kueri
Filter diteruskan menggunakan string kueri URL dalam parameter filter.
Karena filter berisi karakter khusus (seperti <, >=, dan tanda petik),
filter tersebut harus dienkode URL saat dikirim dalam permintaan HTTP.
Misalnya, permintaan dengan filter
steps.interval.civil_start_time >= "2026-03-04T00:00:00"
harus dienkode sebagai:
GET https://health.googleapis.com/v4/users/me/dataTypes/steps/dataPoints ?filter=steps.interval.civil_start_time%20%3E%3D%20%222026-03-04T00%3A00%3A00%22
Format penamaan
Jika jenis data memiliki lebih dari satu kata, format ID berbeda antara jalur resource dan filter:
- Jalur endpoint: gunakan tanda hubung (misalnya,
/dataTypes/body-fat). - String filter: gunakan garis bawah (misalnya,
body_fat).
Jika Anda menggunakan tanda hubung dalam ID filter, API akan menampilkan 400 Bad Request
dengan alasan error INVALID_DATA_POINT_FILTER.
Jenis dan kolom filter
Kolom yang Anda gunakan dalam filter bergantung pada jenis rekaman jenis data yang Anda kueri. Tabel berikut menjelaskan kolom yang didukung untuk setiap jenis catatan:
| Jenis data | Deskripsi | Kolom filter yang didukung |
|---|---|---|
| Interval | Titik data yang dicatat selama jangka waktu tertentu (misalnya, steps, distance, calories). |
{dataType}.interval.start_time{dataType}.interval.civil_start_time
Contoh: steps.interval.civil_start_time
|
| Sampel | Pengamatan instan atau pengukuran singkat (misalnya, weight, body-fat, blood-glucose). |
{dataType}.sample_time.physical_time{dataType}.sample_time.civil_time
Contoh: body_fat.sample_time.physical_time
|
| Setiap hari | Metrik dan ringkasan harian (misalnya, daily-heart-rate-variability). |
{dataType}.date
Contoh: daily_heart_rate_variability.date
|
| Sesi | Sesi pengguna yang diperpanjang dengan aturan pengaturan waktu khusus. |
Latihan: {dataType}.interval.civil_start_timeTidur: sleep.interval.end_time, sleep.interval.civil_end_timeEKG: electrocardiogram.interval.start_time
Contoh: sleep.interval.civil_end_time
|
Operator dan aturan format yang didukung
Ekspresi filter harus mematuhi aturan pemformatan berikut:
Operator perbandingan
Hanya dua operator perbandingan yang didukung:
| Operator | Deskripsi |
|---|---|
>= |
Batas bawah (inklusif). |
< |
Batas atas (eksklusif). |
Menggunakan operator perbandingan lainnya (seperti >, <=, atau =) akan menampilkan 400 Bad Request dengan INVALID_DATA_POINT_FILTER_RESTRICTION_COMPARATOR.
Operator logika
| Operator | Dukungan |
|---|---|
AND |
Operator default dan hanya didukung. Digunakan untuk menggabungkan batas awal dan akhir. |
OR |
Tidak didukung. Penggunaan OR akan menampilkan 400 Bad Request dengan alasan error INVALID_DATA_POINT_FILTER_EXPRESSION_STRUCTURE ("Filter harus berupa gabungan atau urutan pembatasan. Ditemukan: DISJUNCTION"). |
Literal waktu
Literal waktu dalam ekspresi filter harus menggunakan format berikut:
| Jenis waktu | Persyaratan | Contoh |
|---|---|---|
| Waktu fisik | Format RFC 3339, yang diakhiri dengan Z atau offset UTC. Mewakili peristiwa dunia nyata dalam UTC. |
Benar: "2026-03-01T00:00:00Z", "2026-03-01T00:00:00-08:00"Salah: "2026-03-01" |
| Waktu sipil | Format ISO 8601: YYYY-MM-DD[THH:mm:ss]. Mewakili waktu pada jam pengguna, terlepas dari lokasi atau selisih zona waktu. |
Benar: "2026-03-01", "2026-03-01T08:30:00" |
Aturan validasi filter
Filter mengikuti aturan berikut:
| Aturan | Deskripsi | Contoh |
|---|---|---|
| Tidak ada jenis waktu campuran | Jangan mencampur batas waktu fisik dan waktu sipil. | Tidak valid: steps.interval.start_time >= "2026-03-01T00:00:00Z" AND steps.interval.civil_start_time < "2026-03-02"Error: INVALID_DATA_POINT_FILTER_MIXED_TIME_RESTRICTIONS ("Filter tidak boleh berisi rentang waktu fisik dan waktu sipil") |
| Tidak ada jenis data campuran | Gunakan kolom yang termasuk dalam jenis data di jalur permintaan. | Tidak valid: Jalur /users/.../dataTypes/steps/... dengan filter distance.interval.start_time >= "..."Error: INVALID_DATA_POINT_FILTER_COLLECTION_MISMATCH ("Jenis data dalam filter tidak cocok dengan koleksi jenis data induk") |
| Logika urutan waktu | Batas atas harus lebih besar dari batas bawah. | Tidak valid: steps.interval.start_time >= "2026-03-02T00:00:00Z" AND steps.interval.start_time < "2026-03-01T00:00:00Z"Error: INVALID_TIME_RANGE ("Waktu berakhir kueri harus lebih besar daripada waktu mulai") |
| Format kasus | Gunakan snake case yang cocok dengan nama jenis data. | Tidak valid: body-fat.sample_time.physical_time >= "..."Error: INVALID_DATA_POINT_FILTER ("Filter tidak valid") |
API menampilkan HTTP 400 Bad Request untuk filter yang tidak valid. Periksa
error.details[].metadata.detailedReasons untuk mengetahui kode alasan error.
Cakupan OAuth yang diperlukan
Untuk membuat kueri titik data menggunakan filter, pengguna yang diberi otorisasi harus memberikan cakupan OAuth yang relevan untuk jenis data tersebut. Jika cakupan yang diperlukan tidak ada, API akan menampilkan status 403 Forbidden dengan MISSING_OAUTH_SCOPE.
Tabel berikut memetakan cakupan OAuth ke jenis data yang diberikan akses baca
kepadanya. Tabel menampilkan cakupan dalam format relatifnya (misalnya,
.activity_and_fitness.readonly mewakili
https://www.googleapis.com/auth/googlehealth.activity_and_fitness.readonly):
| Cakupan OAuth yang diperlukan | Jenis data |
|---|---|
.activity_and_fitness.readonly |
active-energy-burned, active-minutes, active-zone-minutes, activity-level, altitude, calories-in-heart-rate-zone, daily-vo2-max, distance, exercise, floors, run-vo2-max, sedentary-period, steps, swim-lengths-data, time-in-heart-rate-zone, total-calories, vo2-max |
.ecg.readonly |
elektrokardiogram |
.health_metrics_and_measurements.readonly |
glukosa darah, lemak tubuh, suhu inti tubuh, variabilitas detak jantung harian, zona detak jantung harian, saturasi oksigen harian, laju pernapasan harian, detak jantung istirahat harian, turunan suhu tidur harian, detak jantung, variabilitas detak jantung, tinggi badan, saturasi oksigen, ringkasan tidur laju pernapasan, sensor suhu kulit, berat badan |
.irn.readonly |
notifikasi-irama-tidak-teratur |
.nutrition.readonly |
makanan, satuan-pengukuran-makanan, catatan-hidrasi, catatan-nutrisi |
.sleep.readonly |
sleep |
Jika klien Anda hanya diberi cakupan tulis (seperti
.activity_and_fitness.writeonly) untuk jenis data yang diminta, Anda tetap dapat
mengirimkan kueri titik data yang ditulis oleh klien Anda sendiri. Dalam hal ini, permintaan
secara implisit dibatasi untuk family sumber data self-sources. Untuk mengetahui detail dan batasan jenis data, lihat Memfilter menurut famili sumber data.
Kasus penggunaan dan contoh
Contoh berikut menunjukkan cara membuat filter untuk skenario umum:
Mengkueri langkah-langkah menurut rentang waktu fisik
Langkah kueri yang direkam antara 2026-03-01T00:00:00Z (inklusif)
dan 2026-03-02T00:00:00Z (eksklusif):
GET https://health.googleapis.com/v4/users/me/dataTypes/steps/dataPoints ?filter=steps.interval.start_time >= "2026-03-01T00:00:00Z" AND steps.interval.start_time < "2026-03-02T00:00:00Z"
Mengkueri langkah-langkah menurut rentang waktu sipil
Langkah-langkah kueri untuk sepanjang hari pada 4 Maret 2026, relatif terhadap waktu lokal pengguna:
GET https://health.googleapis.com/v4/users/me/dataTypes/steps/dataPoints ?filter=steps.interval.civil_start_time >= "2026-03-04" AND steps.interval.civil_start_time < "2026-03-05"
Mengueri lemak tubuh berdasarkan waktu pengambilan sampel fisik
Kueri pengukuran lemak tubuh yang direkam mulai Maret 2026 (dalam UTC):
GET https://health.googleapis.com/v4/users/me/dataTypes/body-fat/dataPoints ?filter=body_fat.sample_time.physical_time >= "2026-03-01T00:00:00Z"
Bobot kueri menurut waktu sampel sipil
Log bobot kueri dicatat setelah waktu setempat tertentu:
GET https://health.googleapis.com/v4/users/me/dataTypes/weight/dataPoints ?filter=weight.sample_time.civil_time >= "2026-03-01T08:00:00"
Kueri ringkasan harian variabilitas detak jantung
Kueri ringkasan harian variabilitas detak jantung (HRV) yang direkam sebelum tanggal tertentu:
GET https://health.googleapis.com/v4/users/me/dataTypes/daily-heart-rate-variability/dataPoints ?filter=daily_heart_rate_variability.date < "2026-08-15"
Mengueri sesi latihan menurut waktu mulai sipil
Kueri sesi latihan yang terjadi selama minggu tertentu di zona waktu lokal pengguna:
GET https://health.googleapis.com/v4/users/me/dataTypes/exercise/dataPoints ?filter=exercise.interval.civil_start_time >= "2026-03-01" AND exercise.interval.civil_start_time < "2026-03-08"
Mengkueri sesi tidur menurut waktu berakhir kalender
Kueri catatan tidur berdasarkan waktu berakhir sesi:
GET https://health.googleapis.com/v4/users/me/dataTypes/sleep/dataPoints ?filter=sleep.interval.civil_end_time >= "2026-03-04T05:00:00" AND sleep.interval.civil_end_time < "2026-03-04T12:00:00"
Membuat kueri elektrokardiogram menurut waktu mulai
Membuat kueri rekaman EKG yang dimulai dari titik waktu UTC fisik. Perhatikan bahwa
kueri EKG hanya mendukung perbandingan >= pada start_time:
GET https://health.googleapis.com/v4/users/me/dataTypes/electrocardiogram/dataPoints ?filter=electrocardiogram.interval.start_time >= "2026-03-10T12:00:00Z"
Memfilter menurut grup sumber data
Grup sumber data adalah pengelompokan logis sumber data (seperti smartwatch, aplikasi seluler, atau entri manual). Hal ini memungkinkan Anda mengisolasi atau menggabungkan data dari jenis sumber tertentu (misalnya, perangkat wearable fisik, entri manual, atau data yang ditulis oleh klien Anda sendiri).
Semua endpoint list, reconcile, rollUp, dan dailyRollUp mendukung parameter dataSourceFamily. Mekanisme penerusan bergantung pada endpoint:
| Endpoint (metode HTTP) | Mekanisme |
|---|---|
list (GET) |
Teruskan dataSourceFamily sebagai parameter kueri URL. |
reconcile (GET) |
Teruskan dataSourceFamily sebagai parameter kueri URL. |
rollUp (POST) |
Teruskan dataSourceFamily sebagai kolom di isi permintaan JSON. |
dailyRollUp (POST) |
Teruskan dataSourceFamily sebagai kolom di isi permintaan JSON. |
Grup sumber data yang didukung
Tabel berikut menjelaskan nilai dataSourceFamily yang didukung:
| Opsi | Deskripsi |
|---|---|
users/me/dataSourceFamilies/all-sources |
Nilai default (saat diberi cakupan baca). Mencakup titik data dari semua sumber data pihak pertama (1P) dan pihak ketiga (3P) yang tersedia. Data aplikasi pihak ketiga ditampilkan dengan opsi ini (seperti langkah smartwatch + langkah aplikasi pihak ketiga + langkah ponsel + langkah manual). |
users/me/dataSourceFamilies/google-wearables |
Mencakup data yang direkam oleh perangkat pelacak Google dan Fitbit (seperti pelacak wearable Fitbit dan Pixel Watch). Mengecualikan data yang dicatat secara manual dan data yang diperkirakan oleh ponsel. Gunakan opsi ini saat integrasi Anda memerlukan telemetri sensor mentah yang direkam langsung oleh hardware perangkat wearable. |
users/me/dataSourceFamilies/google-sources |
Mencakup sumber pihak pertama Google dan Fitbit. Data ini mencakup catatan perangkat pelacak fisik, data dari Health Connect, dan entri manual yang dicatat melalui aplikasi pihak pertama (seperti aplikasi Fitbit atau Google Fit). |
users/me/dataSourceFamilies/self-sources |
Hanya menyertakan data yang ditulis oleh klien panggilan melalui Google Health API (titik data yang sumber datanya didaftarkan melalui API dengan ID klien OAuth yang sama dengan pemanggil). |
Jika tidak ada titik data yang cocok dengan family sumber data yang diminta, responsnya adalah daftar kosong, bukan error.
Cakupan hanya tulis dan sumber mandiri
Pemanggil yang hanya diberi cakupan tulis (seperti
.activity_and_fitness.writeonly) untuk jenis data yang diminta dapat membaca
data yang mereka tulis sendiri, dan hanya data tersebut.
- Permintaan tanpa parameter
dataSourceFamilyeksplisit, atau dengandataSourceFamilyyang ditetapkan keusers/me/dataSourceFamilies/self-sources, akan dibatasi secara implisit keself-sources. - Meminta kelompok sumber data lainnya (seperti
all-sources,google-wearables, ataugoogle-sources) hanya dengan cakupan tulis akan gagal dengan error403 Forbidden(PERMISSION_DENIED).
Batasan jenis data pada endpoint daftar
Di endpoint list (users.dataTypes.dataPoints.list), pemfilteran menurut
dataSourceFamily tidak didukung untuk jenis data sleep, food, dan
food-measurement-unit:
- Menetapkan
dataSourceFamilysecara eksplisit padalistuntuksleep,food, ataufood-measurement-unitakan gagal dengan error400 Bad Request(INVALID_ARGUMENT). - Memanggil
listuntuk jenis data ini saat hanya diberi cakupan tulis (dengan pembatasan keself-sourcestersirat oleh cakupan pemanggil) akan gagal dengan error403 Forbidden(PERMISSION_DENIED). - Untuk memfilter titik data
sleepmenurutdataSourceFamily, gunakan endpointreconcile.
Contoh grup sumber data
Untuk mencantumkan titik data mentah yang ditulis klien Anda sendiri untuk pengguna, panggil endpoint list dengan parameter kueri dataSourceFamily yang ditetapkan ke users/me/dataSourceFamilies/self-sources.
Misalnya, permintaan GET berikut mencantumkan pengukuran body-fat mentah yang ditulis oleh klien yang memanggil, dimulai pada 01-03-2026:
Permintaan
GET https://health.googleapis.com/v4/users/me/dataTypes/body-fat/dataPoints ?dataSourceFamily=users/me/dataSourceFamilies/self-sources &filter=body_fat.sample_time.physical_time >= "2026-03-01T00:00:00Z" Authorization: Bearer access-token Accept: application/json
Respons
{
"dataPoints": [
{
"name": "users/123456789/dataTypes/body-fat/dataPoints/1234567890",
"dataSource": {
"recordingMethod": "UNKNOWN",
"application": {
"packageName": "",
"webClientId": "",
"googleWebClientId": "google-web-client-id"
},
"platform": "GOOGLE_WEB_API"
},
"bodyFat": {
"sampleTime": {
"physicalTime": "2026-03-10T10:00:00Z",
"utcOffset": "0s",
"civilTime": {
"date": {
"year": 2026,
"month": 3,
"day": 10
},
"time": {
"hours": 10
}
}
},
"percentage": 20
}
}
],
"nextPageToken": ""
}Untuk mendapatkan aliran data yang disesuaikan dari family sumber data tertentu, panggil endpoint
reconcile dengan parameter kueri dataSourceFamily.
Misalnya, permintaan GET berikut mengambil data tidur yang direkam oleh pelacak untuk hari setelah 03-03-2026:
Permintaan
GET https://health.googleapis.com/v4/users/me/dataTypes/sleep/dataPoints:reconcile ?dataSourceFamily=users/me/dataSourceFamilies/google-wearables &filter=sleep.interval.civil_end_time >= "2026-03-03" Authorization: Bearer access-token Accept: application/json
Respons
{
"dataPoints": [
{
"name": "users/2515055256096816351/dataTypes/sleep/dataPoints/2724123844716220216",
"dataSource": {
"recordingMethod": "DERIVED",
"device": {
"displayName": "Charge 6"
},
"platform": "FITBIT"
},
"sleep": {
"interval": {
"startTime": "2026-03-03T20:57:30Z",
"startUtcOffset": "0s",
"endTime": "2026-03-04T04:41:30Z",
"endUtcOffset": "0s"
},
"type": "STAGES",
"stages": [
{
"startTime": "2026-03-03T20:57:30Z",
"startUtcOffset": "0s",
"endTime": "2026-03-03T20:59:30Z",
"endUtcOffset": "0s",
"type": "AWAKE",
"createTime": "2026-03-04T04:43:40.937183Z",
"updateTime": "2026-03-04T04:43:40.937183Z"
},
{
"startTime": "2026-03-04T04:07:30Z",
"startUtcOffset": "0s",
"endTime": "2026-03-04T04:41:30Z",
"endUtcOffset": "0s",
"type": "AWAKE",
"createTime": "2026-03-04T04:43:40.937183Z",
"updateTime": "2026-03-04T04:43:40.937183Z"
}
],
"metadata": {
"stagesStatus": "SUCCEEDED",
"processed": true,
"main": true
},
"summary": {
"minutesInSleepPeriod": "464",
"minutesAfterWakeUp": "0",
"minutesToFallAsleep": "0",
"minutesAsleep": "407",
"minutesAwake": "57",
"stagesSummary": [
{
"type": "AWAKE",
"minutes": "56",
"count": "12"
},
{
"type": "LIGHT",
"minutes": "198",
"count": "19"
},
{
"type": "DEEP",
"minutes": "114",
"count": "10"
},
{
"type": "REM",
"minutes": "94",
"count": "4"
}
]
},
"createTime": "2026-03-04T04:43:40.337983Z",
"updateTime": "2026-03-04T04:43:40.937183Z"
}
}
],
"nextPageToken": ""
}Untuk menggabungkan titik data selama ukuran periode tertentu yang dibatasi untuk keluarga sumber data tertentu, panggil endpoint rollUp dan teruskan kolom dataSourceFamily dalam isi permintaan JSON.
Permintaan POST berikut mengkueri jumlah langkah kaki intrahari dalam interval per jam (3600s), yang dikumpulkan secara eksklusif dari perangkat wearable:
Permintaan
POST https://health.googleapis.com/v4/users/me/dataTypes/steps/dataPoints:rollUp
Authorization: Bearer access-token
Accept: application/json
{
"range": {
"startTime": "2026-07-29T00:00:00Z",
"endTime": "2026-07-29T23:59:59Z"
},
"windowSize": "3600s",
"dataSourceFamily": "users/me/dataSourceFamilies/google-wearables"
}Respons
{
"rollupDataPoints": [
{
"startTime": "2026-07-29T08:00:00Z",
"endTime": "2026-07-29T09:00:00Z",
"steps": {
"countSum": "1200"
}
},
{
"startTime": "2026-07-29T09:00:00Z",
"endTime": "2026-07-29T10:00:00Z",
"steps": {
"countSum": "3450"
}
}
]
}Untuk menggabungkan titik data harian untuk keluarga sumber tertentu, panggil endpoint
dailyRollUp dan teruskan kolom dataSourceFamily di isi
permintaan.
Misalnya, permintaan berikut menghitung ringkasan harian untuk langkah-langkah pengguna, termasuk semua sumber Google dan Fitbit pihak pertama (perangkat wearable + entri manual):
Permintaan
POST https://health.googleapis.com/v4/users/me/dataTypes/steps/dataPoints:dailyRollUp
Authorization: Bearer access-token
Accept: application/json
{
"range": {
"start": {
"date": {
"year": 2026,
"month": 7,
"day": 28
},
"time": {
"hours": 0,
"minutes": 0,
"seconds": 0,
"nanos": 0
}
},
"end": {
"date": {
"year": 2026,
"month": 7,
"day": 30
},
"time": {
"hours": 0,
"minutes": 0,
"seconds": 0,
"nanos": 0
}
}
},
"windowSizeDays": 1,
"dataSourceFamily": "users/me/dataSourceFamilies/google-sources"
}Tanggapan
{
"rollupDataPoints": [
{
"civilStartTime": {
"date": {
"year": 2026,
"month": 7,
"day": 28
},
"time": {}
},
"civilEndTime": {
"date": {
"year": 2026,
"month": 7,
"day": 28
},
"time": {
"hours": 23,
"minutes": 59,
"seconds": 59
}
},
"steps": {
"countSum": "8430"
}
},
{
"civilStartTime": {
"date": {
"year": 2026,
"month": 7,
"day": 29
},
"time": {}
},
"civilEndTime": {
"date": {
"year": 2026,
"month": 7,
"day": 29
},
"time": {
"hours": 23,
"minutes": 59,
"seconds": 59
}
},
"steps": {
"countSum": "11245"
}
}
]
}