#3198·listmonk

Inconsistent analytics counts between campaign endpoint and analytics endpoints

Author: officina-musciCreated Aug 21, 2026Updated Sep 10, 2026

Version:

Description of the bug and steps to reproduce:

I am experiencing inconsistent counts when retrieving analytics data for a campaign via the Listmonk API. The totals reported by the campaign endpoint (GET /api/campaigns/{campaign_id}) do not match the aggregated totals from the analytics endpoints (GET /api/campaigns/analytics/{type}), even though the same time range (from campaign start date to today) is used for all requests.

I know that the campaign endpoint is not an analytics endpoint, so it does not take date parameters. However, the date range used in the analytics endpoints should cover the same period as the campaign, and therefore the totals should be consistent across all endpoints.


Endpoints Tested

1. Campaign Endpoint

Request:

GET /api/campaigns/{campaign_id}

Response:

json
{
  "id": {campaign_id},
  "created_at": {timestamp},
  "updated_at": {timestamp},
  "views": 903,
  "clicks": 393,
  "bounces": 0,
  "lists": [...],
  "media": [],
  "started_at": {timestamp},
  ...
}

Reported totals:

  • Views: 903
  • Clicks: 393

2. Views Analytics Endpoint

Request:

GET /api/campaigns/analytics/views?id={campaign_id}&from={campaign_started_at_date}&to={now_date}

Response:

json
[
  { "campaign_id": {campaign_id}, "count": 250, "timestamp": {timestamp} },
  { "campaign_id": {campaign_id}, "count": 55, "timestamp": {timestamp} },
  { "campaign_id": {campaign_id}, "count": 23, "timestamp": {timestamp} },
  { "campaign_id": {campaign_id}, "count": 5, "timestamp": {timestamp} },
  { "campaign_id": {campaign_id}, "count": 4, "timestamp": {timestamp} },
  { "campaign_id": {campaign_id}, "count": 1, "timestamp": {timestamp} },
  { "campaign_id": {campaign_id}, "count": 2, "timestamp": {timestamp} },
  { "campaign_id": {campaign_id}, "count": 5, "timestamp": {timestamp} },
  { "campaign_id": {campaign_id}, "count": 1, "timestamp": {timestamp} },
  { "campaign_id": {campaign_id}, "count": 2, "timestamp": {timestamp} },
  { "campaign_id": {campaign_id}, "count": 5, "timestamp": {timestamp} }
]

Calculated total:

  • Views: 353 (250 + 55 + 23 + 5 + 4 + 1 + 2 + 5 + 1 + 2 + 5)

3. Clicks Analytics Endpoint

Request:

GET /api/campaigns/analytics/clicks?id={campaign_id}&from={campaign_started_at_date}&to={now_date}

Response:

json
[
  { "campaign_id": {campaign_id}, "count": 111, "timestamp": {timestamp} },
  { "campaign_id": {campaign_id}, "count": 38, "timestamp": {timestamp} },
  { "campaign_id": {campaign_id}, "count": 12, "timestamp": {timestamp} },
  { "campaign_id": {campaign_id}, "count": 9, "timestamp": {timestamp} },
  { "campaign_id": {campaign_id}, "count": 1, "timestamp": {timestamp} },
  { "campaign_id": {campaign_id}, "count": 2, "timestamp": {timestamp} },
  { "campaign_id": {campaign_id}, "count": 4, "timestamp": {timestamp} },
  { "campaign_id": {campaign_id}, "count": 1, "timestamp": {timestamp} },
  { "campaign_id": {campaign_id}, "count": 2, "timestamp": {timestamp} }
]

Calculated total:

  • Clicks: 180 (111 + 38 + 12 + 9 + 1 + 2 + 4 + 1 + 2)

4. Links Analytics Endpoint

Request:

GET /api/campaigns/analytics/links?id={campaign_id}&from={campaign_started_at_date}&to={now_date}

Response:

json
[
  { "url": {link_url}, "count": 174 },
  { "url": {link_url}, "count": 52 }
]

Calculated total:

  • Link clicks: 226 (174 + 52)

Inconsistencies

Comparison with campaign endpoint totals:

Metric Campaign Endpoint Analytics Endpoint Discrepancy
Views 903 353 -550
Clicks 393 180 -213
Link clicks 393 226 -167

The analytics endpoints return significantly lower counts than the campaign endpoint for the same campaign and time range. This inconsistency affects the reliability of the data provided by the API.

Comparison between analytics endpoints:

Metric Clicks Analytics Endpoint Links Analytics Endpoint Discrepancy
Clicks 180 226 +46

The clicks reported by the links analytics endpoint exceed those reported by the clicks analytics endpoint, which is unexpected since link clicks should be a subset of total clicks.

Expected Behaviour

The totals from the analytics endpoints should match the totals reported in the campaign endpoint and be consistent across all analytics endpoints for the same campaign and time range.