Express / Connect
Drop-in middleware and query handler for Express and any Connect-compatible framework.
Full setup
server.ts
import express from 'express';
import { createExpressMiddleware, createExpressQueryHandler } from 'apptvty/express';
const app = express();
const config = {
apiKey: process.env.APPTVTY_API_KEY!,
siteId: process.env.APPTVTY_SITE_ID!,
};
// Log all requests — place before your routes
app.use(createExpressMiddleware(config));
// AEO query endpoint for AI agents
app.get('/query', createExpressQueryHandler(config));
app.listen(3000);createExpressMiddleware()
Standard Connect-style middleware. Intercepts the response finish event to capture the status code, then enqueues a log entry. Calling next()is non-blocking — the log write happens after the response is sent.
typescript
import { IncomingMessage, ServerResponse } from 'http';
function createExpressMiddleware(
config: ApptvtyConfig,
): (req: IncomingMessage, res: ServerResponse, next: (err?: unknown) => void) => voidcreateExpressQueryHandler()
A terminal route handler (not middleware). Reads ?q= and ?lang= from the raw request URL, calls the Apptvty RAG backend, and writes the JSON response.
typescript
function createExpressQueryHandler(
config: ApptvtyConfig,
): (req: IncomingMessage, res: ServerResponse) => Promise<void>Other frameworks
The Express exports use raw http.IncomingMessage and http.ServerResponse — compatible with any Connect-style stack. For frameworks like Fastify, use an adapter or the framework-agnostic core exports:
typescript
import { ApptvtyClient, RequestLogger, detectCrawler, createQueryHandler } from 'apptvty';
const config = { apiKey: '...', siteId: '...' };
const client = new ApptvtyClient(config);
const logger = new RequestLogger(client, config);
const handleQuery = createQueryHandler(client, config);
// Use in any framework's request hook
const crawler = detectCrawler(userAgent);
logger.enqueue({ site_id: config.siteId, ...fields });See the type reference for the full RequestLogEntry shape.