Cómo filtrar datos

La API de Google Health se basa en expresiones de filtro para restringir los puntos de datos que se muestran cuando se llaman a métodos de recuperación estándar. Específicamente, los filtros se usan con lo siguiente:

En esta guía, se explica cómo se implementa el filtrado, la sintaxis y las convenciones, y se incluyen ejemplos para cada tipo de registro.

Convenciones de filtros

La API de Google Health implementa filtros según el estándar de las Propuestas de mejora de las APIs de Google (AIP-160).

Parámetros de consulta

Los filtros se pasan a través de la cadena de consulta de la URL en el parámetro filter. Dado que los filtros contienen caracteres especiales (como <, >= y comillas), deben codificarse como URL cuando se transmiten en la solicitud HTTP.

Por ejemplo, una solicitud con el filtro steps.interval.civil_start_time >= "2026-03-04T00:00:00" se debe codificar de la siguiente manera:

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

Formato de nomenclatura

Si un tipo de datos tiene más de una palabra, el formato del identificador difiere entre la ruta del recurso y el filtro:

  • Ruta de acceso del extremo: Usa guiones (por ejemplo, /dataTypes/body-fat).
  • Cadena de filtro: Usa guiones bajos (por ejemplo, body_fat).

Si usas guiones en el identificador del filtro, la API devuelve un 400 Bad Request con el motivo del error INVALID_DATA_POINT_FILTER.

Tipos y campos de filtros

Los campos que usas en un filtro dependen del tipo de registro del tipo de datos sobre el que realizas la consulta. En la siguiente tabla, se describen los campos admitidos para cada tipo de registro:

Tipo de registro Descripción Campos de filtro admitidos
Interval Son los puntos de datos registrados durante un período (por ejemplo, steps, distance, calories). {dataType}.interval.start_time
{dataType}.interval.civil_start_time

Ejemplo:
steps.interval.civil_start_time
Muestra Observaciones instantáneas o mediciones breves (por ejemplo, weight, body-fat, blood-glucose) {dataType}.sample_time.physical_time
{dataType}.sample_time.civil_time

Ejemplo:
body_fat.sample_time.physical_time
A diario Métricas y resúmenes diarios (por ejemplo, daily-heart-rate-variability) {dataType}.date

Ejemplo:
daily_heart_rate_variability.date
Sesión Sesiones de usuario extendidas con reglas de sincronización especializadas Ejercicio: {dataType}.interval.civil_start_time
Sueño: sleep.interval.end_time, sleep.interval.civil_end_time
ECG: electrocardiogram.interval.start_time

Ejemplo:
sleep.interval.civil_end_time

Operadores y reglas de formato admitidos

Las expresiones de filtro deben cumplir con las siguientes reglas de formato:

Operadores de comparación

Solo se admiten dos operadores de comparación:

Operador Descripción
>= Límite inferior (inclusive).
< Límite superior (exclusivo).

Si se usan otros operadores de comparación (como >, <= o =), se devuelve un 400 Bad Request con INVALID_DATA_POINT_FILTER_RESTRICTION_COMPARATOR.

Operadores lógicos

Operador Asistencia
AND Es el operador predeterminado y el único compatible. Se usa para combinar los límites de inicio y finalización.
OR No compatible. El uso de OR devuelve un 400 Bad Request con el motivo de error INVALID_DATA_POINT_FILTER_EXPRESSION_STRUCTURE ("El filtro debe ser una conjunción o secuencia de restricciones. Se encontró: DISJUNCTION").

Literales de hora

Los literales de tiempo en las expresiones de filtro deben usar estos formatos:

Tipo hora Requisitos Ejemplos
Tiempo físico Formato RFC 3339, que termina en Z o en un desplazamiento de UTC. Representa eventos del mundo real en UTC. Correcto: "2026-03-01T00:00:00Z", "2026-03-01T00:00:00-08:00"
Incorrecto: "2026-03-01"
Hora civil Formato ISO 8601: YYYY-MM-DD[THH:mm:ss]. Representa la hora en el reloj de un usuario, independientemente de la ubicación o las compensaciones de zona horaria. Correcto: "2026-03-01", "2026-03-01T08:30:00"

Reglas de validación de filtros

Los filtros siguen estas reglas:

Regla Descripción Ejemplos
No se admiten tipos de tiempo mixtos No mezcles límites de tiempo físicos y civiles. No válido: 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 ("El filtro no puede contener períodos tanto físicos como civiles")
No hay tipos de datos mixtos Usa los campos que pertenecen al tipo de datos en la ruta de acceso de la solicitud. No válido: Ruta de acceso /users/.../dataTypes/steps/... con filtro distance.interval.start_time >= "..."
Error: INVALID_DATA_POINT_FILTER_COLLECTION_MISMATCH ("El tipo de datos del filtro no coincide con la colección de tipos de datos principal")
Lógica de ordenamiento por tiempo El límite superior debe ser mayor que el límite inferior. No válido: steps.interval.start_time >= "2026-03-02T00:00:00Z" AND steps.interval.start_time < "2026-03-01T00:00:00Z"
Error: INVALID_TIME_RANGE ("La hora de finalización de la búsqueda debe ser estrictamente posterior a la hora de inicio")
Formato de la caja Usa snake case que coincida con el nombre del tipo de datos. No válido: body-fat.sample_time.physical_time >= "..."
Error: INVALID_DATA_POINT_FILTER ("Invalid filter")

La API devuelve HTTP 400 Bad Request para los filtros no válidos. Verifica error.details[].metadata.detailedReasons para conocer el código del motivo del error.

Permisos de OAuth obligatorios

Para consultar puntos de datos con filtros, el usuario autorizado debe otorgar el alcance de OAuth pertinente para ese tipo de datos. Si falta el alcance requerido, la API devuelve un estado 403 Forbidden con MISSING_OAUTH_SCOPE.

En la siguiente tabla, se asignan los permisos de OAuth a los tipos de datos a los que otorgan acceso de lectura. En la tabla, se muestran los permisos en su formato relativo (por ejemplo, .activity_and_fitness.readonly representa https://www.googleapis.com/auth/googlehealth.activity_and_fitness.readonly):

Permiso de OAuth obligatorio Tipos de datos
.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 Electrocardiograma
.health_metrics_and_measurements.readonly glucemia, grasa corporal, temperatura corporal central, variabilidad de la frecuencia cardíaca diaria, zonas de frecuencia cardíaca diarias, saturación de oxígeno diaria, frecuencia respiratoria diaria, frecuencia cardíaca en reposo diaria, derivaciones de temperatura del sueño diarias, frecuencia cardíaca, variabilidad de la frecuencia cardíaca, altura, saturación de oxígeno, resumen del sueño de la frecuencia respiratoria, sensores de temperatura cutánea, peso
.irn.readonly irregular-rhythm-notification
.nutrition.readonly food, food-measurement-unit, hydration-log, nutrition-log
.sleep.readonly sleep

Si a tu cliente solo se le otorga un alcance de escritura (como .activity_and_fitness.writeonly) para un tipo de datos solicitado, aún puedes consultar los puntos de datos que escribió tu propio cliente. En este caso, las solicitudes se restringen de forma implícita a la familia de fuentes de datos self-sources. Para obtener detalles y conocer las limitaciones de los tipos de datos, consulta Cómo filtrar por familia de fuentes de datos.

Casos de uso y ejemplos

En los siguientes ejemplos, se muestra cómo construir filtros para situaciones comunes:

Pasos de la consulta por rango de tiempo físico

Pasos de la búsqueda registrados entre 2026-03-01T00:00:00Z (inclusive) y 2026-03-02T00:00:00Z (exclusive):

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"

Pasos de la consulta por rango de tiempo civil

Pasos de la búsqueda para un día completo, el 4 de marzo de 2026, en relación con el reloj local del usuario:

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"

Consulta la grasa corporal por hora de la muestra física

Consulta las mediciones de grasa corporal registradas a partir de marzo de 2026 (en 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"

Peso de la búsqueda por hora de la muestra civil

Registros de peso de la búsqueda grabados después de una hora local específica:

GET https://health.googleapis.com/v4/users/me/dataTypes/weight/dataPoints
  ?filter=weight.sample_time.civil_time >= "2026-03-01T08:00:00"

Consultar resúmenes diarios de la variabilidad de la frecuencia cardíaca

Consultar los resúmenes diarios de la variabilidad de la frecuencia cardíaca (VFC) registrados antes de una fecha específica:

GET https://health.googleapis.com/v4/users/me/dataTypes/daily-heart-rate-variability/dataPoints
  ?filter=daily_heart_rate_variability.date < "2026-08-15"

Consultar sesiones de ejercicio por hora de inicio civil

Consultar las sesiones de ejercicio que ocurrieron durante una semana específica en la zona horaria local del usuario:

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"

Consulta las sesiones de sueño por hora civil de finalización

Consultar registros de sueño por hora de finalización de la sesión:

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"

Cómo consultar electrocardiogramas por hora de inicio

Consultar los registros de ECG a partir de un punto físico en el tiempo en UTC Ten en cuenta que las búsquedas de ECG solo admiten una comparación de >= en start_time:

GET https://health.googleapis.com/v4/users/me/dataTypes/electrocardiogram/dataPoints
  ?filter=electrocardiogram.interval.start_time >= "2026-03-10T12:00:00Z"

Filtrar por familia de fuentes de datos

Una familia de fuentes de datos es una agrupación lógica de fuentes de datos (como relojes inteligentes, apps para dispositivos móviles o entradas manuales). Te permite aislar o agregar datos de tipos específicos de fuentes (por ejemplo, dispositivos wearables físicos, entradas manuales o datos escritos por tu propio cliente).

Todos los extremos list, reconcile, rollUp y dailyRollUp admiten el parámetro dataSourceFamily. El mecanismo de aprobación depende del extremo:

Extremo (método HTTP) Mecanismos
list (GET) Pasa dataSourceFamily como un parámetro de consulta de URL.
reconcile (GET) Pasa dataSourceFamily como un parámetro de consulta de URL.
rollUp (POST) Pasa dataSourceFamily como un campo en el cuerpo de la solicitud JSON.
dailyRollUp (POST) Pasa dataSourceFamily como un campo en el cuerpo de la solicitud JSON.

Familias de fuentes de datos compatibles

En la siguiente tabla, se describen los valores de dataSourceFamily admitidos:

Opción Descripción
users/me/dataSourceFamilies/all-sources Valor predeterminado (cuando se otorga un alcance de lectura). Incluye puntos de datos de todas las fuentes de datos de origen (1P) y de terceros (3P) disponibles. Con esta opción, se devuelven los datos de apps de terceros (como los pasos del reloj inteligente, los pasos de la app de terceros, los pasos del teléfono celular y los pasos manuales).
users/me/dataSourceFamilies/google-wearables Incluye los datos registrados por los dispositivos de monitoreo de Google y Fitbit (como los monitores wearables de Fitbit y el Pixel Watch). Excluye los datos registrados manualmente y los datos estimados por el teléfono. Usa esta opción cuando tu integración requiera telemetría sin procesar del sensor registrada directamente por el hardware del wearable.
users/me/dataSourceFamilies/google-sources Incluye fuentes de origen de Google y Fitbit. Esto incluye los registros de dispositivos de monitoreo de actividad física, los datos de Health Connect y las entradas manuales registradas a través de apps propias (como la app de Fitbit o Google Fit).
users/me/dataSourceFamilies/self-sources Incluye solo los datos que el cliente que llama escribió a través de la API de Google Health (puntos de datos cuya fuente de datos se registró a través de la API con el mismo ID de cliente OAuth que el llamador).

Si ningún punto de datos coincide con la familia de fuentes de datos solicitada, la respuesta será una lista vacía en lugar de un error.

Permisos de solo escritura y fuentes propias

Los llamadores a los que solo se otorgan permisos de escritura (como .activity_and_fitness.writeonly) para los tipos de datos solicitados pueden leer los datos que escribieron ellos mismos y solo esos datos.

  • Las solicitudes sin un parámetro dataSourceFamily explícito o con dataSourceFamily establecido en users/me/dataSourceFamilies/self-sources se restringen de forma implícita a self-sources.
  • Si solicitas cualquier otra familia de fuentes de datos (como all-sources, google-wearables o google-sources) solo con un permiso de escritura, se producirá un error 403 Forbidden (PERMISSION_DENIED).

Limitaciones del tipo de datos en el endpoint de la lista

En el extremo list (users.dataTypes.dataPoints.list), no se admite el filtrado por dataSourceFamily para los tipos de datos sleep, food y food-measurement-unit:

  • Si se configura dataSourceFamily de forma explícita en list para sleep, food o food-measurement-unit, se produce un error 400 Bad Request (INVALID_ARGUMENT).
  • Si se llama a list para estos tipos de datos cuando solo se otorga un alcance de escritura (en el que las restricciones para self-sources están implícitas en los alcances de la persona que llama), se produce un error 403 Forbidden (PERMISSION_DENIED).
  • Para filtrar los datos de sleep por dataSourceFamily, usa el endpoint reconcile.

Ejemplos de familias de fuentes de datos

Para enumerar los puntos de datos sin procesar que tu propio cliente escribió para un usuario, llama al extremo list con el parámetro de consulta dataSourceFamily establecido en users/me/dataSourceFamilies/self-sources.

Por ejemplo, la siguiente solicitud GET enumera las mediciones sin procesar de body-fat que escribió el cliente que llama a partir del 2026-03-01:

Solicitud

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

Respuesta

{
  "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": ""
}

Para obtener un flujo de datos conciliado de una familia de fuentes de datos específica, llama al extremo reconcile con el parámetro de consulta dataSourceFamily.

Por ejemplo, la siguiente solicitud GET recupera el sueño registrado por el dispositivo de monitoreo para el día posterior al 2026-03-03:

Solicitud

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

Respuesta

{
  "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": ""
}

Para agregar puntos de datos en un período específico restringido a una familia de fuentes de datos en particular, llama al extremo rollUp y pasa el campo dataSourceFamily en el cuerpo de la solicitud JSON.

La siguiente solicitud POST consulta los recuentos de pasos de caminata intradía en intervalos horarios (3600s), agregados exclusivamente a partir de dispositivos wearables:

Solicitud

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"
}

Respuesta

{
  "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"
      }
    }
  ]
}

Para agregar puntos de datos diarios de una familia de fuentes específica, llama al extremo dailyRollUp y pasa el campo dataSourceFamily en el cuerpo de la solicitud.

Por ejemplo, la siguiente solicitud calcula los resúmenes diarios de los pasos del usuario, incluidas todas las fuentes propias de Google y Fitbit (dispositivos wearables y entradas manuales):

Solicitud

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"
}

Respuesta

{
  "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"
      }
    }
  ]
}