Analytics
Get detailed geographic and device analytics for email events. Understand where your subscribers are located, what devices they use, and identify bot traffic to get accurate engagement metrics.
Geographic Analytics
Get a breakdown of email events by country. Available at both the organization level and per-campaign level.
Organization Level
GET /v1/analytics/geoconst geoData = await client.analytics.geo({
days: 30,
eventType: 'OPENED',
});
console.log(`Total events: ${geoData.totalCount}`);
for (const entry of geoData.data) {
console.log(`${entry.countryName}: ${entry.count} (${entry.percentage}%)`);
}
// Example output:
// Total events: 12,450
// United States: 5,210 (41.8%)
// United Kingdom: 1,870 (15.0%)
// Germany: 1,120 (9.0%)
// ...Campaign Level
GET /v1/campaigns/:id/analytics/geoconst geoData = await client.analytics.campaignGeo('campaign_xxxxx', {
eventType: 'CLICKED',
});
for (const entry of geoData.data) {
console.log(`${entry.countryCode} — ${entry.countryName}: ${entry.count} clicks`);
}Query Parameters
| Parameter | Type | Description |
|---|---|---|
| days | integer | Lookback period in days (max 90, default 30). Only for org-level. |
| eventType | string | OPENED or CLICKED (default: OPENED) |
Response Fields
| Field | Type | Description |
|---|---|---|
| totalCount | integer | Total number of events in the period |
| data[].countryCode | string | ISO 3166-1 alpha-2 country code |
| data[].countryName | string | Full country name |
| data[].count | integer | Number of events from this country |
| data[].percentage | number | Percentage of total events (0-100) |
Device Analytics
Get a breakdown of email events by device type, operating system, and email client. Includes bot detection to help you separate genuine engagement from automated opens.
Organization Level
GET /v1/analytics/devicesconst deviceData = await client.analytics.devices({
days: 30,
eventType: 'OPENED',
});
// Bot detection metrics
console.log(`Total opens: ${deviceData.totalCount}`);
console.log(`Bot opens: ${deviceData.botCount}`);
console.log(`Machine opens: ${deviceData.machineOpenCount}`);
// Device breakdown
for (const device of deviceData.devices) {
console.log(`${device.deviceType}: ${device.count} (${device.percentage}%)`);
}
// OS breakdown
for (const os of deviceData.operatingSystems) {
console.log(`${os.name}: ${os.count} (${os.percentage}%)`);
}
// Email client breakdown
for (const client of deviceData.emailClients) {
console.log(`${client.name}: ${client.count} (${client.percentage}%)`);
}Campaign Level
GET /v1/campaigns/:id/analytics/devicesconst deviceData = await client.analytics.campaignDevices('campaign_xxxxx');
// Filter out bot traffic for accurate metrics
const humanOpens = deviceData.totalCount - deviceData.botCount;
console.log(`Human opens: ${humanOpens}`);Response Fields
| Field | Type | Description |
|---|---|---|
| totalCount | integer | Total number of events |
| botCount | integer | Events identified as bot-generated |
| machineOpenCount | integer | Machine-generated opens (e.g., Apple MPP) |
| devices | array | Breakdown by device type (desktop, mobile, tablet) |
| operatingSystems | array | Breakdown by OS (iOS, Android, Windows, macOS, etc.) |
| emailClients | array | Breakdown by email client (Gmail, Apple Mail, Outlook, etc.) |
Link Analytics
Track click-through performance for individual links in emails and campaigns. When open/click tracking is enabled on a domain, all links are automatically tracked and click data is available through these endpoints.
Email Link Analytics
GET /v1/emails/:id/linksconst { data } = await client.emails.links('email_xxxxx');
for (const link of data) {
console.log(`${link.url}: ${link.totalClicks} clicks (${link.uniqueClicks} unique)`);
}Campaign Link Analytics
GET /v1/campaigns/:id/linksconst { data } = await client.campaigns.links('campaign_xxxxx');
// Sort by most clicked
const sorted = data.sort((a, b) => b.totalClicks - a.totalClicks);
for (const link of sorted) {
console.log(`${link.url}`);
console.log(` Total clicks: ${link.totalClicks}`);
console.log(` Unique clicks: ${link.uniqueClicks}`);
}Engagement Scoring
Get aggregated engagement statistics for an audience and trigger recalculation of subscriber engagement scores based on recent activity.
Get Engagement Stats
GET /v1/audiences/:id/engagement-statsconst stats = await client.audiences.getEngagementStats('audience_xxxxx');
console.log(`Average score: ${stats.averageScore}`);
console.log(`Scored: ${stats.scoredCount}, Unscored: ${stats.unscoredCount}`);
// Tier distribution
console.log(`Highly engaged: ${stats.distribution.HIGHLY_ENGAGED}`);
console.log(`Engaged: ${stats.distribution.ENGAGED}`);
console.log(`Moderately engaged: ${stats.distribution.MODERATELY_ENGAGED}`);
console.log(`At risk: ${stats.distribution.AT_RISK}`);
console.log(`Inactive: ${stats.distribution.INACTIVE}`);Recalculate Engagement
POST /v1/audiences/:id/recalculate-engagementconst result = await client.audiences.recalculateEngagement('audience_xxxxx');
console.log(`Recalculated scores for ${result.processed} subscribers`);Bot Detection
Veil Mail automatically identifies bot-generated opens and clicks, including Apple Mail Privacy Protection (MPP) pre-fetches and corporate security scanners. This helps you measure genuine subscriber engagement.
Tip: Use the botCount and machineOpenCount fields to calculate true open rates. Subtract these from totalCount for human-only engagement metrics.
Organization-level analytics requires the email:read scope. Campaign-level analytics requires the campaign:read scope. Engagement scoring requires the audience:read and audience:write scopes.