
See what changed in any saved filter or JQL query, on a dashboard or on its own page.
Filter Activity Stream is a Forge app for Jira Cloud. It adds two places to read the stream.
It shows five kinds of events.
| Event | Source in Jira | Example line |
|---|---|---|
| Created | issue created + creator | Alice Ng created the issue |
| Transitioned | changelog item status | Bob Ray changed status from To Do to In Progress |
| Commented | issue comments (first 280 characters as plain text) | Bob Ray commented: Keys rotated in staging |
| Assigned | changelog item assignee | Alice Ng assigned to Alice Ng (was Bob Ray) |
| Field changed | every other changelog item (priority, labels, custom fields, …) | Alice Ng set labels to security |
Board re-ranking ("Rank" changes) is left out. It's drag-and-drop noise.
Point it at any saved filter or JQL. Pick one of your starred filters, type a filter ID or an exact filter name, or write JQL. An ORDER BY in your JQL is ignored, because the stream is always newest first.
Then narrow it down.
CSV export covers all loaded events, with UTC time, local time, issue, summary, event, actor, field, from, to and comment excerpt. The CSV opens in a dialog for you to copy into a spreadsheet, since UI Kit apps can't start a file download. Cells that start with =, +, -, @, tab or CR get a leading ', so spreadsheets don't run them as formulas. The export is limited to 2 MB.
When a limit is hit, a warning says which one. For example "Showing the newest 2,000 of 2,345 events."
Every Jira call runs as the person viewing the gadget. So restricted comments and issues they can't browse never appear, and the cache is per user.
| What | Limit | When it is reached |
|---|---|---|
| Issues scanned per refresh | 500, most recently updated first | A warning asks you to narrow the filter or the time window |
| Events kept per refresh | 2,000, newest first | Warning shows the true total |
| Time window | up to 30 days | Not selectable beyond 30 days |
| Loading time | about 20 s, then partial results | A warning says "Jira was slow…" |
| Issues with long change histories | the full history is read newest first for up to 100 issues per refresh, at most the newest 300 changes each | Warning names how many issues may be missing recent changes |
| Issues with many comments | extra comments are fetched for up to 100 issues (5 pages each) | A warning says "Not every comment was loaded…" |
| JQL length | 2,000 characters | Settings error |
| People filter | 20 people | Settings error |
| Cache | 5 minutes per user and query, up to 6.4 MB per result (2,000 events always fit unless the text is mostly control characters) | "Refresh" bypasses it once the result is at least 15 s old. If a result cannot be cached, a notice says that paging and export reload it from Jira |
| CSV export | 2 MB | Dialog says how many rows were included |
Dashboard gadget / global page (UI Kit, render: native)
└─ invoke('getActivity' | 'exportCsv' | 'listFilters' | 'getPageConfig' | 'savePageConfig')
└─ resolver (src/index.js → src/lib/service.js)
├─ Forge KVS cache (key = sha256(accountId + query); 5-minute TTL)
└─ api.asUser().requestJira(...)
1. POST /rest/api/3/search/jql
jql = (<filter or JQL>) AND updated >= -<window>m ORDER BY updated DESC
fields = summary, created, creator, reporter, updated [, comment]
expand = changelog (only when change events are wanted)
pages of 100 via nextPageToken, at most 500 issues
2. GET /rest/api/3/issue/{id}/changelog (only for issues whose embedded changelog is partial;
Jira returns it oldest first, so the app reads the
last page first and walks back to the window start;
up to 100 issues, 3 pages of 100 each, 4 in parallel)
3. GET /rest/api/3/issue/{id}/comment?orderBy=-created (only when the embedded comments are
partial; 4 in parallel; stops at the window start)
→ events: dedupe by id, filter by window/type/person, sort newest first, cap at 2,000
Each event has a stable id, so duplicates collapse. Changelog items use h:<historyId>:<field>:<n>, comments use c:<commentId> and creation uses n:<issueId>. The same history or comment can come from the search and from a follow-up call, and you'll see it once.
The stream is newest first. When events share a timestamp, an issue's creation is listed below the edits made with it. After that, events are ordered by type (transition, assignment, field change, comment) and then by id, so the order is the same on every refresh.
Filter names are quoted and escaped as JQL strings (" → \", \ → \\), and numeric IDs are used as-is. Before your JQL is wrapped in ( … ), the app checks it for balanced parentheses and quotes. That check follows JQL's backslash escapes inside and outside quotes, and it refuses a backslash outside quotes that isn't followed by a character. So your JQL can't close the wrapper early. It always runs with your own Jira permissions, and paths sent to Jira come from a fixed allow-list (numeric issue IDs only).
Jira errors become plain messages. Bad JQL shows Jira's own explanation, and 403 or 404 says you lack permission or the filter is missing or not shared with you. The app retries 429 and 503 twice using Retry-After (at most 3 s per wait), within the time budget. If a follow-up call for change history or comments fails, even with a timeout or network error, the stream still shows with a warning. Forge's "allow access" (user consent) error passes through untouched, so Jira can show its consent prompt.
| Scope | Why |
|---|---|
read:jira-work | Search issues, read changelogs, comments and your starred filters |
read:jira-user | Names and avatars of people in the stream and the people picker |
storage:app | The 5-minute result cache and the global page's saved settings |
The app has no external permissions, no remote back end and no egress. All code runs on Atlassian's Forge platform, so it's built to qualify for Runs on Atlassian. Atlassian decides eligibility, and you can check it with forge eligibility after deploying.
PRIVACY.md lists what is stored and for how long.
Zovo builds and maintains this app. If it saves you time, you can support the work on GitHub Sponsors. Sponsorship is optional, and the tool works the same without it.
Zovo is made by theluckystrike on GitHub.
MIT, see LICENSE.
If this app saves you time, you can support the work on GitHub Sponsors. Monthly tiers start at $5, and one-time tiers start at $15. Sponsorship is optional, and the tool works the same without it.