A cloud-native analytics solution for OpenRouter API usage data using DuckLake for incremental, versioned data storage.
OR Analytics fetches activity data from the OpenRouter API and stores it incrementally in DuckLake - a lakehouse format that combines the benefits of data lakes and warehouses. Data is stored in S3-compatible object storage with automatic versioning and time travel capabilities.
Key Features:
- ✅ Incremental Appends: Only new data is written daily (no rewrites)
- ✅ No Local Storage: Uses in-memory DuckDB (stateless, no single point of failure)
- ✅ Cloud-Native: All data persisted in S3/R2 via DuckLake
- ✅ Version Control: Automatic snapshots for time travel queries
- ✅ Built-in Scheduler: Run as a daily cron job or custom schedule
OpenRouter API → DuckDB (in-memory) → DuckLake → PostgreSQL Catalog + S3/R2 Storage
- Fetch: Retrieve last 30 days of activity from OpenRouter
- Filter: Only select records newer than the last stored date
- Append: Write new records to DuckLake (creates new snapshot)
- Persist: Data automatically saved to S3, metadata in PostgreSQL
- Go 1.26+
- OpenRouter provisioning key (not regular API key): https://openrouter.ai/settings/provisioning-keys
- PostgreSQL instance for DuckLake catalog
- S3-compatible object storage (AWS S3, Cloudflare R2, MinIO, etc.)
github.com/duckdb/duckdb-go/v2(v2.5.0) - Official DuckDB Go driver with DuckLake extensionsgithub.com/hra42/openrouter-go(v1.0.0) - OpenRouter API clientgithub.com/go-co-op/gocron/v2(v2.17.0) - Scheduler library
First, configure your DuckLake catalog and storage:
-- In your PostgreSQL instance
CREATE DATABASE or_analytics_catalog;Your S3/R2 bucket should be created and accessible with access keys.
# Required: OpenRouter API key
export OPENROUTER_API_KEY="sk-or-v1-..."
# Required: PostgreSQL catalog credentials
export PG_PASSWORD="your-postgres-password"
# Required: S3/R2 credentials
export S3_KEY="your-s3-access-key"
export S3_SECRET="your-s3-secret-key"# Basic import (uses default configuration)
go run main.go
# With custom configuration
go run main.go \
-db my_analytics \
-pg-host your-pg-host \
-pg-port 5432 \
-s3-endpoint s3.example.com \
-s3-bucket my-analytics \
-verbose# Daily at midnight (UTC)
go run main.go -schedule daily
# Custom schedule (2 AM EST)
go run main.go -schedule "0 2 * * *" -timezone America/New_York
# Run now, then schedule daily
go run main.go -schedule now
# With webhook notifications
go run main.go -schedule daily -webhook-url https://hooks.example.com/analytics-pg-password/PG_PASSWORD- PostgreSQL catalog password-s3-key/S3_KEY- S3/R2 access key ID-s3-secret/S3_SECRET- S3/R2 secret access key
-db- DuckLake database name (default:or_analytics)-pg-host- PostgreSQL host (default:localhost)-pg-port- PostgreSQL port (default:5432)-pg-user- PostgreSQL user (default:admin)-pg-dbname- PostgreSQL catalog database (default:or_analytics_catalog)
-s3-endpoint- S3/R2 endpoint URL-s3-bucket- S3/R2 bucket name (default:or-analytics)-s3-region- S3/R2 region (default:us-east-1)
-schedule- Schedule mode:daily,hourly,now, or cron expression-timezone- Timezone for scheduler (default:UTC)-webhook-url- Webhook URL for notifications-date- Filter by specific date (YYYY-MM-DD)-verbose- Enable verbose logging
docker build -t or-analytics .docker run --rm \
-e OPENROUTER_API_KEY=sk-or-v1-... \
-e PG_PASSWORD=... \
-e S3_KEY=... \
-e S3_SECRET=... \
or-analyticsdocker run -d \
--name or-analytics-scheduler \
-e OPENROUTER_API_KEY=sk-or-v1-... \
-e PG_PASSWORD=... \
-e S3_KEY=... \
-e S3_SECRET=... \
or-analytics -schedule daily -verbose# Start scheduler
docker-compose --profile scheduler up -d
# View logs
docker-compose logs -f or-analytics-schedulerConnect to your DuckLake database from any DuckDB client:
-- Install extensions
INSTALL ducklake;
INSTALL postgres;
INSTALL httpfs;
INSTALL aws;
-- Configure credentials
CREATE SECRET s3_bucket (
TYPE S3,
KEY_ID 'your-key',
SECRET 'your-secret',
REGION 'us-east-1',
ENDPOINT 's3.example.com',
USE_SSL true,
URL_STYLE 'path'
);
-- Attach database
ATTACH 'ducklake:postgres:dbname=or_analytics_catalog host=localhost port=5432 user=admin password=...'
AS or_analytics (DATA_PATH 's3://or-analytics');
USE or_analytics;
-- Query your data
SELECT
date,
model,
SUM(requests) as total_requests,
SUM(usage) as total_cost
FROM analytics
WHERE date >= current_date - 7
GROUP BY date, model
ORDER BY date DESC, total_cost DESC;DuckLake automatically creates snapshots, allowing you to query historical data:
-- Query data as it was at a specific timestamp
SELECT * FROM analytics AS OF TIMESTAMP '2025-10-01 00:00:00';
-- Query a specific snapshot version
SELECT * FROM analytics AS OF VERSION 42;# All tests
go test -v
# With coverage
go test -v -cover
# With race detection
go test -v -raceCGO_ENABLED=1 go build -ldflags="-s -w" -trimpath -o or-analyticsUnlike traditional approaches that rewrite all data daily, OR Analytics uses an efficient incremental pattern:
- Query Last Date: Check
MAX(date)in DuckLake - Filter API Results: Only process records newer than last date
- Append New Data: Insert only new records (e.g., 1 day vs 42 days)
- Auto-Snapshot: DuckLake creates new version automatically
Example:
- Day 1: Import 30 days of history → 30 days written
- Day 2: Import last 30 days, append 1 new day → 1 day written ✅
- Day 3: Import last 30 days, append 1 new day → 1 day written ✅
- No Local Database Needed: Stateless, runs anywhere
- Incremental Writes: Only new data, no rewrites
- Automatic Versioning: Time travel built-in
- S3-Native: Data lives in cheap object storage
- SQL Queries: Full DuckDB analytics capabilities
If you get 401/403 errors:
- Ensure you're using a provisioning key, not a regular API key
- Get one at: https://openrouter.ai/settings/provisioning-keys
- PostgreSQL: Verify catalog host/port and credentials
- S3/R2: Check endpoint URL, bucket name, and access keys
- Firewall: Ensure outbound access to PostgreSQL and S3 endpoints
This is normal if you've already imported today's data. The incremental append will skip duplicates.
Unlicense — public domain
Issues and pull requests welcome at https://github.com/hra42/or-analytics