OneApp Docs
PackagesIntegrations

Integrations Overview

Integrations Collection

Multi-provider analytics with PostHog, Segment, and Vercel. Tree-shaking optimized with retry logic, privacy controls, and batching. Single API for all analytics providers.

Quick Start

Add analytics in 3 minutes:

pnpm add @repo/3p-core @repo/3p-posthog

Lazy loading, privacy controls, retry logic included. Skip to Quick Start →

Why Integrations?

Each analytics provider has different APIs. PostHog needs one setup, Segment another, Vercel a third. Events sent to multiple providers requires duplicated code. Privacy controls (GDPR, CCPA) reimplemented per provider. No retry logic when providers fail. Bundle size bloats from loading everything upfront.

Integrations solves this with a unified adapter pattern, lazy loading, composable utilities, and tree-shaking optimization.

Production-ready with PostHog, Segment, and Vercel support, retry logic, circuit breakers, privacy controls, and batching.

Use cases

  • Multi-provider analytics — Send events to PostHog, Segment, Vercel with single call
  • Tree-shaking — Import only what you need, minimal bundle impact (< 5KB)
  • Privacy compliance — GDPR/CCPA with IP anonymization, DNT respect
  • Resilient tracking — Retry logic, circuit breakers, failover handling
  • Lazy loading — Load providers only when needed, faster page loads

How it works

Integrations provides adapters and orchestration:

import { LazyMultiProvider } from "@repo/3p-core/orchestration/lazy-multi-provider";

const analytics = new LazyMultiProvider({
  providers: {
    posthog: {
      enabled: true,
      priority: 1,
      loader: async () => {
        const { PostHogAdapter } = await import("@repo/3p-posthog/adapter");
        return new PostHogAdapter({
          provider: "posthog",
          apiKey: process.env.POSTHOG_KEY!
        });
      }
    }
  }
});

// Single call reaches all providers
await analytics.track({ name: "Purchase", properties: { value: 100 } });

Uses BaseAdapter pattern for consistency, lazy loading for performance, and composable utilities (retry, privacy, batching) for resilience.

Key features

Tree-shaking — Import only adapters you use, minimal bundle impact

Lazy loading — Providers loaded on-demand, not at page load

Multi-provider — PostHog, Segment, Vercel with single API

Privacy controls — GDPR/CCPA compliance with IP anonymization

Retry logic — Exponential backoff, circuit breakers, failover

Batching — Queue events, flush on interval or size threshold

Quick Start

1. Install packages

# Core + PostHog
pnpm add @repo/3p-core @repo/3p-posthog

# Add Segment or Vercel as needed
pnpm add @repo/3p-segment @repo/3p-vercel

2. Create multi-provider analytics

lib/analytics.ts
import { LazyMultiProvider } from "@repo/3p-core/orchestration/lazy-multi-provider";

export const analytics = new LazyMultiProvider({
  providers: {
    posthog: {
      enabled: !!process.env.POSTHOG_KEY,
      priority: 1,
      loader: async () => {
        const { PostHogAdapter } = await import("@repo/3p-posthog/adapter");
        return new PostHogAdapter({
          provider: "posthog",
          apiKey: process.env.POSTHOG_KEY!
        });
      }
    }
  }
});

3. Track events across providers

app/components/Button.tsx
"use client";

import { analytics } from "#/lib/analytics";

export function Button() {
  async function handleClick() {
    await analytics.track({
      name: "Button Clicked",
      properties: { id: "cta" },
    });
  }

  return <button onClick={handleClick}>Click Me</button>;
}

4. Add composable utilities

lib/analytics-enhanced.ts
import { withRetry } from "@repo/3p-core/composable/with-retry";
import { withPrivacy } from "@repo/3p-core/composable/with-privacy";
import { withBatching } from "@repo/3p-core/composable/with-batching";
import { analytics } from "./analytics";

// Chain utilities for retry, privacy, batching
let enhanced = analytics;
enhanced = withRetry(enhanced, { maxRetries: 3 });
enhanced = withPrivacy(enhanced, { gdprCompliant: true });
enhanced = withBatching(enhanced, { batchSize: 100 });

export { enhanced as analytics };

That's it! You now have multi-provider analytics with retry logic, privacy controls, and batching.

Production setup with all protections

Combine retry, privacy, and batching for production:

const adapter = new PostHogAdapter({ provider: "posthog", apiKey: key });
const resilient = withRetry(withPrivacy(withBatching(adapter, { batchSize: 100 }), { gdprCompliant: true }), {
  maxRetries: 3
});

Technical Details

For Developers: Technical implementation details

Available Packages

PackageDescriptionStatus
@repo/3p-coreCore utilities, adapters, and orchestration✅ Complete
@repo/3p-posthogPostHog analytics & feature flags✅ Complete
@repo/3p-segmentSegment analytics & warehousing✅ Complete
@repo/3p-vercelVercel Analytics & Web Vitals✅ Complete

Architecture

graph TB
    subgraph Core["Core Utilities"]
        BaseAdapter["BaseAdapter"]
        Utils["Utilities: Retry, Privacy, Batching"]
        Composable["Composable: withRetry, withBatching, withPrivacy"]
    end

    subgraph Providers["Provider Adapters"]
        PostHog["PostHog (feature flags, events)"]
        Segment["Segment (events, warehouse)"]
        Vercel["Vercel (web vitals, analytics)"]
    end

    subgraph Orchestration["Orchestration"]
        MultiProvider["LazyMultiProvider"]
        Router["Router"]
    end

    Core -->|extends| Providers
    Providers -->|managed by| Orchestration
    MultiProvider -->|uses| Utils

    classDef coreStyle fill:#8b5cf6,color:#fff
    classDef providerStyle fill:#ec4899,color:#fff
    classDef orchestrationStyle fill:#06b6d4,color:#fff

    class Core coreStyle
    class Providers providerStyle
    class Orchestration orchestrationStyle

Execution Modes

Broadcast Mode (Default)

// Send to ALL enabled providers
const result = await analytics.track(event);
// result.results = { posthog: true, segment: true, vercel: true }

Failover Mode

// Try providers in priority order, stop at first success
const analytics = new LazyMultiProvider({
  providers: {
    /* ... */
  },
  execution: { mode: "failover" }
});

Parallel Mode

// Send to all providers simultaneously
const analytics = new LazyMultiProvider({
  providers: {
    /* ... */
  },
  execution: { mode: "parallel", timeout: 5000 }
});

Composable Utilities

Retry with Exponential Backoff

import { withRetry } from "@repo/3p-core/composable/with-retry";

const resilient = withRetry(adapter, {
  maxRetries: 3,
  backoffMultiplier: 2, // 1s, 2s, 4s
  maxRetryDelay: 30000
});

await resilient.track(event);

Privacy & GDPR Compliance

import { withPrivacy } from "@repo/3p-core/composable/with-privacy";

const compliant = withPrivacy(adapter, {
  anonymizeIp: true,
  respectDoNotTrack: true,
  gdprCompliant: true,
  ccpaCompliant: true,
  cookieConsent: true
});

// PII automatically filtered
await compliant.track({ email: "user@example.com", userId: "123" });
// Result: { userId: "123_hashed" } - email removed

Batching & Flushing

import { withBatching } from "@repo/3p-core/composable/with-batching";

const batched = withBatching(adapter, {
  batchSize: 100,
  flushInterval: 5000,
  maxQueueSize: 1000
});

// Events batched automatically
await batched.track(event1);
await batched.track(event2);
await batched.track(event3);

// Manual flush
await batched.flush();

Chaining Composables

import { withRetry } from "@repo/3p-core/composable/with-retry";
import { withPrivacy } from "@repo/3p-core/composable/with-privacy";
import { withBatching } from "@repo/3p-core/composable/with-batching";

let analytics = adapter;
analytics = withRetry(analytics, { maxRetries: 3 });
analytics = withPrivacy(analytics, { gdprCompliant: true });
analytics = withBatching(analytics, { batchSize: 100 });

// Now has retry, privacy, AND batching
await analytics.track(event);

Error Handling

Circuit Breaker Pattern

import { CircuitBreaker } from "@repo/3p-core/utils/retry";

const breaker = new CircuitBreaker(
  5, // Failure threshold
  60000 // Reset timeout (1 min)
);

try {
  const result = await breaker.execute(async () => {
    return await adapter.track(event);
  });
} catch (error) {
  if (error.message === "Circuit breaker is OPEN") {
    console.warn("Provider temporarily disabled");
  }
}

// Check state
console.log(breaker.getState()); // 'CLOSED' | 'OPEN' | 'HALF_OPEN'

Graceful Degradation

try {
  await analytics.track(event);
} catch (error) {
  // Fallback to console logging
  console.log("[Analytics Fallback]", event);
}

Security Best Practices

Never Expose Secret Keys Client-Side

// ❌ WRONG: Secret in client bundle
const adapter = new PostHogAdapter({
  apiKey: process.env.POSTHOG_SECRET_KEY
});

// ✅ CORRECT: Use public keys only
const adapter = new PostHogAdapter({
  apiKey: process.env.NEXT_PUBLIC_POSTHOG_KEY
});

Validate User Input

import { validateEvent } from "@repo/3p-core/utils/validation";

const validation = validateEvent(userGeneratedEvent);
if (!validation.valid) {
  console.error("Invalid event:", validation.errors);
  return;
}

// Use sanitized version
await adapter.track(validation.sanitized);

Avoid Tracking Sensitive Data

// ❌ WRONG: Never track PII
await adapter.track({
  properties: {
    email: user.email,
    creditCard: "1234-5678-9012-3456"
  }
});

// ✅ CORRECT: Track anonymized identifiers
await adapter.track({
  userId: user.id, // Hashed if GDPR enabled
  properties: {
    amount: 99.99,
    product_id: "prod_123"
  }
});

Testing

Unit Testing Adapters

import { describe, it, expect, vi } from "vitest";
import { PostHogAdapter } from "@repo/3p-posthog/adapter";

describe("PostHogAdapter", () => {
  it("tracks events correctly", async () => {
    const adapter = new PostHogAdapter({
      provider: "posthog",
      apiKey: "test-key"
    });

    const result = await adapter.track({
      name: "Test Event",
      properties: { test: true }
    });

    expect(result).toBe(true);
  });
});

Mock Provider for Testing

class MockAdapter {
  async track() {
    return true;
  }
  async identify() {
    return true;
  }
  async page() {
    return true;
  }
}

// Use in tests instead of real adapters
const adapter = new MockAdapter();

Performance Metrics

MetricTargetNotes
Bundle Size< 5KBTree-shaking optimized
Init Time< 50msLazy loading
Track Latency< 10msNon-blocking
Batch Flush< 1sDefault 5s interval

Configuration

Environment Variables

# PostHog
NEXT_PUBLIC_POSTHOG_KEY=phc_xxxxx
POSTHOG_SECRET_KEY=phc_xxxxx

# Segment
NEXT_PUBLIC_SEGMENT_KEY=xxxxx
SEGMENT_SECRET_KEY=xxxxx

# Vercel
VERCEL_ANALYTICS_ID=xxxxx

Troubleshooting

Events Not Being Sent

// 1. Check if provider is enabled
console.log(analytics.isProviderEnabled("posthog"));

// 2. Verify API key
console.log(process.env.POSTHOG_KEY);

// 3. Check network requests in DevTools
// Look for requests to posthog.com

// 4. Enable debug logging
import { setLogger } from "@repo/3p-core/utils/logger";
setLogger("debug");

High Queue Size

// Monitor batching metrics
const metrics = analytics.getMetrics?.();
console.log("Queue size:", metrics?.queueSize);
console.log("Error count:", metrics?.errorCount);

// Flush manually if needed
await analytics.flush?.();

Package Documentation

External Resources

On this page