Skip to content

SDK Reference

Official Node.js & browser client for Enrich.sh.

Installation

bash
npm install enrich.sh

Works in Node.js, browsers, and edge workers (Cloudflare Workers, Deno, Bun).

Quick Start

javascript
import { Enrich } from 'enrich.sh'

const enrich = new Enrich('sk_live_your_api_key')

// Buffer events (auto-flushes when ready)
enrich.track('page_views', {
  url: window.location.href,
  user_id: 'user_123',
})

// Or send immediately
await enrich.ingest('page_views', [
  { url: '/home', user_id: 'user_123' },
  { url: '/pricing', user_id: 'user_456' },
])

Constructor

typescript
new Enrich(apiKey: string, options?: EnrichOptions)
ParameterTypeRequiredDescription
apiKeystringYour API key (sk_live_* or sk_test_*)
optionsEnrichOptionsConfiguration options

EnrichOptions

OptionTypeDefaultDescription
baseUrlstringhttps://enrich.shAPI base URL

Example:

javascript
const enrich = new Enrich('sk_live_your_key')

// Custom base URL (self-hosted / staging)
const enrich = new Enrich('sk_test_your_key', {
  baseUrl: 'https://staging.enrich.sh',
})

TIP

Batching, flush timing, and retries are managed automatically by the SDK. No configuration needed — we handle optimal delivery for you.


Methods

track(streamId, event)

Buffer a single event for automatic batched delivery. The SDK handles batching and flush timing automatically for optimal throughput.

typescript
track(streamId: string, event: Record<string, unknown>): void
ParameterTypeDescription
streamIdstringTarget stream identifier
eventobjectEvent payload (any JSON-serializable object)
javascript
enrich.track('events', {
  event: 'page_view',
  url: '/pricing',
  user_id: 'user_123',
})

TIP

A _ts field (Unix millisecond timestamp) is automatically added to each tracked event.


ingest(streamId, data)

Send events immediately without buffering.

typescript
ingest(streamId: string, data: object | object[]): Promise<IngestResponse>
ParameterTypeDescription
streamIdstringTarget stream identifier
dataobject or object[]Single event or array of events

Returns: Promise<IngestResponse>

typescript
interface IngestResponse {
  accepted: number
  buffered: number
}
javascript
// Single event
await enrich.ingest('events', { event: 'signup', user_id: 'u_123' })

// Batch
await enrich.ingest('events', [
  { event: 'page_view', url: '/home' },
  { event: 'page_view', url: '/pricing' },
])

flush(streamId?)

Force-flush buffered events. Normally you don't need to call this — the SDK auto-flushes. Use it before shutdown or when you need guaranteed delivery.

typescript
flush(streamId?: string): Promise<void>
javascript
// Flush one stream
await enrich.flush('events')

// Flush all streams
await enrich.flush()

query(streamId, params?)

Get presigned URLs for stored Parquet files. Pass directly to DuckDB's read_parquet().

typescript
query(streamId: string, params?: QueryParams): Promise<string[]>

QueryParams

ParameterTypeDescription
datestringSingle day — YYYY-MM-DD
startstringRange start — YYYY-MM-DD
endstringRange end — YYYY-MM-DD
daysnumberLast N days
javascript
// Last 7 days
const urls = await enrich.query('events', { days: 7 })

// Date range
const urls = await enrich.query('events', {
  start: '2026-02-01',
  end: '2026-02-07',
})

// Use with DuckDB
await conn.query(
  `SELECT * FROM read_parquet(${JSON.stringify(urls)})`
)

queryDetailed(streamId, params?)

Same as query() but returns full metadata.

typescript
queryDetailed(streamId: string, params?: QueryParams): Promise<QueryDetailedResponse>
typescript
interface QueryDetailedResponse {
  success: boolean
  stream_id: string
  file_count: number
  urls: string[]
  files: FileInfo[]
  expires_at: string
}

interface FileInfo {
  key: string
  url: string
  size: number
  uploaded_at: string
}
javascript
const result = await enrich.queryDetailed('events', { days: 7 })
console.log(`${result.file_count} files, expires ${result.expires_at}`)

beacon(streamId?)

Best-effort flush that survives page unload/tab close. Uses fetch({ keepalive: true }) with proper Authorization headers. Fire-and-forget — does not return a Promise.

typescript
beacon(streamId?: string): void
javascript
// Recommended: call on page unload
window.addEventListener('beforeunload', () => {
  enrich.beacon()
})

// Or flush a specific stream
enrich.beacon('events')

INFO

Unlike navigator.sendBeacon(), this method supports custom headers (Authorization), so your API key never appears in the URL.


destroy()

Flush all buffers and stop timers. Call before shutdown.

typescript
destroy(): Promise<void>
javascript
// Clean shutdown
await enrich.destroy()

Full Example

Edge / Service Worker

javascript
import { Enrich } from 'enrich.sh'

const enrich = new Enrich('sk_live_your_key')

// Track navigation events
chrome.webNavigation.onCompleted.addListener((details) => {
  enrich.track('navigation', {
    url: details.url,
    tab_id: details.tabId,
  })
})

// Flush before extension unloads
chrome.runtime.onSuspend.addListener(() => {
  enrich.beacon()
})

Node.js Server

javascript
import { Enrich } from 'enrich.sh'

const enrich = new Enrich('sk_live_your_key')

// Track API requests
app.use((req, res, next) => {
  enrich.track('api_logs', {
    method: req.method,
    path: req.path,
    status: res.statusCode,
    duration_ms: Date.now() - req.startTime,
  })
  next()
})

// Clean shutdown
process.on('SIGTERM', async () => {
  await enrich.destroy()
  process.exit(0)
})

Querying with DuckDB

javascript
import { Enrich } from 'enrich.sh'
import duckdb from 'duckdb'

const enrich = new Enrich('sk_live_your_key')

// Get presigned URLs
const urls = await enrich.query('events', { days: 30 })

// Query with DuckDB
const db = new duckdb.Database(':memory:')
const conn = db.connect()

conn.run(`
  SELECT event, COUNT(*) as count
  FROM read_parquet(${JSON.stringify(urls)})
  GROUP BY event
  ORDER BY count DESC
`, (err, result) => {
  console.table(result)
})

Serverless data ingestion for developers.