Skip to content

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)
PropertyDetails
BucketOne per customer (enrich-r2-{customer_id})
FormatParquet (Snappy compressed, ~10x smaller than JSON)
AccessScoped 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 ​

  1. Go to dashboard.enrich.sh → Integrations
  2. Click Enable Warehouse
  3. Your bucket and credentials are provisioned instantly

API ​

bash
curl -X POST https://enrich.sh/warehouse/enable \
  -H "Authorization: Bearer sk_live_your_key"

Response:

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

bash
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 ​

sql
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 ​

sql
SELECT *
FROM s3(
  'https://{endpoint}/{bucket}/events/2026/02/**/*.parquet',
  '{access_key}',
  '{secret_key}',
  'Parquet'
);

Snowflake ​

sql
-- 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:

sql
CREATE EXTERNAL TABLE `project.dataset.events`
OPTIONS (
  format = 'PARQUET',
  uris = ['gs://your-gcs-mirror/events/2026/02/*.parquet']
);

Python + DuckDB ​

python
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 ​

javascript
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 ​

VolumeTypical 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 ​

PropertyDetails
Bucket isolationOne bucket per customer — no shared storage
Credential scopeRead-only, scoped to your bucket only
EncryptionAt-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 ​

bash
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.

Serverless data ingestion for developers.