Overview
Raw payloads storage lets you capture the exact JSON payloads received from wearable providers before any processing. This is useful when you need to:- Debug data issues - inspect exactly what a provider sent when something doesn’t look right
- Test ingestion changes - replay real payloads against updated parsing logic to make sure nothing breaks
- Reproduce bugs - grab the original payload that caused a problem and use it in local development
Configuration
Add these environment variables to your.env file:
Storage Backends
Disabled (default)
No payloads are stored. Thestore_raw_payload() call returns immediately with no overhead.
Log
Writes each payload as a structured JSON line to stdout. Useful for development, or when your infrastructure already captures application logs (e.g., CloudWatch, Datadog).S3
Uploads each payload as a JSON file to an S3 bucket (or any S3-compatible object store like MinIO or Railway Object Storage).AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION). See the AWS Setup guide for details.
S3 key format
Files are organized by provider, source, date, and user:_unknownis used when a user ID is not available (e.g., Garmin webhooks)file_idis a random 12-character hex string
S3 object metadata
Each object includes metadata for filtering and querying:Supported Ingestion Points
Raw payloads storage is currently enabled at two ingestion points:The Android SDK sends
provider: "google" for Health Connect; the endpoint normalizes it to health_connect before the payload is stored. Objects written before the provider split are still under the google/ prefix.SDK Payload Offload
By default the SDK sync endpoint hands the whole payload to Celery, which keeps it in the Redis broker. A queued backlog then grows with payload size, and a large backfill can push Redis tomaxmemory.
SDK_PAYLOAD_S3_OFFLOAD uploads the payload to S3 instead and queues only its s3://bucket/key reference. The worker fetches the body when the task runs.
RAW_PAYLOAD_S3_BUCKET, or AWS_BUCKET_NAME) and startup fails without one. It does not need RAW_PAYLOAD_STORAGE=s3 — archival is a debugging aid and must not gate queue reliability, so offload works with archival disabled. For the same reason RAW_PAYLOAD_MAX_SIZE_BYTES does not apply to it.
With RAW_PAYLOAD_STORAGE=s3 there is still one object, written to the same key with the same metadata, serving as both the queued payload and the archive.
With RAW_PAYLOAD_STORAGE=disabled the object only exists to carry the payload, so the worker deletes it once the batch is committed — a failed batch keeps its payload for diagnosis. This needs s3:DeleteObject on the bucket, otherwise every batch logs a delete failure.
Error Handling
Raw payloads storage is designed to never break your data ingestion pipeline:- Oversized payloads - Payloads exceeding
RAW_PAYLOAD_MAX_SIZE_BYTESare skipped with a warning log. Data processing continues normally. - S3 upload failures - Errors are logged but not propagated. The webhook or sync request continues processing.
- Missing S3 bucket - If the S3 backend is configured but no bucket is available, it falls back to
disabledwith an error log. - S3 client failure - If the S3 client cannot be created (e.g., missing
boto3or invalid credentials), it falls back todisabled.
SDK_PAYLOAD_S3_OFFLOAD the upload is the payload’s only copy, so a failure returns 503 and the SDK retries, rather than a batch being queued without a body.
Example Setup
- Development (Log)
- Development (MinIO)
- Production (S3)
Replaying Stored Payloads
Use thereplay_raw_payloads.py script to re-send S3-stored payloads through the SDK sync endpoint. This is useful for reproducing issues, re-processing data after a fix, or load testing.
Filtering
Narrow down which payloads to replay:Replaying to a different user
Use--target-user-id to send one user’s payloads to a different user account:
Dry run
Preview which payloads would be sent without making any requests:Options
Related Guides
- AWS Setup - Configure AWS credentials and S3 buckets
- How to Add a Provider - Adding raw payload storage to new providers
- Integration Guide - Testing your setup

