Data Retention Policy

The Data Retention Policy feature allows you to automatically clean up old messages and inactive channels from your application. This helps you manage storage costs, comply with data governance requirements, and keep your application focused on relevant, recent data.

Warning:

Data retention cleanup permanently deletes data. Deleted messages, channels, and their associated data (reactions, attachments, members, etc.) cannot be recovered. Make sure you understand the implications before enabling retention policies.

Overview

Stream Chat supports two types of retention policies:

  • Old Messages (old-messages): Automatically deletes messages older than a specified age.
  • Inactive Channels (inactive-channels): Automatically deletes channels that have been inactive for longer than a specified period. A channel is considered inactive based on the most recent of its created_at, updated_at, or last_message_at timestamps.

Key characteristics:

  • Retention policies can be configured at the app level using server-side API calls or directly from the Stream Dashboard under your app's Chat settings
  • The API is server-side only — all endpoints require authentication with a server-side API key
  • Data is hard-deleted, not archived — deleted data cannot be recovered
  • Minimum retention age is 24 hours, maximum is 5 years (43,800 hours)
  • A 24-hour grace period applies after enabling or updating a policy before any cleanup begins
  • Cleanup runs asynchronously in the background — after enabling a policy, it may take hours or even days for all eligible data to be removed depending on the volume of data. During this period, expired data may still appear in API responses
  • Both policy types can be active simultaneously
  • When a policy is enabled or updated, email notifications are sent to all admin team members
  • Retention policy settings and cleanup run history are visible in the Stream Dashboard

How Long Messages Are Kept by Default

If no retention policy is configured, messages and channels are kept indefinitely. There is no default expiry, and nothing ages out on its own until you enable one of the policies above.

Data is only deleted because you asked for it, either through a retention policy or through an explicit delete call.

Who Can Change a Retention Policy

Retention policies can only be changed with your app's server-side credentials:

  • The retention endpoints are server-side only. They cannot be called with a client-side token, whatever role the user has.
  • Or from your app's Chat settings in the Stream Dashboard, which requires access to your Stream organization.

There is no per-user permission for retention. Who can change it is governed by who holds your server-side API secret and who has dashboard access.

Two bounds apply to every value and cannot be overridden through the API. The minimum is 24 hours and the maximum is 5 years (43,800 hours).

Contact support if your compliance requirements need a longer window. The ceiling can be raised per organization.

Note:

Retention policy changes are not currently recorded in an audit log.

The dashboard and the getRetentionPolicy endpoint show the current configuration and when it was last updated (enabled_at). The run history shows what each cleanup deleted. Neither records who made a change, or what the previous value was.

Keep your own record at the point where you call the API if you need a change history for compliance.

Confirming a Deletion Has Completed

Cleanup is asynchronous and paced, so a policy does not take effect immediately. See the 24-hour grace period and background processing described above.

Use the cleanup run history to confirm progress. Each run reports how many messages and channels it deleted.

Runs returning counts mean cleanup is working through your data. Contact support if the backlog stays flat across several runs.

Deletion and Backups

Deleted data is removed permanently from Stream's live systems and cannot be recovered through the API. This applies both to retention policy cleanup and to explicit hard deletes.

Stream also keeps operational backups for disaster recovery, as any production system does. Deleting data does not rewrite backups taken before the deletion.

Those copies expire on their own schedule, independently of your retention settings and your delete calls. Contact support if you have a regulatory requirement that depends on the exact backup window.

Setting a Retention Policy

To enable automatic cleanup, create a retention policy by specifying the policy type and the maximum age in hours.

// Delete messages older than 6 months (4,380 hours)
var response = await client.Chat.SetRetentionPolicyAsync(
    new SetRetentionPolicyRequest
    {
        Policy = "old-messages",
        MaxAgeHours = 4380,
    });

// Delete channels inactive for more than 6 months
response = await client.Chat.SetRetentionPolicyAsync(
    new SetRetentionPolicyRequest
    {
        Policy = "inactive-channels",
        MaxAgeHours = 4380,
    });

Request Parameters

Field Type Description Required
policy string The policy type: old-messages or inactive-channels Yes
max_age_hours integer Maximum age in hours before data is eligible for deletion. Must be between 24 and 43,800 (5 years). Yes
Info:

If a policy already exists for the specified type, calling this endpoint again will update the existing policy with the new max_age_hours value.

Retrieving Retention Policies

Retrieve all active retention policies for your application.

var response = await client.Chat.GetRetentionPolicyAsync();
Note:

Cleanup run history is automatically pruned after 6 months. Runs older than 180 days are deleted at the end of each cleanup cycle. If you need long-term retention audit records, export the run history periodically using this endpoint.

Deleting a Retention Policy

Remove a retention policy to stop automatic cleanup for that policy type. Data that has already been deleted cannot be recovered.

var response = await client.Chat.DeleteRetentionPolicyAsync(
    new DeleteRetentionPolicyRequest
    {
        Policy = "old-messages",
    });

Viewing Cleanup Run History

You can query the history of retention cleanup runs using filters and sorting. This is useful for verifying that cleanup is working as expected and understanding how much data has been removed.

var response = await client.Chat.GetRetentionPolicyRunsAsync(
    new GetRetentionPolicyRunsRequest
    {
        FilterConditions = new Dictionary<string, object>
        {
            { "policy", new Dictionary<string, object> { { "$eq", "old-messages" } } }
        },
        Sort = new List<SortParamRequest>
        {
            new SortParamRequest { Field = "date", Direction = -1 }
        },
        Limit = 10,
    });

Request Parameters

Parameter Type Description
filter_conditions object Filter runs by policy ("old-messages" or "inactive-channels") and/or date (e.g., {"$gte": "2026-01-01"})
sort array Sort by policy or date. Each entry has field and direction (-1 for descending, 1 for ascending)
limit integer Number of runs to return per page (default: 25)
next string Cursor for the next page of results (from previous response)
prev string Cursor for the previous page of results (from previous response)
Info:

The runs endpoint uses cursor-based pagination. Use the next and prev cursors returned in the response to navigate between pages. Only one of next or prev can be specified at a time.