# Consent changes

**Summary:** Consent changes counts updated consent records using their latest saved status, not every change made to those records.

- Role: [Technical Support](https://www.subrite.no/technical-support)
- Source: https://www.subrite.no/technical-support/insights-consent-changes
- Updated: 2026-09-28
- Markdown index: https://www.subrite.no/technical-support/llms.txt

<a id="collection-and-category-rules"></a>
## Collection and category rules

`processAndSaveConsentActivitySummary` selects nondeleted `MemberConsent` rows whose `updatedAt` falls within the reporting day. The consent join supplies tenant scope.

The writer uses `dataDate` when supplied, otherwise yesterday. `DateUtil` provides the configured timezone's day boundaries. Counts use each row's current status and the gap between its `createdAt` and `updatedAt`.

| Stored count | Condition |
| --- | --- |
| `newlyAccepted` | Accepted, update within 60 seconds of creation |
| `reaccepted` | Accepted, update more than 60 seconds after creation |
| `newlyWithdrawn` | Withdrawn, update within 60 seconds of creation |
| `rewithdrawn` | Withdrawn, update more than 60 seconds after creation |

`reaccepted` does not require a previous withdrawal. An older row updated while accepted can enter that category. [Source: collection predicates](https://github.com/subrite/subrite-crm/blob/6cd1850569be3b1702ca736a19320c7626efb7bc/api-server/src/modules/stats/services/stats-store.service.ts#L779-L895).

For example, accepting then withdrawing the same consent on one day can yield one withdrawn record here. [Consent source](https://www.subrite.no/technical-support/insights-consent-source?md=true) can count both history events.

The collector checks for any existing summary for that tenant and `dateOfRecord`, then returns early if found. Rerunning collection does not automatically refresh that day's counts.

<a id="query-signs-and-consent-selection"></a>
## Query, signs and consent selection

`historical-consent-activity` sums summary fields by `dateOfRecord` and period. It filters tenant and nondeleted summaries.

- `newlyAccepted` becomes **Subscribed**, positive.
- `reaccepted` becomes **Subscribed - again**, positive.
- `newlyWithdrawn + rewithdrawn` becomes **Unsubscribed**, multiplied by −1.

No member-level distinct count is applied. Several consent types belonging to one member contribute separately. [Source: aggregation](https://github.com/subrite/subrite-crm/blob/6cd1850569be3b1702ca736a19320c7626efb7bc/api-server/src/modules/stats/repositories/consent-activity-summary.repository.ts#L40-L96).

The frontend parses comma-separated `consentIds`. Missing or empty IDs default to currently active consent IDs in the service.

The repository adds its `IN` filter only for a nonempty array. If no active IDs exist, that default becomes an unfiltered consent query within the tenant. Historical inactive types can therefore remain in results. This differs from Consents, whose empty-active-ID guard returns no rows. [Source: default selection](https://github.com/subrite/subrite-crm/blob/6cd1850569be3b1702ca736a19320c7626efb7bc/api-server/src/modules/stats/services/stats.services.ts#L602-L619).

<a id="net-change-and-percentages"></a>
## Net change and percentages

Net change = newly accepted + reaccepted − newly withdrawn − rewithdrawn.

With 8 additions and 3 withdrawals, the net is 5. The withdrawal share is 3/11 because tooltip shares use absolute visible values, not the signed net.

The Details tooltip total sums visible signed values. Net change sums all returned categories, including hidden ones. Shared positional legend state can hide the combined bar after switching views; restore all categories before comparing. [Source: tooltip and combined arithmetic](https://github.com/subrite/subrite-crm/blob/6cd1850569be3b1702ca736a19320c7626efb7bc/frontend/src/ui/StatsView/index.tsx#L182-L246).

<a id="dates-and-discrepancy-checks"></a>
## Dates and discrepancy checks

The weekly default covers the last 12 weeks. Daily windows stop yesterday; coarser periods include the unfinished current bucket. Requested windows are capped at 550 buckets. Activity uses the day summarized; Consents snapshots use summary creation time.

- A change is missing: compare the record's current status and `updatedAt` with the reporting window. Later updates can move it outside that window.
- Too many “again” records: compare `updatedAt - createdAt` with 60 seconds. The category does not inspect prior history.
- Results remain with no active consents: inspect the resolved `consentIds` and the empty-array behavior above.
- Totals disagree with Consent source: compare mutable rows here with the separate history events there.
- Blank graph: check the API response and category values. Invalid responses render empty; zero values become `null`.

The chart translates the 3 returned field names; it does not plot each consent type separately. [Sources: chart mapping](https://github.com/subrite/subrite-crm/blob/6cd1850569be3b1702ca736a19320c7626efb7bc/frontend/src/app/%28admin%29/admin/%28panel%29/analytics/statistics/consent-changes/ConsentChangeStats/index.tsx#L40-L120), [timeline bounds](https://github.com/subrite/subrite-crm/blob/6cd1850569be3b1702ca736a19320c7626efb7bc/frontend/src/app/%28admin%29/admin/%28panel%29/analytics/statistics/utils/timeline/resolveTimelineWindow.ts#L53-L185).

The endpoint requires Dashboard read permission; the menu also depends on Analytics access and Insights. [Source: endpoint gate](https://github.com/subrite/subrite-crm/blob/6cd1850569be3b1702ca736a19320c7626efb7bc/api-server/src/modules/stats/controllers/stats.controller.ts#L373-L381).

<a id="sources-and-verification"></a>
## Sources and verification

Source checked 28 September 2026 at `6cd1850569be3b1702ca736a19320c7626efb7bc`. Prior UI evidence confirms navigation and the heading **Consents changes**. No fresh UI, numeric reconciliation, empty-selection or ordinary-role test was performed.

For graph interpretation and controls, see [Consent changes](https://www.subrite.no/administrators/insights-consent-changes?md=true).

## Related pages

- [Consent changes](https://www.subrite.no/administrators/insights-consent-changes?md=true): Consent changes counts updated consent records using their latest saved status, not every change made to those records.
