SuperAgent
Lightweight and flexible HTTP client library for Node.js and browsers. Enables intuitive request building through chainable API. Provides features like plugin system, automatic parsing, multipart support, and progress tracking.
Library
SuperAgent
Overview
SuperAgent is developed as "a lightweight HTTP client for browsers and Node.js" - a library providing intuitive and expressive APIs. With readable syntax through function chaining, Promise/async-await support, plugin system, and automatic parsing functionality, it's available for both frontend and backend development. Created by TJ Holowaychuk and part of the same ecosystem as Express.js, it has become a beloved HTTP client library among JavaScript developers.
Details
SuperAgent 2025 edition maintains a balanced approach between rich functionality and ease of use, establishing itself as a mature HTTP client that adapts to modern JavaScript development. Through compatibility with Express.js, extensibility via plugins, unified browser/Node.js API, and timeout/retry/progress tracking features, it serves diverse development scenarios. With comprehensive functionality including automatic JSON parsing, form data processing, file uploads, and response transformation, it positions itself as a well-balanced library between learning curve and feature richness.
Key Features
- Unified API: Consistent interface across browser and Node.js environments
- Chainable API: Intuitive and readable method chaining syntax
- Plugin System: Flexible functionality extension and customization
- Automatic Parsing: Automatic parsing of JSON, XML, and form data
- Progress Tracking: Real-time monitoring of upload/download progress
- Express Integration: Excellent compatibility with Express.js ecosystem
Pros and Cons
Pros
- Readable code through intuitive chaining syntax
- Unified API experience across browser and Node.js
- Rich extensibility through plugin system
- Convenient automatic JSON parsing and response transformation features
- Excellent integration with Express.js and same ecosystem
- Low learning curve with beginner-friendly design
Cons
- Limited functionality compared to modern libraries like Axios and Fetch
- TypeScript support relies on community with limited official support
- Larger bundle size compared to lightweight libraries like Ky
- Insufficient support for modern HTTP features like HTTP/2
- More basic error handling compared to other libraries
- Concerns about long-term maintainability
Reference Pages
Code Examples
Installation and Basic Setup
# Install SuperAgent
npm install superagent
# TypeScript type definitions (community version)
npm install @types/superagent --save-dev
# Check ESM environment usage
node --version # Node.js 14+ recommended
// ES6 Modules import
import superagent from 'superagent';
// CommonJS import
const superagent = require('superagent');
// Browser usage (CDN)
// <script src="https://unpkg.com/[email protected]/dist/superagent.min.js"></script>
Basic Requests (GET/POST/PUT/DELETE)
import superagent from 'superagent';
// Basic GET request
async function basicGetRequest() {
try {
const response = await superagent
.get('https://api.example.com/users')
.set('Accept', 'application/json')
.set('User-Agent', 'MyApp/1.0');
console.log('Status:', response.status);
console.log('Headers:', response.headers);
console.log('User data:', response.body); // Automatic JSON parsing
} catch (error) {
console.error('GET request error:', error.message);
}
}
// GET request with query parameters
async function getWithQuery() {
try {
const response = await superagent
.get('https://api.example.com/users')
.query({
page: 1,
limit: 10,
sort: 'created_at',
filter: 'active'
})
.set('Authorization', 'Bearer your-jwt-token');
console.log('Search results:', response.body);
console.log('Request URL:', response.request.url);
} catch (error) {
if (error.response) {
console.error('HTTP error:', error.response.status, error.response.text);
} else {
console.error('Network error:', error.message);
}
}
}
// POST request (sending JSON)
async function postJsonRequest() {
try {
const userData = {
name: 'John Doe',
email: '[email protected]',
age: 30
};
const response = await superagent
.post('https://api.example.com/users')
.send(userData) // Automatically sent as JSON
.set('Authorization', 'Bearer your-jwt-token')
.set('Content-Type', 'application/json');
console.log('Created user:', response.body);
console.log('Creation date:', response.headers['date']);
} catch (error) {
console.error('POST error:', error.status, error.message);
}
}
// PUT request (update)
async function putRequest() {
try {
const updatedData = {
name: 'Jane Doe',
email: '[email protected]'
};
const response = await superagent
.put('https://api.example.com/users/123')
.send(updatedData)
.set('Authorization', 'Bearer your-jwt-token');
if (response.status === 200) {
console.log('User updated successfully:', response.body);
}
} catch (error) {
console.error('Update error:', error.status, error.response?.text);
}
}
// DELETE request
async function deleteRequest() {
try {
const response = await superagent
.delete('https://api.example.com/users/123')
.set('Authorization', 'Bearer your-jwt-token');
if (response.status === 204) {
console.log('User deleted successfully');
}
} catch (error) {
console.error('Delete error:', error.status);
}
}
// Form data submission
async function submitFormData() {
try {
const response = await superagent
.post('https://api.example.com/login')
.type('form') // application/x-www-form-urlencoded
.send({
username: 'testuser',
password: 'secret123',
remember: 'true'
});
console.log('Login successful:', response.body);
} catch (error) {
console.error('Login error:', error.message);
}
}
// Detailed response format retrieval
async function detailedResponse() {
try {
const response = await superagent
.get('https://api.example.com/status')
.accept('json');
console.log('Status code:', response.status);
console.log('Status text:', response.statusText);
console.log('Response type:', response.type);
console.log('Character encoding:', response.charset);
console.log('Content length:', response.headers['content-length']);
console.log('Response time:', response.duration, 'ms');
} catch (error) {
console.error('Request error:', error);
}
}
// Parallel execution example
async function parallelRequests() {
try {
const [users, posts, comments] = await Promise.all([
superagent.get('https://api.example.com/users'),
superagent.get('https://api.example.com/posts'),
superagent.get('https://api.example.com/comments')
]);
console.log('Users count:', users.body.length);
console.log('Posts count:', posts.body.length);
console.log('Comments count:', comments.body.length);
} catch (error) {
console.error('Parallel request error:', error.message);
}
}
Advanced Configuration and Customization (Headers, Authentication, Timeout, etc.)
// Custom headers and authentication setup
async function advancedHeaders() {
try {
const response = await superagent
.get('https://api.example.com/protected')
.set({
'Authorization': 'Bearer your-jwt-token',
'Accept': 'application/json',
'User-Agent': 'MyApp/1.0 (SuperAgent)',
'X-API-Version': 'v2',
'X-Request-ID': generateRequestId(),
'Accept-Language': 'en-US,ja-JP;q=0.9'
})
.timeout({
response: 5000, // Response wait time (5 seconds)
deadline: 10000 // Overall time limit (10 seconds)
});
console.log('Protected resource:', response.body);
} catch (error) {
if (error.timeout) {
console.error('Timeout error:', error.timeout);
} else {
console.error('Authentication error:', error.status);
}
}
}
// Basic authentication
async function basicAuth() {
try {
const response = await superagent
.get('https://api.example.com/basic-auth')
.auth('username', 'password'); // Basic auth
console.log('Basic auth success:', response.body);
} catch (error) {
console.error('Authentication failed:', error.status);
}
}
// Bearer Token authentication
async function bearerAuth() {
try {
const response = await superagent
.get('https://api.example.com/bearer-auth')
.auth('your-access-token', { type: 'bearer' });
console.log('Bearer auth success:', response.body);
} catch (error) {
console.error('Token auth failed:', error.message);
}
}
// Proxy configuration (Node.js environment)
async function proxyRequest() {
try {
const response = await superagent
.get('https://api.example.com/data')
.proxy('http://proxy.example.com:8080')
.set('User-Agent', 'MyApp via Proxy');
console.log('Response via proxy:', response.body);
} catch (error) {
console.error('Proxy error:', error.message);
}
}
// SSL certificate configuration (Node.js environment)
async function sslConfiguration() {
try {
const fs = require('fs');
const response = await superagent
.get('https://secure-api.example.com/data')
.ca(fs.readFileSync('/path/to/ca-certificate.pem'))
.cert(fs.readFileSync('/path/to/client-certificate.pem'))
.key(fs.readFileSync('/path/to/client-private-key.pem'))
.passphrase('certificate-passphrase');
console.log('SSL communication success:', response.body);
} catch (error) {
console.error('SSL configuration error:', error.message);
}
}
// Cookie handling
async function cookieHandling() {
// Cookie sending
try {
const response = await superagent
.get('https://api.example.com/session-data')
.set('Cookie', 'session_id=abc123; user_pref=dark_mode');
console.log('Response with cookies:', response.body);
// Get cookies from response
const setCookieHeader = response.headers['set-cookie'];
if (setCookieHeader) {
console.log('Received cookies:', setCookieHeader);
}
} catch (error) {
console.error('Cookie handling error:', error.message);
}
}
// Redirect control
async function redirectControl() {
try {
// Disable redirects
const response = await superagent
.get('https://api.example.com/redirect-endpoint')
.redirects(0); // Disable redirects
console.log('Response without redirects:', response.status);
} catch (error) {
if (error.status === 302) {
console.log('Redirect detected:', error.response.headers.location);
}
}
try {
// Allow up to 3 redirects
const response = await superagent
.get('https://api.example.com/redirect-endpoint')
.redirects(3);
console.log('Response after redirects:', response.body);
} catch (error) {
console.error('Redirect error:', error.message);
}
}
// Custom parser configuration
async function customParser() {
try {
const response = await superagent
.get('https://api.example.com/custom-data')
.parse((res, callback) => {
let data = '';
res.on('data', chunk => {
data += chunk;
});
res.on('end', () => {
try {
// Custom parsing process
const parsed = data.split('\n').map(line => line.trim());
callback(null, parsed);
} catch (err) {
callback(err);
}
});
});
console.log('Custom parse result:', response.body);
} catch (error) {
console.error('Parse error:', error.message);
}
}
function generateRequestId() {
return 'req-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9);
}
Error Handling and Retry Functionality
// Comprehensive error handling
async function comprehensiveErrorHandling() {
try {
const response = await superagent
.get('https://api.example.com/users')
.timeout({
response: 5000,
deadline: 10000
})
.retry(3); // Automatic retry up to 3 times
return response.body;
} catch (error) {
// Detailed SuperAgent error handling
if (error.timeout) {
console.error('Timeout error:');
console.error('- Response wait:', error.timeout.response ? 'Yes' : 'No');
console.error('- Overall deadline:', error.timeout.deadline ? 'Yes' : 'No');
} else if (error.response) {
// HTTP errors (4xx, 5xx)
const status = error.response.status;
const errorBody = error.response.text;
console.error('HTTP Error:', status);
switch (status) {
case 400:
console.error('Bad Request: Please check request parameters');
break;
case 401:
console.error('Unauthorized: Invalid authentication credentials');
// Trigger token refresh or redirect to login
break;
case 403:
console.error('Forbidden: Insufficient permissions');
break;
case 404:
console.error('Not Found: Resource does not exist');
break;
case 429:
const retryAfter = error.response.headers['retry-after'];
console.error('Rate Limited: Please try again later');
if (retryAfter) {
console.error('Retry available after:', retryAfter + ' seconds');
}
break;
case 500:
console.error('Internal Server Error: Server-side issue');
break;
case 502:
console.error('Bad Gateway: Server temporarily unavailable');
break;
case 503:
console.error('Service Unavailable: Server overloaded');
break;
default:
console.error('Error details:', errorBody);
}
} else {
// Network errors
console.error('Network error:', error.message);
console.error('Target host:', error.address);
console.error('Port:', error.port);
}
throw error;
}
}
// Custom retry strategy
async function customRetryStrategy() {
const maxRetries = 3;
const baseDelay = 1000; // 1 second
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
const response = await superagent
.get('https://api.example.com/unstable-endpoint')
.timeout({
response: 5000,
deadline: 10000
});
return response.body;
} catch (error) {
const isLastAttempt = attempt === maxRetries;
if (isLastAttempt) {
console.error('Maximum retry attempts reached:', error.message);
throw error;
}
// Check if error should be retried
const shouldRetry = error.timeout ||
(error.response && [408, 429, 500, 502, 503, 504].includes(error.response.status));
if (!shouldRetry) {
console.error('Non-retryable error:', error.message);
throw error;
}
// Exponential backoff
const delay = baseDelay * Math.pow(2, attempt);
console.log(`Retry ${attempt + 1}/${maxRetries} - retrying in ${delay}ms`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
// Status-specific error handling
async function statusSpecificHandling() {
try {
const response = await superagent
.get('https://api.example.com/conditional-endpoint')
.ok(res => res.status < 500); // Treat status < 500 as success
return response.body;
} catch (error) {
if (error.response) {
const status = error.response.status;
if (status >= 400 && status < 500) {
// Client errors (4xx)
console.log('Handling as client error:', status);
return { error: 'client_error', status, message: error.response.text };
} else if (status >= 500) {
// Server errors (5xx)
console.log('Handling as server error:', status);
throw error; // Treat server errors as exceptions
}
}
throw error;
}
}
// Partial failure tolerance in parallel requests
async function partialFailureHandling() {
const urls = [
'https://api.example.com/reliable',
'https://api.example.com/unreliable',
'https://api.example.com/another'
];
const requests = urls.map(url =>
superagent.get(url)
.timeout({ response: 3000 })
.catch(error => ({
error: true,
url,
message: error.message,
status: error.response?.status
}))
);
const results = await Promise.all(requests);
const successful = results.filter(result => !result.error);
const failed = results.filter(result => result.error);
console.log('Success:', successful.length, 'Failed:', failed.length);
console.log('Failure details:', failed);
return { successful, failed };
}
// Progressive failure recovery
async function progressiveRecovery() {
const endpoints = [
'https://primary-api.example.com/data',
'https://backup-api.example.com/data',
'https://fallback-api.example.com/data'
];
for (let i = 0; i < endpoints.length; i++) {
try {
console.log(`Attempt ${i + 1}: ${endpoints[i]}`);
const response = await superagent
.get(endpoints[i])
.timeout({ response: 3000 + (i * 2000) }) // Gradually increase timeout
.retry(i + 1); // Increase retry count for later APIs
console.log(`Success with endpoint ${i + 1}`);
return response.body;
} catch (error) {
console.log(`Endpoint ${i + 1} failed:`, error.message);
if (i === endpoints.length - 1) {
console.error('All endpoints failed');
throw new Error('All endpoints failed');
}
}
}
}
Concurrent Processing and Asynchronous Requests
// Parallel execution of multiple requests
async function parallelRequests() {
try {
const startTime = Date.now();
const [users, posts, comments, categories] = await Promise.all([
superagent.get('https://api.example.com/users'),
superagent.get('https://api.example.com/posts'),
superagent.get('https://api.example.com/comments'),
superagent.get('https://api.example.com/categories')
]);
const endTime = Date.now();
console.log(`Parallel execution time: ${endTime - startTime}ms`);
return {
users: users.body,
posts: posts.body,
comments: comments.body,
categories: categories.body
};
} catch (error) {
console.error('Parallel request error:', error.message);
throw error;
}
}
// Partial failure tolerance using Promise.allSettled
async function parallelWithPartialFailure() {
const endpoints = [
'https://api.example.com/endpoint1',
'https://api.example.com/endpoint2',
'https://api.example.com/endpoint3',
'https://api.example.com/unreliable-endpoint'
];
const requests = endpoints.map(url => superagent.get(url).timeout(5000));
const results = await Promise.allSettled(requests);
const successful = [];
const failed = [];
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
successful.push({
url: endpoints[index],
data: result.value.body
});
} else {
failed.push({
url: endpoints[index],
error: result.reason.message
});
}
});
console.log(`Success: ${successful.length}, Failed: ${failed.length}`);
return { successful, failed };
}
// Sequential data fetching with pagination support
async function fetchAllPages() {
const allData = [];
let page = 1;
let hasMore = true;
while (hasMore) {
try {
const response = await superagent
.get('https://api.example.com/paginated-data')
.query({
page: page,
limit: 20
})
.timeout(10000);
const pageData = response.body;
allData.push(...pageData.items);
hasMore = pageData.hasMore;
page++;
console.log(`Page ${page - 1} completed: ${pageData.items.length} items`);
// Wait to reduce API load
if (hasMore) {
await new Promise(resolve => setTimeout(resolve, 200));
}
} catch (error) {
console.error(`Page ${page} fetch error:`, error.message);
break;
}
}
console.log(`Total ${allData.length} items fetched`);
return allData;
}
// Parallel pagination (high-speed data fetching)
async function parallelPagination() {
// Get total pages from first page
const firstPage = await superagent
.get('https://api.example.com/paginated-data')
.query({ page: 1, limit: 20 });
const totalPages = firstPage.body.totalPages;
const allData = [...firstPage.body.items];
if (totalPages > 1) {
// Fetch remaining pages in parallel
const pageNumbers = Array.from({ length: totalPages - 1 }, (_, i) => i + 2);
const pageRequests = pageNumbers.map(page =>
superagent
.get('https://api.example.com/paginated-data')
.query({ page, limit: 20 })
.timeout(10000)
);
const pageResults = await Promise.allSettled(pageRequests);
pageResults.forEach((result, index) => {
if (result.status === 'fulfilled') {
allData.push(...result.value.body.items);
} else {
console.error(`Page ${pageNumbers[index]} failed:`, result.reason.message);
}
});
}
console.log(`Parallel fetch completed: ${allData.length} items`);
return allData;
}
// Rate-limited sequential execution
async function rateLimitedRequests(urls, requestsPerSecond = 5) {
const interval = 1000 / requestsPerSecond; // Request interval
const results = [];
for (let i = 0; i < urls.length; i++) {
const startTime = Date.now();
try {
const response = await superagent
.get(urls[i])
.timeout(5000);
results.push({
url: urls[i],
success: true,
data: response.body
});
console.log(`${i + 1}/${urls.length} completed: ${urls[i]}`);
} catch (error) {
results.push({
url: urls[i],
success: false,
error: error.message
});
console.error(`${i + 1}/${urls.length} failed: ${urls[i]}`);
}
// Rate limiting wait
if (i < urls.length - 1) {
const elapsed = Date.now() - startTime;
const waitTime = Math.max(0, interval - elapsed);
if (waitTime > 0) {
await new Promise(resolve => setTimeout(resolve, waitTime));
}
}
}
const successCount = results.filter(r => r.success).length;
console.log(`Processing completed: ${successCount}/${urls.length} successful`);
return results;
}
// Concurrency-limited parallel processing
async function concurrencyLimitedRequests(urls, maxConcurrency = 3) {
const results = [];
const executing = [];
for (const url of urls) {
const promise = superagent.get(url).timeout(5000).then(
response => ({ url, success: true, data: response.body }),
error => ({ url, success: false, error: error.message })
);
results.push(promise);
if (urls.length >= maxConcurrency) {
executing.push(promise);
if (executing.length >= maxConcurrency) {
await Promise.race(executing);
executing.splice(executing.findIndex(p => p === promise), 1);
}
}
}
const finalResults = await Promise.all(results);
const successCount = finalResults.filter(r => r.success).length;
console.log(`Concurrency-limited processing completed: ${successCount}/${urls.length} successful`);
return finalResults;
}
Framework Integration and Practical Examples
// Express.js integration example
import express from 'express';
import superagent from 'superagent';
const app = express();
app.use(express.json());
// API proxy endpoint
app.get('/api/proxy/:service/*', async (req, res) => {
try {
const { service } = req.params;
const path = req.params[0];
const serviceUrls = {
'users': 'https://users-api.example.com',
'posts': 'https://posts-api.example.com',
'comments': 'https://comments-api.example.com'
};
const baseUrl = serviceUrls[service];
if (!baseUrl) {
return res.status(404).json({ error: 'Service not found' });
}
const response = await superagent
.get(`${baseUrl}/${path}`)
.query(req.query)
.set('Authorization', req.headers.authorization)
.timeout(10000);
res.json(response.body);
} catch (error) {
console.error('Proxy error:', error.message);
res.status(error.response?.status || 500).json({
error: 'Proxy request failed',
message: error.message
});
}
});
// React/Vue.js integration example (API client service)
class ApiService {
constructor(baseURL, token) {
this.baseURL = baseURL;
this.token = token;
}
// Common request configuration
request() {
return superagent
.timeout({
response: 10000,
deadline: 15000
})
.set('Authorization', `Bearer ${this.token}`)
.set('Content-Type', 'application/json');
}
// Get user list
async getUsers(page = 1, limit = 20) {
try {
const response = await this.request()
.get(`${this.baseURL}/users`)
.query({ page, limit });
return {
data: response.body,
pagination: {
page,
limit,
total: parseInt(response.headers['x-total-count'])
}
};
} catch (error) {
throw this.handleError(error);
}
}
// Create user
async createUser(userData) {
try {
const response = await this.request()
.post(`${this.baseURL}/users`)
.send(userData);
return response.body;
} catch (error) {
throw this.handleError(error);
}
}
// Update user
async updateUser(id, userData) {
try {
const response = await this.request()
.put(`${this.baseURL}/users/${id}`)
.send(userData);
return response.body;
} catch (error) {
throw this.handleError(error);
}
}
// Delete user
async deleteUser(id) {
try {
await this.request()
.delete(`${this.baseURL}/users/${id}`);
return true;
} catch (error) {
throw this.handleError(error);
}
}
// Error handling
handleError(error) {
if (error.response) {
return {
status: error.response.status,
message: error.response.text || error.message,
data: error.response.body
};
} else {
return {
status: 0,
message: error.message,
data: null
};
}
}
}
// File upload functionality
async function uploadFile(file, metadata = {}) {
try {
const response = await superagent
.post('https://api.example.com/upload')
.attach('file', file, file.name)
.field('description', metadata.description || '')
.field('category', metadata.category || 'general')
.set('Authorization', 'Bearer your-token')
.on('progress', (event) => {
if (event.direction === 'upload') {
const percent = Math.round((event.loaded / event.total) * 100);
console.log(`Upload progress: ${percent}%`);
}
});
console.log('Upload completed:', response.body);
return response.body;
} catch (error) {
console.error('Upload error:', error.message);
throw error;
}
}
// Download progress tracking
async function downloadFile(url, filename) {
try {
const response = await superagent
.get(url)
.on('progress', (event) => {
if (event.direction === 'download') {
const percent = Math.round((event.loaded / event.total) * 100);
console.log(`Download progress: ${percent}%`);
}
})
.buffer(true)
.parse(superagent.parse.image); // Parse as image
// File saving in Node.js environment
if (typeof window === 'undefined') {
const fs = require('fs');
fs.writeFileSync(filename, response.body);
console.log('File saved:', filename);
} else {
// Download in browser environment
const blob = new Blob([response.body]);
const downloadUrl = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = downloadUrl;
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(downloadUrl);
}
} catch (error) {
console.error('Download error:', error.message);
throw error;
}
}
// Plugin system utilization
function createAuthPlugin(getToken) {
return function(request) {
const token = getToken();
if (token) {
request.set('Authorization', `Bearer ${token}`);
}
return request;
};
}
function createLoggingPlugin() {
return function(request) {
const startTime = Date.now();
const method = request.method;
const url = request.url;
console.log(`[${method}] ${url} - Start`);
request.on('response', (response) => {
const duration = Date.now() - startTime;
console.log(`[${method}] ${url} - Completed (${response.status}, ${duration}ms)`);
});
request.on('error', (error) => {
const duration = Date.now() - startTime;
console.log(`[${method}] ${url} - Error (${duration}ms):`, error.message);
});
return request;
};
}
// Plugin usage example
const authPlugin = createAuthPlugin(() => localStorage.getItem('token'));
const loggingPlugin = createLoggingPlugin();
async function apiCallWithPlugins() {
try {
const response = await superagent
.get('https://api.example.com/protected')
.use(authPlugin)
.use(loggingPlugin);
return response.body;
} catch (error) {
console.error('API call error:', error.message);
throw error;
}
}
// WebSocket-like polling implementation
class ApiPoller {
constructor(url, interval = 5000) {
this.url = url;
this.interval = interval;
this.isPolling = false;
this.callbacks = [];
}
onData(callback) {
this.callbacks.push(callback);
}
async start() {
this.isPolling = true;
while (this.isPolling) {
try {
const response = await superagent
.get(this.url)
.timeout(this.interval - 1000);
this.callbacks.forEach(callback => callback(response.body));
} catch (error) {
console.error('Polling error:', error.message);
}
if (this.isPolling) {
await new Promise(resolve => setTimeout(resolve, this.interval));
}
}
}
stop() {
this.isPolling = false;
}
}
// Usage example
const poller = new ApiPoller('https://api.example.com/live-data');
poller.onData(data => console.log('New data:', data));
// poller.start();