creem-datafast-sdk-connect
v1.0.0
Published
Automatically connect CREEM payments to DataFast analytics
Maintainers
Readme
creem-datafast
Automatically connect CREEM payments to DataFast analytics.
This package wraps the core CREEM TypeScript SDK (creem), auto-captures the datafast_visitor_id cookie on checkout, and forwards payment events to DataFast's Payment API via a webhook handler. Merchants add their DataFast API key — the package handles visitor ID capture and revenue forwarding automatically.
Features
| Feature | Description |
|---------|-------------|
| Zero-glue attribution | checkout.completed and subscription.paid events are mapped and forwarded to DataFast automatically |
| Visitor ID auto-injection | Reads datafast_visitor_id from cookies (server-side or client-side) and injects it into CREEM checkout metadata |
| Webhook signature verification | Built-in HMAC-SHA256 verification of the creem-signature header |
| Framework adapters | Ready-to-use helpers for Express and Next.js (App Router & Pages Router) |
| Generic handler | Framework-agnostic handleWebhook() for Fastify, Hono, Bun, Deno, or any custom server |
| Client-side helper | Browser utilities to read the visitor ID cookie and append it to checkout URLs |
| TypeScript first | Full type definitions for all APIs, webhook payloads, and configuration |
Installation
npm install creem-datafast
# or
pnpm add creem-datafast
# or
yarn add creem-datafastEnvironment Variables
DATAFAST_API_KEY=your_datafast_api_key
CREEM_API_KEY=your_creem_api_key
CREEM_WEBHOOK_SECRET=your_creem_webhook_secretQuick Start
Next.js App Router
Step 1 — Create a checkout session (app/api/checkout/route.ts)
import { NextResponse } from 'next/server';
import { CreemDataFast } from 'creem-datafast';
const integration = new CreemDataFast({
datafastApiKey: process.env.DATAFAST_API_KEY!,
creemApiKey: process.env.CREEM_API_KEY!,
webhookSecret: process.env.CREEM_WEBHOOK_SECRET,
});
export async function POST(request: Request) {
const { productId } = await request.json();
const checkout = await integration.createCheckout({
productId,
successUrl: 'https://yoursite.com/success',
// Auto-reads datafast_visitor_id from the request Cookie header
cookieHeader: request.headers.get('cookie') ?? '',
});
return NextResponse.json({ url: checkout.checkoutUrl });
}Step 2 — Handle webhooks (app/api/webhooks/creem/route.ts)
import { creemDataFastRouteHandler } from 'creem-datafast/next';
export const POST = creemDataFastRouteHandler({
datafastApiKey: process.env.DATAFAST_API_KEY!,
webhookSecret: process.env.CREEM_WEBHOOK_SECRET,
// Optional: called after DataFast has been notified
onPaymentAttributed: async (event, payload, response) => {
console.log('Revenue attributed:', payload.transaction_id);
// Grant user access, update your database, send a welcome email, etc.
},
});Next.js Pages Router
Checkout (pages/api/checkout.ts)
import type { NextApiRequest, NextApiResponse } from 'next';
import { CreemDataFast } from 'creem-datafast';
const integration = new CreemDataFast({
datafastApiKey: process.env.DATAFAST_API_KEY!,
creemApiKey: process.env.CREEM_API_KEY!,
});
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { productId } = req.body;
const checkout = await integration.createCheckout({
productId,
successUrl: 'https://yoursite.com/success',
cookieHeader: req.headers.cookie,
});
res.json({ url: checkout.checkoutUrl });
}Webhook (pages/api/webhooks/creem.ts)
import { creemDataFastApiRoute } from 'creem-datafast/next';
export default creemDataFastApiRoute({
datafastApiKey: process.env.DATAFAST_API_KEY!,
webhookSecret: process.env.CREEM_WEBHOOK_SECRET,
});
// Required: disable Next.js body parsing so the raw body is available
// for CREEM webhook signature verification.
export const config = {
api: { bodyParser: false },
};Express
import express from 'express';
import { creemDataFastWebhook, rawBodyParser } from 'creem-datafast/express';
import { CreemDataFast } from 'creem-datafast';
const app = express();
// Webhook route — mount BEFORE express.json()
app.post(
'/webhooks/creem',
rawBodyParser(), // Captures raw body for signature verification
creemDataFastWebhook({
datafastApiKey: process.env.DATAFAST_API_KEY!,
webhookSecret: process.env.CREEM_WEBHOOK_SECRET,
onPaymentAttributed: async (event, payload) => {
console.log('Revenue attributed:', payload.transaction_id);
},
})
);
// Other routes use the standard JSON parser
app.use(express.json());
// Checkout endpoint
const integration = new CreemDataFast({
datafastApiKey: process.env.DATAFAST_API_KEY!,
creemApiKey: process.env.CREEM_API_KEY!,
});
app.post('/checkout', async (req, res) => {
const checkout = await integration.createCheckout({
productId: req.body.productId,
successUrl: 'https://yoursite.com/success',
cookieHeader: req.headers.cookie,
});
res.json({ url: checkout.checkoutUrl });
});
app.listen(3000);Generic / Framework-Agnostic Handler
Use handleWebhook() directly with any HTTP framework:
import { CreemDataFast } from 'creem-datafast';
const integration = new CreemDataFast({
datafastApiKey: process.env.DATAFAST_API_KEY!,
webhookSecret: process.env.CREEM_WEBHOOK_SECRET,
});
// Hono example
app.post('/webhooks/creem', async (c) => {
const rawBody = await c.req.text();
const headers = Object.fromEntries(c.req.raw.headers);
const result = await integration.handleWebhook({ rawBody, headers });
if (!result.success && !result.skipped) {
return c.json({ error: result.error }, 400);
}
return c.json({ received: true });
});Client-Side Checkout URL Approach
If you use CREEM's static payment links directly in the browser, append the visitor ID as a query parameter:
import { appendVisitorIdToUrl, withVisitorId } from 'creem-datafast/client';
// Option A: Append visitor ID to a static CREEM payment link
function CheckoutButton({ productId }: { productId: string }) {
const handleClick = () => {
const url = appendVisitorIdToUrl(`https://checkout.creem.io/${productId}`);
window.location.href = url;
};
return <button onClick={handleClick}>Buy Now</button>;
}
// Option B: Include visitor ID in a fetch request to your checkout endpoint
async function createCheckout(productId: string) {
const body = withVisitorId({ productId, successUrl: '/success' });
const res = await fetch('/api/checkout', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
const { url } = await res.json();
window.location.href = url;
}How It Works
The integration follows the recommended DataFast attribution flow:
1. Visitor arrives on your site → DataFast tracking script sets the datafast_visitor_id cookie.
2. Visitor initiates checkout → Your server-side checkout endpoint calls integration.createCheckout(), which reads the datafast_visitor_id cookie from the request headers and injects it into the CREEM checkout metadata field.
3. Visitor completes payment → CREEM fires a checkout.completed (or subscription.paid) webhook to your endpoint.
4. Webhook handler processes the event → The handler verifies the CREEM signature, extracts the datafast_visitor_id from the checkout metadata, maps the CREEM order data to the DataFast payment format, and calls POST https://datafa.st/api/v1/payments.
5. DataFast attributes the revenue → The payment appears in your DataFast dashboard with full traffic source attribution.
API Reference
new CreemDataFast(config)
The main integration class.
| Option | Type | Required | Description |
|--------|------|----------|-------------|
| datafastApiKey | string | Yes | DataFast API key (Bearer token). Get from DataFast Dashboard → Website Settings → API. |
| creemApiKey | string | No* | CREEM API key. *Required for createCheckout(). |
| webhookSecret | string | No | CREEM webhook secret for signature verification. Highly recommended. |
| creemServerIdx | 0 \| 1 | No | 0 = production (default), 1 = test/sandbox. |
| datafastBaseUrl | string | No | Override the DataFast API base URL (useful for testing). |
integration.createCheckout(options)
Creates a CREEM checkout session with the DataFast visitor ID automatically injected into metadata.
| Option | Type | Description |
|--------|------|-------------|
| productId | string | CREEM product ID (required). |
| cookieHeader | string | Raw Cookie header from the incoming request. Used to auto-extract datafast_visitor_id. |
| datafastVisitorId | string | Explicitly provide the visitor ID (overrides cookie extraction). |
| successUrl | string | URL to redirect the customer after payment. |
| metadata | object | Additional metadata key-value pairs. |
| customer | object | Pre-fill customer email and name. |
| requestId | string | Optional reference ID for tracking. |
Returns { id, checkoutUrl, datafastVisitorId?, raw }.
integration.handleWebhook(request, options?)
Framework-agnostic webhook handler.
const result = await integration.handleWebhook({
rawBody: '{"eventType":"checkout.completed",...}',
headers: { 'creem-signature': 'abc123...' },
});Options callbacks:
| Callback | Signature | Description |
|----------|-----------|-------------|
| onPaymentAttributed | (event, payload, response) => void | Called after DataFast is successfully notified. |
| onEventSkipped | (event) => void | Called for non-revenue events. |
| onError | (error, event?) => void | Called when an error occurs. |
creemDataFastRouteHandler(options) (Next.js App Router)
Returns an async function compatible with export const POST = ....
creemDataFastApiRoute(options) (Next.js Pages Router)
Returns a Next.js API route handler. Remember to export config = { api: { bodyParser: false } }.
creemDataFastWebhook(options) (Express)
Returns an Express RequestHandler. Use rawBodyParser() before it.
Client-Side Helpers (creem-datafast/client)
| Function | Description |
|----------|-------------|
| getDataFastVisitorId() | Reads datafast_visitor_id from document.cookie. Returns string \| null. |
| appendVisitorIdToUrl(url, options?) | Appends ?datafast_visitor_id=... to a URL. |
| ensureVisitorIdInUrl(url, options?) | Idempotent version of appendVisitorIdToUrl. |
| withVisitorId(body) | Merges datafastVisitorId into a fetch request body object. |
Webhook Events
The following CREEM events are handled:
| Event | Action |
|-------|--------|
| checkout.completed | Maps order amount/currency/transaction ID + visitor ID → DataFast payment (one-time) |
| subscription.paid | Maps last transaction amount/currency/ID + visitor ID → DataFast payment (renewal) |
| All other events | Skipped silently; onEventSkipped callback is invoked if provided |
Security
Webhook signature verification is enabled automatically when webhookSecret is provided. The handler computes HMAC-SHA256(rawBody, secret) and compares it to the creem-signature header using a constant-time comparison to prevent timing attacks.
It is strongly recommended to set CREEM_WEBHOOK_SECRET in production. Without it, any HTTP request to your webhook endpoint will be accepted.
License
MIT
