Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.esperr.com/llms.txt

Use this file to discover all available pages before exploring further.

Start With Integrations For Faster SetupIf you want a recipe-backed path for a specific platform, start with the Integrations guides. The SDK is best when you want direct control inside your own middleware or handler code.

Installation

npm install esper-ts-client
# or
yarn add esper-ts-client
# or
pnpm add esper-ts-client

Basic Usage

import { EsperClient, MitigationAction } from "esper-ts-client";

const client = new EsperClient({
  apiKey: "your-api-key",
});

// Send the first request's traffic to Esper beacon for analysis.
await client.sendBeaconEvent({
  type: "http_request",
  ip: "192.168.1.1",
  userAgent: req.headers["user-agent"],
  path: "/login",
  method: "POST",
  sessionId: "session-123",
  data: {
    requestId: "req-1",
  },
});

// Check a later request against active mitigation state.
const result = await client.checkMitigation({
  ip: "192.168.1.1",
  userAgent: req.headers["user-agent"],
  path: "/checkout",
  method: "POST",
  metadata: {
    requestId: "req-2",
    sessionId: "session-123",
  },
});

if (result.action === MitigationAction.Block) {
  res.status(403).json({ error: "Access denied" });
} else if (result.action === MitigationAction.Challenge) {
  res.status(429).json({ challenge: result.challenge });
} else {
  // Allow request to proceed
  next();
}

Configuration

const client = new EsperClient({
  apiKey: "your-api-key", // Required
  apiUrl: "https://api.esperr.com", // Optional
  timeout: 30000, // Optional (milliseconds)
  retries: 3, // Optional
  retryDelay: 1000, // Optional (milliseconds)
});

API Methods

checkMitigation(request)

Check if a request should be mitigated.
const result = await client.checkMitigation({
  ip: '192.168.1.1',              // Required
  userAgent: 'Mozilla/5.0...',    // Optional
  path: '/api/endpoint',          // Optional
  method: 'POST',                 // Optional
  headers: {                      // Optional
    'x-custom': 'value'
  },
  metadata: {                     // Optional
    userId: '123',
    sessionId: 'abc-xyz'
  }
});

// Response
{
  action: MitigationAction,
  reason?: string,
  score?: number,
  challenge?: {
    type: string,
    token: string,
    params?: Record<string, any>
  }
}

verifyChallenge(token, response)

Verify a user’s response to a challenge.
const isValid = await client.verifyChallenge(
  "challenge-token-123",
  "user-response-456",
);

if (isValid) {
  console.log("Challenge passed");
}

sendBeaconEvent(event)

Send request traffic to the beacon server so Esper can analyze it and update state for later mitigation checks.
await client.sendBeaconEvent({
  type: "page_view",
  ip: "192.168.1.1",
  userAgent: "Mozilla/5.0...",
  sessionId: "session-123",
  data: {
    page: "/home",
    referrer: "/login",
  },
});

getUsage()

Get API usage statistics.
const usage = await client.getUsage();

console.log(`Total requests: ${usage.requests}`);
console.log(`Blocked: ${usage.blocked}`);
console.log(`Challenged: ${usage.challenged}`);
console.log(`Allowed: ${usage.allowed}`);

Framework Integration

Express Middleware

import express from "express";
import { EsperClient, MitigationAction } from "esper-ts-client";

const app = express();
const esper = new EsperClient({
  apiKey: process.env.ESPER_API_KEY,
});

// Middleware function
const esperMiddleware = async (req, res, next) => {
  try {
    const result = await esper.checkMitigation({
      ip: req.ip,
      userAgent: req.headers["user-agent"],
      path: req.path,
      method: req.method,
    });

    if (result.action === MitigationAction.Block) {
      return res.status(403).json({
        error: "Access denied",
      });
    }

    if (result.action === "challenge") {
      return res.status(429).json({
        challenge: result.challenge,
      });
    }

    // Store result for later use
    req.esperResult = result;
    next();
  } catch (error) {
    console.error("Esper error:", error);
    // Allow request on error
    next();
  }
};

// Apply middleware
app.use(esperMiddleware);

Next.js API Routes

// pages/api/protected.ts
import { NextApiRequest, NextApiResponse } from "next";
import { EsperClient, MitigationAction } from "esper-ts-client";

const esper = new EsperClient({
  apiKey: process.env.ESPER_API_KEY,
});

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse,
) {
  // Check mitigation
  const result = await esper.checkMitigation({
    ip: req.headers["x-forwarded-for"] || req.socket.remoteAddress,
    userAgent: req.headers["user-agent"],
    path: req.url,
    method: req.method,
  });

  if (result.action === MitigationAction.Block) {
    return res.status(403).json({
      error: "Access denied",
    });
  }

  if (result.action === "challenge") {
    return res.status(429).json({
      challenge: result.challenge,
    });
  }

  // Handle protected route
  res.json({ message: "Protected data" });
}

Fastify Plugin

import fastify from "fastify";
import { EsperClient, MitigationAction } from "esper-ts-client";

const app = fastify();

app.register(async function esperPlugin(app) {
  const esper = new EsperClient({
    apiKey: process.env.ESPER_API_KEY,
  });

  app.addHook("preHandler", async (request, reply) => {
    const result = await esper.checkMitigation({
      ip: request.ip,
      userAgent: request.headers["user-agent"],
      path: request.url,
      method: request.method,
    });

    if (result.action === MitigationAction.Block) {
      reply.code(403).send({
        error: "Access denied",
      });
    }

    if (result.action === "challenge") {
      reply.code(429).send({
        challenge: result.challenge,
      });
    }

    request.esperResult = result;
  });
});

Browser Usage

The SDK can be used in browser environments for client-side protection:
<script type="module">
  import { EsperClient } from "https://cdn.jsdelivr.net/npm/esper-ts-client/+esm";

  const client = new EsperClient({
    apiKey: "your-public-api-key",
  });

  // Send page view event
  client.sendBeaconEvent({
    type: "page_view",
    sessionId: sessionStorage.getItem("sessionId"),
    data: {
      page: window.location.pathname,
      referrer: document.referrer,
    },
  });
</script>

Error Handling

import { EsperClient, MitigationAction } from "esper-ts-client";

try {
  const result = await client.checkMitigation(request);
  // Handle result
} catch (error) {
  if (error.response) {
    // API error response
    console.error("API error:", error.response.data);
  } else if (error.request) {
    // Network error
    console.error("Network error:", error.message);
  } else {
    // Other error
    console.error("Error:", error.message);
  }

  // Allow request on error
  next();
}

TypeScript Support

The SDK includes full TypeScript definitions:
import {
  EsperClient,
  EsperConfig,
  MitigationRequest,
  MitigationResponse,
  BeaconEvent,
  ChallengeData,
} from "esper-ts-client";

// All types are fully typed
const config: EsperConfig = {
  apiKey: "your-api-key",
  timeout: 30000,
};

const request: MitigationRequest = {
  ip: "192.168.1.1",
  userAgent: "Mozilla/5.0...",
};

Testing

// Mock the client for testing
jest.mock("esper-ts-client");

import { EsperClient, MitigationAction } from "esper-ts-client";

const mockClient = EsperClient as jest.MockedClass<typeof EsperClient>;

beforeEach(() => {
  mockClient.prototype.checkMitigation.mockResolvedValue({
    action: "allow",
    score: 10,
  });
});

test("should allow valid request", async () => {
  const result = await client.checkMitigation({
    ip: "192.168.1.1",
  });

  expect(result.action).toBe("allow");
});

Examples

Full examples are available in the GitHub repository.