The customer database for Express.js backends
Express.js powers a significant share of Node.js APIs and backends. Whether you're running a full monolith or a microservice handling auth, TinyCRM slots in as a single function call in your route handlers — no new dependencies, no middleware to configure, no behavioral changes to your existing code.
Installation
npm install tinycrm-sdkSet your API key in .env:
TINYCRM_API_KEY=tcrm_proj_xxxxxxxxxxxxExpress architecture and integration points
In an Express.js app, TinyCRM belongs in your route handlers — specifically wherever you create users, confirm sign-ups, or process payment webhooks.
src/
lib/
tinycrm.ts ← Shared singleton
routes/
auth.ts ← POST /auth/signup — call identify() here
webhooks.ts ← Payment webhooks — update status on paid
middleware/
activity.ts ← Optional: ping on authenticated requestsGetting started: Express.js integration
Step 1 — Create a shared SDK instance
// src/lib/tinycrm.ts
import { TinyCRM } from "tinycrm-sdk";
export const tinycrm = new TinyCRM({
apiKey: process.env.TINYCRM_API_KEY!,
});Step 2 — Identify in your sign-up route
// src/routes/auth.ts
import { Router, Request, Response } from "express";
import { tinycrm } from "../lib/tinycrm";
import { db } from "../lib/db";
const router = Router();
router.post("/signup", async (req: Request, res: Response) => {
const { email, name, password } = req.body;
const user = await db.users.create({ email, name, password });
// Fire-and-forget — no await, response is not blocked
tinycrm.identify({
email: user.email,
name: user.name,
status: "free",
params: {
source: req.query.utm_source as string ?? "direct",
ip_country: req.headers["cf-ipcountry"] as string ?? "",
},
});
res.json({ ok: true, userId: user.id });
});
export default router;Step 3 — Integrate with Passport.js local strategy
// src/auth/passport.ts
import passport from "passport";
import { Strategy as LocalStrategy } from "passport-local";
import { tinycrm } from "../lib/tinycrm";
import { db } from "../lib/db";
passport.use(new LocalStrategy(
{ usernameField: "email" },
async (email, password, done) => {
let user = await db.users.findByEmail(email);
if (!user) {
// New user — create and identify
user = await db.users.create({ email, password });
tinycrm.identify({ email, status: "free" });
}
if (!user.verifyPassword(password)) {
return done(null, false, { message: "Invalid credentials" });
}
return done(null, user);
}
));Step 4 — Stripe webhook for paid conversions
// src/routes/webhooks.ts
import { Router } from "express";
import Stripe from "stripe";
import { tinycrm } from "../lib/tinycrm";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
const router = Router();
router.post(
"/stripe",
express.raw({ type: "application/json" }),
(req, res) => {
const event = stripe.webhooks.constructEvent(
req.body,
req.headers["stripe-signature"]!,
process.env.STRIPE_WEBHOOK_SECRET!
);
if (event.type === "checkout.session.completed") {
const session = event.data.object;
tinycrm.identify({
email: session.customer_email!,
status: "paid",
params: { plan: session.metadata?.plan ?? "pro" },
});
}
res.json({ received: true });
}
);
export default router;Step 5 — Optional: ping middleware for activity tracking
// src/middleware/activity.ts
import { Request, Response, NextFunction } from "express";
import { tinycrm } from "../lib/tinycrm";
export function trackActivity(req: Request, res: Response, next: NextFunction) {
if (req.user?.email) {
// Fire-and-forget ping to update last_activity
tinycrm.ping({ email: req.user.email });
}
next();
}
// Apply to authenticated routes:
app.use("/api/dashboard", authenticate, trackActivity);Node.js ecosystem compatibility
Passport.js
Integrate in strategy verify callbacks or route handlers.
Prisma
Call identify() after prisma.user.create().
TypeORM
Works after userRepo.save(user).
Mongoose
Use post('save') middleware on your User schema.
Fastify
SDK is framework-agnostic — works in any route handler.
AWS Lambda
Works in Lambda Node.js 18+ runtimes.
Express.js FAQ
Does tinycrm-sdk work with Express.js middleware?
Yes. You can create a custom Express middleware that calls ping() on every authenticated request, or call identify() directly in your route handler functions. Both patterns are valid.
Can I use TinyCRM with Passport.js authentication?
Yes. Call identify() inside the Passport strategy's verify callback after the user is created or first logged in. For OAuth strategies, fire it in the done() callback after user upsert.
Does it work with Fastify or Koa instead of Express?
Yes. The SDK is framework-agnostic — it uses native fetch and has no Express dependency. Import it in any Node.js 18+ server framework including Fastify, Koa, Hapi, or raw HTTP handlers.
How do I avoid the identify() call blocking my Express route response?
Don't await the identify() promise. Call it without await (fire-and-forget) and the Express route returns immediately. The SDK runs the HTTP request in the background. Errors are swallowed silently by default.
Your Node.js customers deserve a real home
14-day free trial. No credit card. Works with any Express or Node.js backend.
npm install tinycrm-sdk