API Latency Tracking
Capture timing data for HTTP requests across Next.js, Flutter, Android, iOS, and Node.js with automatic instrumentation and percentile metrics.
API Latency Tracking captures timing data for all HTTP requests made by your application. The SDK automatically instruments HTTP clients to measure request duration and reports this data to AbrovaTrace for analysis with p50, p95, and p99 percentile metrics.
GET, POST, PUT, DELETE, PATCH, etc.
Full URL and host for grouping
200, 404, 500, etc.
Request duration in milliseconds
Error details if request fails
Any additional metadata you attach
Next.js / React#
Automatic Tracking
Enable automatic fetch interception to track all HTTP requests:
import { AbrovaTrace } from '@abrova-trace/nextjs-sdk';
AbrovaTrace.init({
apiKey: 'ab_live_your_api_key',
environment: 'production',
});
// Enable automatic HTTP tracking
// This intercepts window.fetch and reports timing
AbrovaTrace.getInstance()?.enablePerformanceTracking({
batchSize: 5, // Send spans in batches of 5 (default)
flushInterval: 5000, // Flush at most 5 seconds after a span is buffered (default)
});Manual Operation Tracking
const sdk = AbrovaTrace.getInstance();
// Track an async operation
const result = await sdk?.trackOperation(
'fetchUserProfile',
async () => {
const response = await fetch('/api/users/123');
return response.json();
},
{
operationType: 'http',
tags: { userId: '123' }
}
);Performance Fetch Wrapper
const sdk = AbrovaTrace.getInstance();
// Create a tracked fetch function
const performanceFetch = sdk?.createPerformanceFetch() ?? fetch;
// Use it like regular fetch — timing is automatically captured
const response = await performanceFetch('/api/users');
const data = await response.json();The wrapper reports spans only after enablePerformanceTracking(), trackOperation() or reportPerformanceSpan() has been called. In the browser, enablePerformanceTracking() already tracks every fetch, so use the wrapper on the server.
Manual Span Reporting
import { createHttpSpan, PerformanceSpanFactory } from '@abrova-trace/nextjs-sdk';
// Create and report an HTTP span
const span = createHttpSpan({
method: 'GET',
url: 'https://api.example.com/users',
statusCode: 200,
durationMs: 245,
startTime: new Date(),
});
AbrovaTrace.getInstance()?.reportPerformanceSpan(span);
// Or use the factory for other span types
const dbSpan = PerformanceSpanFactory.forDbQuery({
queryType: 'SELECT',
tableName: 'users',
durationMs: 15,
startTime: new Date(),
});
AbrovaTrace.getInstance()?.reportPerformanceSpan(dbSpan);Flutter#
Performance HTTP Client
Use the PerformanceHttpClient to automatically track all HTTP requests:
import 'package:abrova_trace_flutter_sdk/abrova_trace_flutter_sdk.dart';
// Create a performance-tracking HTTP client
final client = PerformanceHttpClient(
apiKey: 'ab_live_your_api_key',
environment: 'production',
releaseVersion: '1.0.0',
addBreadcrumbs: true, // Also add HTTP breadcrumbs
excludedHosts: {'analytics.example.com'}, // Hosts to skip (Abrova's own API is always skipped)
minDurationMs: 0, // Track all requests (set higher to filter fast ones)
);
// All requests are automatically tracked
final response = await client.get(
Uri.parse('https://api.example.com/users'),
);
// Don't forget to flush and close
await client.flush();
client.close();Custom Operation Tracking
import 'package:abrova_trace_flutter_sdk/abrova_trace_flutter_sdk.dart'; // Automatic tracking with closure final result = await PerformanceTracker.track( operation: 'processOrder', apiKey: 'ab_live_your_api_key', block: () async => await orderService.process(orderId), ); // Manual tracking final tracker = PerformanceTracker( operation: 'processPayment', apiKey: 'ab_live_your_api_key', operationType: 'custom', environment: 'production', ); // ... perform operation await tracker.finish(status: SpanStatus.ok);
Android (Kotlin)#
OkHttp Performance Interceptor
import ir.abrova.trace.sdk.network.AbrovaTracePerformanceInterceptor
import okhttp3.OkHttpClient
import okhttp3.Request
val client = OkHttpClient.Builder()
.addInterceptor(AbrovaTracePerformanceInterceptor()) // APM tracking
.build()
// All API calls are automatically tracked
val request = Request.Builder()
.url("https://api.example.com/users")
.build()
client.newCall(request).execute().use { response ->
// Duration, status code, and errors are automatically reported
val users = response.body?.string()
}With Retrofit
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(AbrovaTracePerformanceInterceptor())
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build()
// All API calls through this Retrofit instance are automatically trackedManual Span Reporting
import ir.abrova.trace.sdk.AbrovaTrace
import ir.abrova.trace.sdk.models.PerformanceSpan
// Track a custom operation
val result = AbrovaTrace.trackOperation("load_user_profile") {
val user = fetchUserFromApi()
cacheUserLocally(user)
user
}
// Manual span
AbrovaTrace.reportPerformanceSpan(
PerformanceSpan.fromHttpRequest(
method = "GET",
url = "https://api.example.com/products",
statusCode = 200,
durationMs = 245L,
startTime = System.currentTimeMillis() - 245
)
)
// Database query span
AbrovaTrace.reportPerformanceSpan(
PerformanceSpan.forDbQuery(
queryType = "SELECT",
tableName = "products",
durationMs = 15L,
startTime = System.currentTimeMillis() - 15,
rowsAffected = 50
)
)iOS (Swift)#
Automatic URLSession Tracking
import AbrovaTrace // Enable automatic tracking for all URLSession requests AbrovaTrace.shared.enablePerformanceTracking() // Or create a custom session with tracking let config = AbrovaTrace.shared.performanceSessionConfiguration() let session = URLSession(configuration: config) // All requests through this session are automatically tracked let (data, response) = try await session.data(from: url)
Configuration
// Exclude specific hosts from tracking // (Abrova Trace's own API is always excluded) AbrovaTrace.shared.setPerformanceExcludedHosts(["analytics.example.com"]) // Set minimum duration to track (filter very fast requests) AbrovaTrace.shared.setPerformanceMinDuration(10) // Skip requests shorter than 10ms
Manual Tracking
import AbrovaTrace
// Track with closure
let profile = try await PerformanceTracker.trackAsync("fetchProfile") {
await api.fetchProfile()
}
// Manual tracker
let tracker = PerformanceTracker(operation: "processOrder")
tracker.setTag("orderId", value: "12345")
// ... perform operation
tracker.finish(status: .ok)Node.js#
Operation Tracking
The Node.js SDK has no automatic HTTP span capture. Wrap the work you want timed with trackOperation, or send spans yourself with reportPerformanceSpan:
const AbrovaTrace = require('@abrova-trace/nodejs-sdk');
app.get('/api/users/:id', async (req, res) => {
const user = await AbrovaTrace.trackOperation(
'GET /api/users/:id',
() => db.users.findById(req.params.id),
{ operationType: 'db', tags: { route: '/api/users/:id' } }
);
res.json(user);
});Express.js Middleware
The Express middleware records each request (method, URL, status, duration) as an HTTP breadcrumb attached to errors — not as a Performance span:
const middleware = AbrovaTrace.expressMiddleware(); app.use(middleware.requestHandler()); // Your routes // Error handler (must be last) app.use(middleware.errorHandler());
Database Query Tracking
const { Breadcrumb } = require('@abrova-trace/nodejs-sdk');
async function executeQuery(sql, params) {
const startTime = Date.now();
try {
AbrovaTrace.addBreadcrumb(Breadcrumb.database(sql.substring(0, 100), 0));
const results = await db.query(sql, params);
AbrovaTrace.addBreadcrumb(Breadcrumb.database(
'Query completed',
Date.now() - startTime
));
return results;
} catch (error) {
AbrovaTrace.captureException(error, {
extra: { sql, duration_ms: Date.now() - startTime }
});
throw error;
}
}Dashboard View#
The Performance dashboard shows latency data with the following views:
Overview Stats
- • Requests
- • Error rate
- • p50 latency
- • p95 / p99 latency
Latency
- • p50, p95, p99 over time
- • Requests over time, errors stacked
Operations
- • Operation name and type
- • Request count and latency percentiles
- • Error count
- • Status codes, Web Vitals and failed requests cards
Filtering
- • Time range (1h, 24h, 7d, 30d or custom)
- • Platform
- • Environment
- • Release
Best Practices#
Use descriptive names like "GET /api/users" instead of generic names for easier identification
Add tags like user ID, tenant ID, or feature flags to filter and segment data in the dashboard
Always set environment (production, staging, development) to separate data from different deployments
Average latency hides outliers — focus on p95 and p99 for worst-case user experience
Filter out health check endpoints and internal SDK calls from tracking
Let the SDK batch spans — use reportPerformanceSpanBatch when you report many spans yourself