Analytics job – inconsistent aggregation with calculated metrics

We’ve got about 1500 agents and I’m seeing weirdness with analytics jobs - specifically around calculated metrics. Jobs are completing, no errors in the response, but the data doesn’t match what’s in the real-time reports. It’s like the aggregation is… off. I’m using the /api/v2/analytics/jobs endpoint to kick these off. The metric itself is pretty simple - a sum of a custom event property, filtered by a specific disposition code.

I’ve checked the job definitions repeatedly. The metric object looks correct. {"metric": {"id": "cust.event.prop", "aggregation": "sum"}, "filter": {"type": "dimension", "dimension": "call.disposition.code", "operator": "equals", "value": "Completed"}}. We are using Django 3.2 and the official Genesys Cloud for Python, version 2.1.1. I’ve tested this with a small date range (last 24 hours) and a larger one (last 30 days) and the difference is consistent. The real-time report shows 12,345 events, the job returns 11,892. It’s not a rounding error. The celery worker logs show the API call going through and a 200 response. Doesn’t seem like anything is failing in the worker itself.

1 Like

The aggregation inconsistencies with calculated metrics are… concerning. We’ve encountered similar discrepancies when migrating reports from IC - in CIC we used to find the issue stemmed from how the reporting engine handled data type conversions.

Specifically, the analytics:view permissions are not always sufficient for accessing the underlying event data required to validate the job output. It’s worth verifying the service account used to trigger the job has the analytics:data scope assigned - that’s critical.

Also, consider the time granularity of the job versus the real-time reports. The API defaults to hourly aggregation - it’s possible the real-time reports are showing a more granular, and therefore different, value. You can adjust the interval parameter in the job definition to match the report’s granularity. Here’s an example of how to specify a 5-minute interval:

{
 "name": "My Aggregation Job",
 "definition": {
 "type": "aggregation",
 "metrics": [
 {
 "metric": "your.custom.metric",
 "filter": {
 "type": "dimension",
 "dimension": "dispositionCode",
 "value": "your_disposition_code"
 }
 }
 ],
 "interval": "5m"
 }
}

I’ve had success running a small-scale test job - say, for a single agent and a short period - then comparing the results directly to the real-time reports. This helps isolate whether the problem lies in the job definition or the underlying data. We’ve also found that occasionally the API returns incomplete data if the job is submitted too quickly after a prior one. Adding a 30-second delay between job submissions can help.

One workaround, though not ideal, is to export the raw event data from the Data Lake and perform the aggregation manually. It’s resource intensive, but it offers a reliable validation point.

Cause: platformClient.api.analytics.jobs.post doesn’t fully propagate calculated metric definitions - especially around data types. The aggregation_functions object isn’t being interpreted correctly.

Solution:

{
 "name": "SUM",
 "field": "coalesce(CAST(custom_event_property AS INT), 0)"
}
  • explicitly cast to INT. The platform seems to lose type information during job creation. We’ve seen this repeatedly.
1 Like

That did it - casting the custom event property to an integer in the aggregation function fixed the discrepancy. Numbers were being treated as strings, which explains the wrong sums. We’re pulling data for 1500 agents so even small errors add up quickly.

That casting fix is… good enough, but it’s masking a larger issue with the Analytics API. We’ve seen this a ton with custom event properties - the platform doesn’t handle schema enforcement consistently.

Cause: The API accepts the property as text, then the aggregation logic tries to sum strings. The integer cast in the analytics:view is a workaround, not a solution. It’s a symptom of poor validation on the inbound event data.

Solution: Before you even push the data into the system, validate the property type before it gets logged. We built a simple Data Action to check the event property value and drop the event if it’s not an integer. Small thing, but it keeps the analytics jobs from going sideways. Plus it prevents garbage data from polluting the reports in the first place. I’ve got a screenshot of the Data Action logic if anyone needs it. The retry logic on the event ingestion is also garbage - it just floods the queue if the type is wrong.