Period Comparison API
Compare analytics data between time periods to track growth, identify trends, and measure performance changes.
Overview
The Sealmetrics API supports two comparison modes:
| Mode | Value | Description |
|---|---|---|
| Previous Period | previous | Same duration, immediately before the selected range |
| Year over Year | yoy | Same dates in the previous year |
Using Comparison
Add the compare parameter to any stats endpoint:
GET /stats/overview?site_id=my-site&period=30d&compare=previous
Parameter Values
| Value | Effect |
|---|---|
previous | Compare with the previous period of same duration |
yoy | Compare with the same period last year |
| (omit) | No comparison (default for most endpoints) |
true | Alias for previous |
The /stats/overview endpoint defaults to compare=previous if not specified.
Comparison Modes Explained
Previous Period
Compares with the same duration immediately before the selected range.
Examples:
| Selected Period | Comparison Period |
|---|---|
| Jan 15-21 (7 days) | Jan 8-14 (7 days) |
| Last 30 days | Previous 30 days |
| This month (Jan 1-10) | Dec 2-11 (same duration) |
GET /stats/sources?site_id=my-site&period=7d&compare=previous
This compares:
- Current: Last 7 days (e.g., Jan 4-10)
- Previous: 7 days before that (Dec 28 - Jan 3)
Year over Year (YoY)
Compares with the exact same dates in the previous year.
Examples:
| Selected Period | Comparison Period |
|---|---|
| Jan 1-31, 2025 | Jan 1-31, 2024 |
| Q4 2024 | Q4 2023 |
| Dec 25, 2024 | Dec 25, 2023 |
GET /stats/sources?site_id=my-site&period=this_month&compare=yoy
This compares:
- Current: January 2025
- Previous: January 2024
Use yoy for seasonal businesses where comparing to last year is more meaningful than the previous period. Black Friday vs Black Friday, not Black Friday vs early November.
Response Format
Overview Endpoint
The /stats/overview endpoint includes comparison data inline:
{
"success": true,
"data": {
"entrances": 15420,
"engaged_entrances": 12336,
"page_views": 45780,
"conversions": 245,
"revenue": 18650.00,
"bounce_rate": 20.0,
"comparison": {
"entrances": 14200,
"engaged_entrances": 11360,
"page_views": 42500,
"conversions": 210,
"revenue": 16800.00,
"bounce_rate": 20.0
},
"deltas": {
"entrances": 8.59,
"engaged_entrances": 8.59,
"page_views": 7.72,
"conversions": 16.67,
"revenue": 11.01,
"bounce_rate": 0.0
},
"time_series": [...],
"comparison_time_series": [...]
}
}
| Field | Description |
|---|---|
comparison | Raw metrics from the comparison period |
deltas | Percentage change from comparison to current |
comparison_time_series | Daily data points for the comparison period |
List Endpoints
Paginated list endpoints include comparison totals:
{
"data": [
{
"utm_source": "google",
"entrances": 8500,
"conversions": 95,
"revenue": 7600.00
},
{
"utm_source": "facebook",
"entrances": 3200,
"conversions": 42,
"revenue": 3150.00
}
],
"total": 25,
"page": 1,
"page_size": 50,
"has_next": false,
"has_prev": false,
"comparison": {
"entrances": 10500,
"engaged_entrances": 8400,
"page_views": 31500,
"conversions": 115,
"revenue": 9200.00
}
}
The comparison object contains aggregate totals for the comparison period (not per-row comparisons).
Calculating Deltas
The API returns comparison data; you calculate deltas client-side:
function calculateDelta(current, previous) {
if (previous === 0) return current > 0 ? 100 : 0;
return ((current - previous) / previous) * 100;
}
// Example
const currentEntrances = response.data.entrances;
const previousEntrances = response.data.comparison.entrances;
const delta = calculateDelta(currentEntrances, previousEntrances);
// Result: 8.59 (8.59% increase)
Delta Interpretation
| Delta | Meaning |
|---|---|
+15.2% | 15.2% increase vs comparison period |
-8.5% | 8.5% decrease vs comparison period |
0% | No change |
N/A | No comparison data available |
Metric Polarity
Some metrics are "inverse" - lower is better:
| Metric | Improvement Direction |
|---|---|
| Entrances | Higher is better |
| Conversions | Higher is better |
| Revenue | Higher is better |
| Bounce Rate | Lower is better |
When displaying deltas, consider inverting colors for bounce rate.
Endpoints Supporting Comparison
| Endpoint | Default | Notes |
|---|---|---|
/stats/overview | previous | Full comparison with time series |
/stats/pages | none | Totals only |
/stats/sources | none | Totals only |
/stats/mediums | none | Totals only |
/stats/campaigns | none | Totals only |
/stats/terms | none | Totals only |
/stats/referrers | none | Totals only |
/stats/geo/countries | none | Totals only |
/stats/conversions | none | Totals only |
/stats/microconversions | none | Totals only |
/stats/landing-pages | none | Totals only |
Date Period + Comparison
The comparison period is calculated based on the selected date range:
With Period Shortcuts
| Period | Current Range | Previous Comparison | YoY Comparison |
|---|---|---|---|
7d | Last 7 days | Previous 7 days | Same 7 days last year |
30d | Last 30 days | Previous 30 days | Same 30 days last year |
this_month | Month to date | Same days in previous month | Same days in previous year |
last_month | Full previous month | Month before that | Same month last year |
this_quarter | Quarter to date | Same days in previous quarter | Same days in previous year |
ytd | Year to date | Same days in previous year | N/A (same as period) |
With Custom Dates
GET /stats/overview?site_id=my-site&start_date=2025-01-01&end_date=2025-01-15&compare=previous
| Dates | |
|---|---|
| Current | Jan 1-15, 2025 (15 days) |
| Previous | Dec 17-31, 2024 (15 days) |
| YoY | Jan 1-15, 2024 |
Edge Cases
Leap Years
For YoY comparison on February 29:
- 2024-02-29 (leap year) → 2023-02-28 (non-leap year)
The API automatically adjusts to February 28.
New Accounts
If the comparison period is before the account existed:
{
"comparison": {
"entrances": 0,
"conversions": 0,
"revenue": 0.00
}
}
All comparison values will be zero.
Missing Data Days
If some days in the comparison period have no data, those days contribute zero to totals. This is normal and doesn't indicate an error.
Code Examples
Python - Calculate All Deltas
import requests
def get_stats_with_comparison(site_id, period="30d", compare="previous"):
response = requests.get(
"https://api.sealmetrics.com/api/v1/stats/overview",
headers={"X-API-Key": API_KEY},
params={
"site_id": site_id,
"period": period,
"compare": compare
}
)
return response.json()["data"]
def calculate_delta(current, previous):
if previous == 0:
return 100.0 if current > 0 else 0.0
return round(((current - previous) / previous) * 100, 2)
# Get data
data = get_stats_with_comparison("my-site", "30d", "previous")
comparison = data["comparison"]
# Calculate deltas
metrics = ["entrances", "conversions", "revenue", "bounce_rate"]
for metric in metrics:
current = data[metric]
previous = comparison[metric]
delta = calculate_delta(current, previous)
# Invert display for bounce_rate (lower is better)
if metric == "bounce_rate":
direction = "improved" if delta < 0 else "worsened"
else:
direction = "up" if delta > 0 else "down"
print(f"{metric}: {current} ({delta:+.1f}% {direction})")
JavaScript - Display Comparison Card
async function fetchWithComparison(accountId, period, compare = 'previous') {
const params = new URLSearchParams({
site_id: accountId,
period,
compare
});
const response = await fetch(
`https://api.sealmetrics.com/api/v1/stats/overview?${params}`,
{ headers: { 'X-API-Key': API_KEY } }
);
return response.json();
}
function formatDelta(current, previous, inverse = false) {
if (previous === 0) {
return current > 0 ? '+∞' : '0%';
}
const delta = ((current - previous) / previous) * 100;
const formatted = `${delta >= 0 ? '+' : ''}${delta.toFixed(1)}%`;
// For inverse metrics (bounce_rate), flip the color logic
const isPositive = inverse ? delta < 0 : delta > 0;
return {
text: formatted,
color: isPositive ? 'green' : delta < 0 ? 'red' : 'gray'
};
}
// Usage
const { data } = await fetchWithComparison('my-site', '30d', 'yoy');
const entrancesDelta = formatDelta(
data.entrances,
data.comparison.entrances
);
console.log(`Entrances: ${data.entrances} (${entrancesDelta.text})`);
const bounceDelta = formatDelta(
data.bounce_rate,
data.comparison.bounce_rate,
true // inverse = true for bounce rate
);
console.log(`Bounce Rate: ${data.bounce_rate}% (${bounceDelta.text})`);
Build Trend Analysis
def analyze_trend(site_id, periods=["7d", "30d", "90d"]):
"""Analyze trends across multiple time periods."""
results = {}
for period in periods:
data = get_stats_with_comparison(site_id, period, "previous")
results[period] = {
"entrances": {
"current": data["entrances"],
"delta": calculate_delta(
data["entrances"],
data["comparison"]["entrances"]
)
},
"revenue": {
"current": data["revenue"],
"delta": calculate_delta(
data["revenue"],
data["comparison"]["revenue"]
)
}
}
return results
# Output
trends = analyze_trend("my-site")
for period, metrics in trends.items():
print(f"\n{period}:")
print(f" Entrances: {metrics['entrances']['current']} ({metrics['entrances']['delta']:+.1f}%)")
print(f" Revenue: €{metrics['revenue']['current']} ({metrics['revenue']['delta']:+.1f}%)")
Best Practices
Choosing Comparison Mode
| Scenario | Recommended Mode |
|---|---|
| Daily monitoring | previous |
| Weekly review | previous |
| Monthly reporting | yoy (seasonal) or previous |
| Campaign analysis | previous (vs pre-campaign) |
| Seasonal business | yoy |
| Growth tracking | previous |
Handling Zero Baselines
When previous period has zero values:
if (previous === 0) {
// Don't show percentage, show absolute change
return current > 0 ? `+${current} (new)` : 'No data';
}
Caching Comparison Data
Comparison calculations are more expensive than single-period queries. Consider:
- Cache comparison results longer (data won't change)
- Fetch comparison data less frequently than real-time data
- Pre-calculate and store daily comparison summaries