Connect
Every Enrich.sh customer gets a dedicated, isolated R2 bucket — your data never shares storage with other customers. Connect any S3-compatible warehouse to read your Parquet files directly.
How It Works
Your Events → enrich.sh → Your Dedicated R2 Bucket → Your Warehouse
(S3-compatible)| Property | Details |
|---|---|
| Bucket | One per customer (enrich-r2-{customer_id}) |
| Format | Parquet (Snappy compressed, ~10x smaller than JSON) |
| Access | Scoped read-only credentials (S3 API) |
| Egress | $0 — Cloudflare R2 has zero egress fees |
| Partitioning | {stream_id}/{year}/{month}/{day}/{hour}/{timestamp}.parquet |
Enabling Your Warehouse
Dashboard
- Go to dashboard.enrich.sh → Integrations
- Click Enable Warehouse
- Your bucket and credentials are provisioned instantly
API
curl -X POST https://enrich.sh/warehouse/enable \
-H "Authorization: Bearer sk_live_your_key"Response:
{
"bucket": "enrich-r2-cust-abc123",
"endpoint": "https://abcdef123456.r2.cloudflarestorage.com",
"access_key_id": "your_read_access_key",
"secret_access_key": "your_read_secret_key",
"region": "auto"
}INFO
Provisioning creates a dedicated R2 bucket and scoped read-only credentials. Your data starts flowing to your bucket immediately.
Get Your Credentials
If your warehouse is already enabled, retrieve your credentials:
curl https://enrich.sh/warehouse \
-H "Authorization: Bearer sk_live_your_key"Or go to Dashboard → Integrations to see your endpoint, bucket, access key, and secret key.
Connecting Your Warehouse
DuckDB
INSTALL httpfs;
LOAD httpfs;
SET s3_region = 'auto';
SET s3_endpoint = '{endpoint}';
SET s3_access_key_id = '{access_key}';
SET s3_secret_access_key = '{secret_key}';
-- Query all events from February
SELECT * FROM read_parquet('s3://{bucket}/events/2026/02/**/*.parquet');
-- Query a specific day
SELECT * FROM read_parquet('s3://{bucket}/events/2026/02/15/**/*.parquet');ClickHouse
SELECT *
FROM s3(
'https://{endpoint}/{bucket}/events/2026/02/**/*.parquet',
'{access_key}',
'{secret_key}',
'Parquet'
);Snowflake
-- Create external stage pointing to R2
CREATE STAGE enrich_stage
URL = 's3compat://{bucket}/'
CREDENTIALS = (AWS_KEY_ID = '{access_key}' AWS_SECRET_KEY = '{secret_key}')
FILE_FORMAT = (TYPE = 'PARQUET');
SELECT * FROM @enrich_stage/events/2026/02/ (FILE_FORMAT => 'PARQUET');BigQuery
Mirror data to GCS first, then create an external table:
CREATE EXTERNAL TABLE `project.dataset.events`
OPTIONS (
format = 'PARQUET',
uris = ['gs://your-gcs-mirror/events/2026/02/*.parquet']
);Python + DuckDB
import duckdb
conn = duckdb.connect()
conn.execute("""
SET s3_region = 'auto';
SET s3_endpoint = '{endpoint}';
SET s3_access_key_id = '{access_key}';
SET s3_secret_access_key = '{secret_key}';
""")
df = conn.execute("""
SELECT event, COUNT(*) as count
FROM read_parquet('s3://{bucket}/events/2026/02/**/*.parquet')
GROUP BY event
ORDER BY count DESC
""").fetchdf()
print(df)SDK
import { Enrich } from 'enrich.sh'
const enrich = new Enrich('sk_live_your_key')
// Get presigned URLs (no S3 credentials needed)
const urls = await enrich.query('events', { days: 7 })
// Pass to DuckDB
await conn.query(
`SELECT * FROM read_parquet(${JSON.stringify(urls)})`
)File Layout
Your data is partitioned by stream, date, and hour:
enrich-r2-cust-abc123/
├── events/
│ └── 2026/
│ └── 02/
│ ├── 15/
│ │ ├── 09/
│ │ │ └── 2026-02-15T09-30-00-000Z.parquet
│ │ └── 10/
│ │ └── 2026-02-15T10-15-00-000Z.parquet
│ └── 16/
│ └── ...
├── clicks/
│ └── 2026/
│ └── ...
└── transactions/
└── _dlq/ ← Dead Letter Queue (strict mode rejections)
└── 2026/
└── ...Glob patterns work: s3://bucket/events/2026/02/**/*.parquet ✅
Data Freshness
| Volume | Typical Flush Delay |
|---|---|
| High volume (>5k events/min) | ~2 minutes |
| Medium volume | ~5–12 minutes |
| Low volume (<50 events/min) | Up to 1 hour (max hold time) |
Data is available to query as soon as the Parquet file is flushed to R2.
Security
| Property | Details |
|---|---|
| Bucket isolation | One bucket per customer — no shared storage |
| Credential scope | Read-only, scoped to your bucket only |
| Encryption | At-rest encryption (Cloudflare R2 default) |
| No egress fees | $0 to read your data — query as much as you want |
WARNING
Your read credentials provide access to all data in your bucket across all streams. Treat them like any other secret.
Disabling Warehouse
curl -X POST https://enrich.sh/warehouse/disable \
-H "Authorization: Bearer sk_live_your_key"This revokes your S3 credentials and stops writing to your dedicated bucket. Data already stored is retained.
