@alaasync/layersync-node
v0.3.1
Published
Server-side companion to @alaasync/layersync-web — fires server CAPI events from Node.js (Next.js API routes, Express, Fastify) and pairs with the browser SDK via shared event_id for cross-source dedup.
Downloads
271
Maintainers
Readme
@alaasync/layersync-node
Server-side conversion tracking for LayerSync. Companion to
@alaasync/layersync-web
— same wire format, same event_id, so server and browser fires
collapse to a single logical conversion via dedupe-groups on
LayerSync and CAPI dedup on Meta / TikTok / etc.
Install
npm i @alaasync/layersync-nodeQuick start (Next.js Pages Router)
Wire once at your project root:
// middleware.ts
import { NextResponse, type NextRequest } from 'next/server';
import { LayerSync } from '@alaasync/layersync-node';
const ls = LayerSync.init({
siteId: process.env.LAYERSYNC_SITE_ID!,
secretKey: process.env.LAYERSYNC_SECRET!,
});
export async function middleware(req: NextRequest) {
// Forward whatever browser-fired event lives on the inbound headers.
// Fire-and-forget — never block the response on tracking.
ls.trackFromHeaders(req).catch(() => {});
return NextResponse.next();
}
export const config = {
matcher: [
'/api/com/:path*',
'/api/cart/:path*',
'/api/checkout/:path*',
'/api/orders/:path*',
],
};The browser SDK auto-injects X-LayerSync-Event-Id +
X-LayerSync-Event-Name headers on the matching cart/order POSTs.
Server-side reads them and forwards a paired event — no per-page code.
Direct firing (purchase confirmation, scheduled jobs)
For events whose authoritative source is the server (order placed via admin tool, webhook, scheduled retention email, etc.):
import { LayerSync } from '@alaasync/layersync-node';
const ls = LayerSync.init({ siteId, secretKey });
await ls.trackWithIdentity(
'purchase',
{
email: '[email protected]',
phone: '+15551234567',
},
{
order_id: 'ORD-1234',
value: 129.50,
currency: 'USD',
items: [
{ item_id: 'SKU-A', name: 'Widget', quantity: 1, price: 79.50 },
{ item_id: 'SKU-B', name: 'Gadget', quantity: 1, price: 50.00 },
],
},
{ req }, // pass the inbound request for auto IP + UA extraction
);PII (email/phone/first_name/last_name) is SHA-256 hashed with Meta/TikTok-compatible normalization before sending. Raw values never leave your server.
Options
LayerSync.init({
siteId: 'site_2388e8834989d117',
secretKey: 'b33e8a4f...', // never the publishable pk_
apiUrl: 'https://layersynchub.com', // override for staging
consoleLog: false, // log errors to stderr
trustProxy: 1, // X-Forwarded-For hops to trust
timeoutMs: 5000, // per-request timeout
maxRetries: 2, // retries on 5xx / network errors
});API
track(eventName, props?, ctx?)
Fire an event. Returns Promise<{ ok, status }>. Never rejects —
failures are logged when consoleLog: true is set.
trackWithIdentity(eventName, traits, props?, ctx?)
Same as track, but accepts plain identity traits which the SDK
hashes before send.
trackFromHeaders(req, extraProps?)
Reads X-LayerSync-Event-Id + X-LayerSync-Event-Name from the
inbound request and fires the matching paired event. Returns null
when the headers aren't present.
Security
- Use the secret key (sk_…), never the publishable key.
- The secret key must never appear in client-side environment variables
(no
NEXT_PUBLIC_…, noVITE_…, no WebpackDefinePlugin). - IP extraction respects your reverse-proxy chain — set
trustProxyto the number of LB hops in front of your app so attackers can't spoof X-Forwarded-For.
License
MIT
