Data Retention

Data retention policies automatically delete old activities from your app. Use them to manage storage, meet data governance requirements, and keep feeds focused on recent content.

Warning:

Retention deletes activities, together with their comments, reactions, and bookmarks. Deleted activities are backed up for 60 days and can be restored by contacting support. After that, they cannot be recovered.

Overview

  • If you set no policy, activities are kept forever. Nothing ages out on its own.
  • A policy deletes activities older than the age you choose, measured from the activity's created_at.
  • A policy covers all activities in the app, or only activities posted to the feed groups you list. An app can have up to 20 policies.
  • Policies are managed with server-side API calls, or under Feeds > Settings > Retention policy for your app in the Stream Dashboard.
  • The minimum age is 24 hours and the maximum is 5 years (43,800 hours). Contact support if your compliance requirements need a longer window.
  • A 24-hour grace period applies after you set or update a policy before anything is deleted, so a mistaken change can be reverted.
  • Cleanup runs in the background. Depending on how much data is eligible, it can take hours or days to remove everything, and expired activities may still appear in API responses until then.
  • When a policy is set or updated (unless retention is paused), an email is sent to your organization's admins.

Policies

Each policy has a name you choose (policy), up to 64 letters, numbers, dashes, or underscores.

  • old-activities is the app-wide policy. It always covers every feed group.
  • Any other name creates a policy limited to the feed groups you list in feed_groups. Pass an empty list to cover all feed groups.

For example, to keep stories for 30 days and everything else for a year, set old-activities to one year and a policy named stories to 30 days, scoped to the stories feed group. An activity is deleted as soon as any policy that covers it says it is old enough.

Info:

A scoped policy matches the feeds an activity was posted to (the feeds in its feeds list), not the timelines it reaches through follows. Scope a policy to the feed groups your activities are actually posted into, such as user or stories. A policy scoped to a group that only receives activities through follows, such as timeline, matches nothing.

What gets deleted

When an activity is deleted by retention:

  • Its comments, reactions (on the activity and on its comments), bookmarks, and pins are deleted with it.
  • It is removed from every feed it was posted to and from followers' timelines.
  • Activities that share it (activities with it as their parent_id) are not deleted. They have their own age and are deleted once they pass it, and until then they are returned without the shared activity.
  • Activities that were already soft-deleted are skipped.

Setting a retention policy

Setting a policy creates it, or updates it if a policy with that name already exists. Updating a policy restarts its 24-hour grace period.

// Delete all activities older than one year (8,760 hours)
feeds.feedsSetRetentionPolicy(
    FeedsSetRetentionPolicyRequest.builder()
        .policy("old-activities")
        .maxAgeHours(8760)
        .build())
    .execute();

To limit a policy to some feed groups, give it a name of your own and list the groups in feed_groups:

Node.js
// Delete activities posted to stories feeds after 30 days (720 hours)
await client.feeds.feedsSetRetentionPolicy({
  policy: "stories",
  max_age_hours: 720,
  feed_groups: ["stories"],
});

Request parameters

Field Type Description Required
policy string The policy name. old-activities is the app-wide policy; any other name is a policy of your own. Yes
max_age_hours integer Age in hours after which an activity is deleted. Between 24 and 43,800 (5 years). Yes
feed_groups string[] The feed groups the policy covers, up to 20. Each must exist in your app. An empty list covers all feed groups. Not allowed for old-activities. For a new policy of your own
enabled boolean false saves the policy without deleting anything. See Pausing retention. Defaults to true. No

Pausing retention

Retention can be paused for the whole app without deleting your policies. Pass enabled: false when you set a policy:

feeds.feedsSetRetentionPolicy(
    FeedsSetRetentionPolicyRequest.builder()
        .policy("old-activities")
        .maxAgeHours(8760)
        .enabled(false)
        .build())
    .execute();
Warning:

Pausing and resuming apply to every policy in the app. Setting any policy without enabled: false resumes retention for all of them, and each one starts a new 24-hour grace period.

Retrieving retention policies

The response lists the app's policies and whether retention is enabled.

GetFeedsRetentionPolicyResponse response =
    feeds.feedsGetRetentionPolicy().execute().getData();

Deleting a retention policy

Deleting a policy stops it, but does not bring back activities it already deleted. To restore those, contact support within the 60-day backup window. Deleting the last policy turns retention off for the app.

feeds.feedsDeleteRetentionPolicy(
    FeedsDeleteRetentionPolicyRequest.builder()
        .policy("stories")
        .build())
    .execute();

Viewing cleanup run history

Each cleanup run reports how many activities it deleted, per policy and day. Use it to confirm that cleanup is working through your data. Runs reporting deletions mean cleanup is progressing. Contact support if the backlog stays flat across several days.

GetFeedsRetentionPolicyRunsResponse response = feeds.feedsGetRetentionPolicyRuns(
    FeedsGetRetentionPolicyRunsRequest.builder()
        .filterConditions(Map.of("policy", Map.of("$eq", "stories")))
        .sort(List.of(SortParamRequest.builder()
            .field("date")
            .direction(-1)
            .build()))
        .limit(10)
        .build())
    .execute()
    .getData();
Parameter Type Description
filter_conditions object Filter by policy and/or date (for example {"date": {"$gte": "2026-01-01"}})
sort array Sort by policy or date. Each entry has field and direction (-1 descending, 1 ascending)
limit integer Number of runs per page
next string Cursor for the next page, from the previous response
prev string Cursor for the previous page, from the previous response

Run history is kept for 6 months. Export it periodically if you need a longer record.

Deletion and backups

Before each cleanup run deletes a batch, Stream backs up the activities and the data deleted with them. These backups are kept for 60 days, and support can restore from them within that window. After 60 days they are deleted and the data cannot be recovered.

Stream's operational backups for disaster recovery are separate and expire on their own schedule. Contact support if you have a regulatory requirement that depends on the exact backup window.