device-ai
v1.0.0
Published
Official Node.js SDK for the Device.AI bot detection API. Zero dependencies, TypeScript-first.
Maintainers
Readme
device-ai
Official Node.js SDK for the Device.AI bot detection API.
Zero dependencies. TypeScript-first. Works with Node.js 18+.
Quick Start
npm install device-aiimport { DeviceAI } from 'device-ai';
const device = new DeviceAI('dv_live_xxx');
// Verify a visitor
const result = await device.verify({
userAgent: req.headers['user-agent'],
ip: req.ip,
});
if (result.bot) {
res.status(403).json({ error: 'bot_detected' });
}Get an API Key
No signup required. Get a key instantly:
const { key } = await DeviceAI.generateKey();
console.log(key); // 'dv_live_...'Or visit device.ai and click "Get Free API Key".
Free tier: 1,000 verifications/day. No credit card required.
API Reference
new DeviceAI(apiKey, options?)
Create a new Device.AI client.
| Parameter | Type | Description |
|-----------|------|-------------|
| apiKey | string | Your API key (dv_live_xxx format) |
| options.baseUrl | string | API base URL (default: https://device.ai) |
| options.timeout | number | Request timeout in ms (default: 10000) |
| options.fetch | typeof fetch | Custom fetch implementation |
device.verify(request)
Verify a visitor and get a bot score.
const result = await device.verify({
userAgent: 'Mozilla/5.0 ...',
ip: '1.2.3.4',
signals: { /* client-side signals from detect.js */ },
});
console.log(result);
// {
// score: 0.94, // 0.0 = bot, 1.0 = human
// bot: false, // true if score < 0.3
// risk: 'low', // 'low' | 'medium' | 'high'
// signals: 7, // number of signals evaluated
// breakdown: [...], // per-signal scoring details
// keyInfo: {
// usage: 42,
// limit: 1000,
// remaining: 958
// },
// version: '2.0.0'
// }device.shield(request)
Lightweight WAF endpoint — returns an action recommendation.
const shield = await device.shield({
userAgent: req.headers['user-agent'],
ip: req.ip,
});
switch (shield.action) {
case 'allow':
// proceed normally
break;
case 'challenge':
// show CAPTCHA or additional verification
break;
case 'block':
res.status(403).json({ error: 'blocked' });
break;
}DeviceAI.generateKey(options?)
Generate a new API key (static method, no instance needed).
const newKey = await DeviceAI.generateKey();
console.log(newKey.key); // 'dv_live_...'
console.log(newKey.rateLimit); // 1000Note: Limited to 5 keys per IP per 24 hours.
Framework Integration
Express.js Middleware
import express from 'express';
import { DeviceAI } from 'device-ai';
const app = express();
const device = new DeviceAI('dv_live_xxx');
// Protect all routes
app.use(device.expressMiddleware({
threshold: 0.3, // block below this score
exclude: ['/health', '/robots.txt'],
verbose: true, // log verification results
}));
// Or protect specific routes with a higher threshold
app.post('/api/login',
device.expressMiddleware({ threshold: 0.4 }),
(req, res) => {
// Access verification result
const deviceResult = (req as any).deviceAI;
console.log(`Login attempt, score: ${deviceResult.score}`);
// ... handle login
}
);
app.listen(3000);Next.js Middleware
// middleware.ts
import { DeviceAI } from 'device-ai';
import { NextResponse, type NextRequest } from 'next/server';
const device = new DeviceAI(process.env.DEVICE_AI_KEY!);
export async function middleware(request: NextRequest) {
const handler = device.nextMiddleware({
threshold: 0.3,
exclude: ['/api/health', '/_next'],
});
const result = await handler(request);
if (result) {
return new NextResponse(result.body, {
status: result.status,
headers: result.headers,
});
}
return NextResponse.next();
}
export const config = {
matcher: ['/api/:path*'],
};Raw Node.js (no framework)
import { createServer } from 'node:http';
import { DeviceAI } from 'device-ai';
const device = new DeviceAI('dv_live_xxx');
const server = createServer(async (req, res) => {
const result = await device.verify({
userAgent: req.headers['user-agent'],
ip: req.socket.remoteAddress,
});
if (result.bot) {
res.writeHead(403, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: 'bot_detected' }));
return;
}
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end(`Welcome! Your trust score: ${result.score}`);
});
server.listen(3000);Error Handling
The SDK throws typed errors for different failure modes:
import { DeviceAI, AuthenticationError, RateLimitError, NetworkError } from 'device-ai';
const device = new DeviceAI('dv_live_xxx');
try {
const result = await device.verify({ userAgent: '...' });
} catch (error) {
if (error instanceof AuthenticationError) {
// Invalid or revoked API key
console.error('Bad key:', error.message);
} else if (error instanceof RateLimitError) {
// Daily limit exceeded
console.error(`Rate limited: ${error.used}/${error.limit}`);
console.error(`Upgrade at: ${error.upgradeUrl}`);
} else if (error instanceof NetworkError) {
// Network timeout or connection failure
console.error('Network issue:', error.message);
}
}Fail-Open Design
The Express and Next.js middleware helpers use a fail-open design: if the Device.AI API is unreachable (network error, timeout), the request is allowed through. This prevents API downtime from blocking your legitimate users.
Score Thresholds
Choose your threshold based on what you're protecting:
| Use Case | Threshold | Notes |
|----------|-----------|-------|
| Contact forms | < 0.3 → block | Moderate protection |
| Login pages | < 0.4 → challenge | Higher security |
| Payment flows | < 0.5 → review | Maximum protection |
| Ad-protected pages | < 0.3 → block | Protect ad revenue |
| Public APIs | < 0.2 → block | More permissive |
Pricing
| Plan | Price | Verifications | |------|-------|---------------| | Free | $0/mo | 1,000/day | | Pro | $19/mo | 100K/mo | | Business | $79/mo | 500K/mo | | Scale | $249/mo | 2M/mo |
Get a free key instantly at device.ai — no signup required.
License
MIT
