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