https://github.com/mathematic-inc/alyt
All-in-one analytics SDK for TypeScript — unified API for GA, PostHog, Mixpanel, Amplitude, Plausible, and Vercel Analytics with YAML codegen and React bindings
https://github.com/mathematic-inc/alyt
amplitude analytics codegen google-analytics mixpanel plausible posthog react sdk typescript
Last synced: 19 days ago
JSON representation
All-in-one analytics SDK for TypeScript — unified API for GA, PostHog, Mixpanel, Amplitude, Plausible, and Vercel Analytics with YAML codegen and React bindings
- Host: GitHub
- URL: https://github.com/mathematic-inc/alyt
- Owner: mathematic-inc
- License: apache-2.0
- Created: 2026-02-28T01:21:13.000Z (5 months ago)
- Default Branch: main
- Last Pushed: 2026-03-11T04:38:27.000Z (5 months ago)
- Last Synced: 2026-05-22T03:38:34.596Z (2 months ago)
- Topics: amplitude, analytics, codegen, google-analytics, mixpanel, plausible, posthog, react, sdk, typescript
- Language: TypeScript
- Size: 304 KB
- Stars: 7
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
README
# alyt
All-in-one Analytics SDK.
Define your analytics events in a YAML schema and get a fully typed TypeScript tracker — no more typos in event names or missing properties. alyt sends events to Google Analytics, PostHog, Mixpanel, Amplitude, Plausible, and Vercel Analytics through a single API, and lets you add or remove providers at runtime for consent flows.
## Install
```bash
# core
pnpm add @alyt/core
# plugins (pick what you use)
pnpm add @alyt/plugin-ga
pnpm add @alyt/plugin-posthog
pnpm add @alyt/plugin-mixpanel
pnpm add @alyt/plugin-amplitude
pnpm add @alyt/plugin-plausible
pnpm add @alyt/plugin-vercel
# react bindings
pnpm add @alyt/react
# codegen (dev dependency)
pnpm add -D @alyt/codegen
```
## Quick Start
```typescript
import { createAnalytics } from "@alyt/core";
import { googleAnalytics } from "@alyt/plugin-ga";
import { posthog } from "@alyt/plugin-posthog";
const analytics = createAnalytics({
plugins: [
googleAnalytics({ measurementId: "G-XXXXXXXXXX" }),
posthog({ apiKey: "phc_XXXXXXXXXX" }),
],
});
analytics.track("button_clicked", { label: "Sign Up" });
analytics.identify("user_123", { plan: "pro" });
analytics.page("Home");
```
Every call fans out to all registered plugins. Plugins that don't implement a method (e.g. Plausible has no `identify`) are silently skipped.
## Plugins
| Plugin | Package | Factory | Required Options |
| --- | --- | --- | --- |
| Google Analytics | `@alyt/plugin-ga` | `googleAnalytics()` | `measurementId: string` |
| PostHog | `@alyt/plugin-posthog` | `posthog()` | `apiKey: string` |
| Mixpanel | `@alyt/plugin-mixpanel` | `mixpanel()` | `token: string` |
| Amplitude | `@alyt/plugin-amplitude` | `amplitude()` | `apiKey: string` |
| Plausible | `@alyt/plugin-plausible` | `plausible()` | `domain: string` |
| Vercel Analytics | `@alyt/plugin-vercel` | `vercelAnalytics()` | _(none)_ |
Each plugin also accepts an optional `client` property to inject an SDK instance (useful for testing or SSR).
### Script Loaders (React / Next.js)
Plugins that need a `` tag provide a React component under a `/react` subpath:
```tsx
import { GAScript } from "@alyt/plugin-ga/react";
import { VercelAnalytics } from "@alyt/plugin-vercel/react";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<body>
<GAScript measurementId="G-XXXXXXXXXX" />
<VercelAnalytics />
{children}
</body>
</html>
);
}
```
| Package | Component | Props |
| --- | --- | --- |
| `@alyt/plugin-ga/react` | `GAScript` | `measurementId?: string` (falls back to `NEXT_PUBLIC_GA_MEASUREMENT_ID`) |
| `@alyt/plugin-posthog/react` | `PostHogScript` | `apiKey: string`, `apiHost?: string` |
| `@alyt/plugin-mixpanel/react` | `MixpanelScript` | `token: string` |
| `@alyt/plugin-amplitude/react` | `AmplitudeScript` | `apiKey: string` |
| `@alyt/plugin-plausible/react` | `PlausibleScript` | `domain: string`, `apiHost?: string` |
| `@alyt/plugin-vercel/react` | `VercelAnalytics` | _(re-export of `@vercel/analytics/react`)_ |
## React
Wrap your app with `AnalyticsProvider` and use the `useAnalytics` hook in any component:
```tsx
import { createAnalytics } from "@alyt/core";
import { AnalyticsProvider, useAnalytics } from "@alyt/react";
import { googleAnalytics } from "@alyt/plugin-ga";
const client = createAnalytics({
plugins: [googleAnalytics({ measurementId: "G-XXXXXXXXXX" })],
});
// In your root layout
function App() {
return (
<AnalyticsProvider client={client}>
<Dashboard />
</AnalyticsProvider>
);
}
// In any component
function Dashboard() {
const analytics = useAnalytics();
return (
<button onClick={() => analytics.track("dashboard_clicked")}>
Go to Dashboard
</button>
);
}
```
`useAnalytics()` throws if used outside an `<AnalyticsProvider>`.
## Codegen
Define your events in a YAML schema and generate a fully typed tracker.
### 1. Define your schema
```yaml
# analytics.schema.yaml
events:
page_viewed:
description: Fired when a user views a page
params:
page_name: string
button_clicked:
description: Fired when a user clicks a button
params:
button_id: string
label: string
user_signed_up:
description: Fired when a new user completes registration
```
Events with no parameters can omit `params`. The optional `description` field generates JSDoc comments in the output.
Parameters support a short form (`name: type`) and a full form for metadata:
```yaml
events:
magic_link_requested:
params:
email:
type: string
hash: true
```
`hash: true` is only valid for `type: string`. The generated tracker method still accepts the raw string argument, but emits the same parameter key with the exact input string replaced by a lowercase SHA-256 hex digest from `globalThis.crypto.subtle`. Alyt does not trim, lowercase, salt, or rename hashed values. Generated methods with hashed params are `async`; generated methods without hashed params remain synchronous.
### 2. Run the CLI
```bash
npx alyt-codegen --schema analytics.schema.yaml --out lib/analytics
```
### 3. Use the generated tracker
The CLI generates two files:
**`types.ts`** -- Event name union and parameter map:
```typescript
export type AnalyticsEventName =
| "page_viewed"
| "button_clicked"
| "user_signed_up";
export interface AnalyticsEventMap {
/** Fired when a user views a page */
page_viewed: { page_name: string };
/** Fired when a user clicks a button */
button_clicked: { button_id: string; label: string };
/** Fired when a new user completes registration */
user_signed_up: Record<string, never>;
}
```
**`tracker.ts`** -- Typed methods that call `client.track()`:
```typescript
import type { AnalyticsClient, TrackOptions } from "@alyt/core";
export function createTracker(client: AnalyticsClient) {
return {
/** Fired when a user views a page */
pageViewed(pageName: string, options?: TrackOptions) {
client.track("page_viewed", { page_name: pageName }, options);
},
/** Fired when a user clicks a button */
buttonClicked(buttonId: string, label: string, options?: TrackOptions) {
client.track("button_clicked", { button_id: buttonId, label: label }, options);
},
/** Fired when a new user completes registration */
userSignedUp(options?: TrackOptions) {
client.track("user_signed_up", undefined, options);
},
};
}
```
Parameter names are converted from `snake_case` (YAML) to `camelCase` (TypeScript). Descriptions become JSDoc comments on both the type map and the tracker methods.
## Selective Tracking
Send an event to specific plugins only using `TrackOptions.only`:
```typescript
// Only send to Google Analytics, skip PostHog
analytics.track("internal_metric", { value: 42 }, { only: ["google-analytics"] });
```
Plugin names are the `name` property returned by each factory:
| Factory | Plugin Name |
| --- | --- |
| `googleAnalytics()` | `"google-analytics"` |
| `posthog()` | `"posthog"` |
| `mixpanel()` | `"mixpanel"` |
| `amplitude()` | `"amplitude"` |
| `plausible()` | `"plausible"` |
| `vercelAnalytics()` | `"vercel"` |
The generated tracker also accepts `TrackOptions` as the last argument on every method.
## Custom Client
Every plugin accepts a `client` option to pass your own SDK instance. This is useful when you've already initialized the SDK elsewhere, or for testing:
```typescript
import { googleAnalytics } from "@alyt/plugin-ga";
// Use your own gtag instance
const plugin = googleAnalytics({
measurementId: "G-XXXXXXXXXX",
client: myCustomGtag,
});
```
## Dynamic Plugins
Add or remove plugins at runtime -- useful for cookie consent flows:
```typescript
import { createAnalytics } from "@alyt/core";
import { googleAnalytics } from "@alyt/plugin-ga";
import { posthog } from "@alyt/plugin-posthog";
const analytics = createAnalytics(); // start with no plugins
// User accepts analytics cookies
analytics.addPlugin(googleAnalytics({ measurementId: "G-XXXXXXXXXX" }));
analytics.addPlugin(posthog({ apiKey: "phc_XXXXXXXXXX" }));
// User revokes consent
analytics.removePlugin("google-analytics");
analytics.removePlugin("posthog");
```
Events tracked before any plugins are added are silently dropped.
## Custom Plugins
Implement the `AnalyticsPlugin` interface to write your own:
```typescript
import type { AnalyticsPlugin } from "@alyt/core";
export function consoleAnalytics(): AnalyticsPlugin {
return {
name: "console",
track(event, params) {
console.log("[track]", event, params);
},
identify(userId, traits) {
console.log("[identify]", userId, traits);
},
page(name, params) {
console.log("[page]", name, params);
},
reset() {
console.log("[reset]");
},
};
}
```
Only `name` and `track` are required. The `identify`, `page`, and `reset` methods are optional.
## Packages
| Package | Description |
| --- | --- |
| [`@alyt/core`](packages/core) | `createAnalytics` client and plugin interface |
| [`@alyt/react`](packages/react) | `AnalyticsProvider` and `useAnalytics` hook |
| [`@alyt/codegen`](packages/codegen) | YAML-to-TypeScript event codegen CLI |
| [`@alyt/plugin-ga`](packages/plugin-ga) | Google Analytics (gtag.js) |
| [`@alyt/plugin-posthog`](packages/plugin-posthog) | PostHog |
| [`@alyt/plugin-mixpanel`](packages/plugin-mixpanel) | Mixpanel |
| [`@alyt/plugin-amplitude`](packages/plugin-amplitude) | Amplitude |
| [`@alyt/plugin-plausible`](packages/plugin-plausible) | Plausible Analytics |
| [`@alyt/plugin-vercel`](packages/plugin-vercel) | Vercel Analytics |
## License
Apache-2.0
> This project is free and open-source work by a 501(c)(3) non-profit. If you find it useful, please consider [donating](https://github.com/sponsors/mathematic-inc).