Privacy policy — Outlier
This is written from the architecture rather than from a template. The source is not public, so the honest version of that claim is narrower than it sounds: what you can check is the method page, which prints the whole arithmetic, and the app's Forge manifest, which Atlassian shows you before installing and which either declares an external host or does not.
Last reviewed: 2026-09-19.
Who this covers
Outlier is a Jira dashboard gadget built on Atlassian Forge, to be distributed through the Atlassian Marketplace. It runs inside Atlassian's infrastructure. It has no servers, no database and no backend of its own.
Who is responsible for what. For the ticket data the app reads, the controller is your own organisation: it is your Jira site, your data, and your agreement with Atlassian. Outlier is a processor acting on your instruction — its code runs inside your site, and what it reads does not leave it.
For anything sent to the address below, the controller is Oleksandr Chmut, a sole trader registered in Ukraine, trading as oc — the vendor on the Marketplace listing. That covers the message, the address it came from, and whatever the sender chose to put in it.
Reading this page makes you a third: Cloudflare serves it, and the request that fetched it is a request to a server somewhere. The vendor is the controller for that too, and the section on cookies says exactly what is collected.
Contact: support@chmut.com.
The basis for processing
For the ticket data, the basis is your organisation's rather than ours: the app processes it under your instruction, on whatever lawful basis you rely on to run your Jira site. We do not choose the purpose and cannot change it.
For a support message, the basis is legitimate interest — answering a question somebody chose to ask, and keeping the exchange long enough to answer follow-up about the same thing. It is not used for anything else: there is no marketing, no profiling, no list, and nowhere it is sent.
For the contact details attached to a paid licence, which Atlassian passes to the vendor rather than the person giving them to us, the basis is also legitimate interest: a vendor has to be able to reach the organisation that bought the thing, about the thing it bought. The interest is that narrow, and the section on sub-processors says what is done with them.
For this page, the basis is legitimate interest in knowing that a documentation site is being read and is not broken, and the interest is served by counts rather than by anything about a reader.
What the app reads
From Jira, as the app or as the person looking, depending on the request:
- Three fields per ticket —
created,updated,status. - The ticket's changelog, from which the app keeps when a status changed and the name of the field that changed.
- A board's configuration and its saved filter, to work out which tickets are in scope.
labels, and only while somebody is configuring a gadget, over up to 500 tickets, so the form can offer the labels that board actually uses.issuetype, on the same terms and for the same reason: while somebody is configuring a gadget, over the same tickets, so the form can offer the kinds of work that board actually carries.- The site's status names, which is one list for the whole Jira rather than anything about a ticket. A column has to be called something on the card, and it has to be classified — a status the app has never seen is a column it cannot judge.
- The boards you can open, by name, so a gadget can be pointed at one and so the card can say which board it is watching.
- The board's open sprints, and only if a gadget was configured to frame the card by them. What is kept from a sprint is its name and how much of the work in flight sits outside it.
Stated precisely, because it is the claim a security review will test: Jira's changelog endpoint has no field filter. The response therefore does carry the text of summary and description edits, and the name of whoever made each change. All of it is discarded at the boundary. Nothing derived from it is computed and nothing derived from it is written anywhere.
The honest sentence is "the app reads only how tickets moved", not "content is never sent to us". The second would be easy to disprove; the first survives being checked.
What it asks for
The list an administrator approves at installation, because that screen is the first thing a security review looks at and it should not be the one place this document is silent.
Every entry that reads Jira is read-only; the app has no write scope of any kind. The one that is not a read is storage:app, which is the permission to keep anything at all — the section below on what is stored is entirely about what it allows, and a list of permissions that left it out would be describing an app with nowhere to put its arithmetic. It is longer than the single read:jira-work most gadgets ask for, and deliberately so: that one line grants comments, attachments, worklogs and the whole of every issue, which would have put "we never read the content of your tickets" beside a permission granting exactly that.
read:board-scope:jira-software
read:board-scope.admin:jira-software
read:project:jira
read:sprint:jira-software
read:filter:jira
read:jql:jira
read:status:jira
read:project-role:jira
read:application-role:jira
read:avatar:jira
storage:app
read:issue-details:jira
read:issue-meta:jira
read:issue.changelog:jira
read:issue-type-hierarchy:jira
read:field:jira
read:field.default-value:jira
read:field.option:jira
read:field-configuration:jira
read:audit-log:jira
read:user:jira
read:group:jiraMost of that list is one endpoint's price. Nine of them — read:application-role:jira, read:avatar:jira, read:filter:jira, read:group:jira, read:issue-type-hierarchy:jira, read:jql:jira, read:project-role:jira, read:user:jira and read:project:jira — are what Jira requires as a set to call the endpoint that returns a saved filter. The app reads one field from that response, jql, and never calls a user, a group or an avatar endpoint at all. It cannot: there is no code that does.
read:audit-log:jira belongs to the second group, with read:issue-details, read:issue-meta and read:issue.changelog — the search that finds the work in flight and the changelog every fact here is derived from. Jira attaches it to that call; the app reads no audit log.
Those two are named because they are the ones that look wrong on the screen — an avatar and an audit log, in a gadget that reads three fields. Naming them is the point of printing the list: it makes the shape of the request checkable against Jira's own documentation rather than against our word.
What the app stores
In Atlassian Forge storage, on your own site. Nothing anywhere else.
- Per ticket: its id and its key — the
ACME-123you see on the card and click through to — when it entered and left each status, and whether it is resolved. No summary, no description, no comments, no assignee, no story points. - Per column: counts and durations derived from the above, and the status names, because a column has to be called something on the card.
- Per site: the list of status ids and names your Jira defines, kept so a card need not ask Jira for it every time somebody opens a dashboard. It is the same list any user of your site can see, and it is read from Jira rather than derived from anything.
- Per board: the board and filter ids, the timezone, the working week and the working hours, the labels and kinds of work a gadget is narrowed by, the columns a team named as review, and — where the card is framed by sprints — the name of the open sprint. Not the query: it is composed from those when it is needed, and kept nowhere. What is kept of a composed query is a short hash of it, which answers the one question it was kept for — whether the board still means what this gadget was set up against — and cannot be read back.
- Per installation: one row for the whole site, and the only thing stored that is not about a board. It holds the day a card first rendered here and the day offsets on which one rendered again, for thirty days and never after — which answers whether the app was used rather than merely installed. There is no identifier in it and nothing that could become one: a date and a list of whole numbers. It goes with everything else when the app is uninstalled.
One of those carries text a person wrote, and it is named rather than buried. The labels are whatever your team calls things, and they cannot be stripped: a query narrowed by different words is a query over a different population.
There were two. The board's query is composed from that board's own saved filter, and a saved filter quite ordinarily reads assignee in (...) or reporter = "someone@example.com" — so an address belonging to a person could sit in a stored row. It is no longer stored: nobody types a query into this app, every clause of it comes from Jira, and the board id, the filter id and the labels are enough to compose it on the pass that needs it. Said here rather than quietly removed, because this page was the place the problem was written down.
No per-person field, anywhere. Not assignee, not reporter, not the account id of whoever moved a ticket. This is enforced by a check that refuses such a field at the boundary, rather than by intention.
That is a claim about fields, and it used to need saying twice, because the stored query was one string and a check that refuses a column called assignee cannot read inside a query somebody else wrote. Now it needs saying once: the query is not kept, so there is no string for a name to be buried in. What is kept about a board is three identifiers and the labels your team chose.
What the app never does
- Send anything to any host other than your own Atlassian site. There is no analytics endpoint, no vendor backend and no third-party service. The app meets the conditions of Atlassian's Runs on Atlassian programme: the manifest declares no external domain, no remote and no outbound fetch. Whether the badge is granted is Atlassian's to decide and not ours to announce — what you can check today is the manifest itself, which Atlassian shows you before you install.
- Send anything to a language model from the pipeline. Every number on the card is arithmetic and every sentence is written; nothing is generated, and the product works unchanged for a site with no AI of any kind.
- Produce any output about an individual person.
One control is the exception to the second of those, and it is named here rather than found later. Ask Rovo why appears only where your site has Rovo, and only when you press it. It opens your Rovo, in your own instance, under your own permissions and on your own credits, with the card's text as the question. That question is the card's text — the same text the copy button puts on your clipboard — together with the ticket keys the card counted rather than listed, one sentence saying what an Outlier card is, and the request itself. Nothing in it is a kind of data the card does not already show you: ticket keys, column names, and how long work has been waiting. The answer goes to you. We never see it, and nothing about it comes back to us.
How long it is kept
- A resolved ticket's derived facts: 400 days, counted from the day it closed.
- An unresolved ticket's derived facts: kept while the board is watched, with no age limit, and this is deliberate rather than an omission. A ticket that has sat untouched for a year is the most interesting thing this product can find, and expiring it would make a board look calm exactly where it is not. What bounds it is the board rather than the clock: the two rules below.
- A board nothing has read - no dashboard opened and no rule asking for its morning: collection stops after 30 days, and everything derived from that board is deleted after 90.
- On uninstall: the app deletes its own rows rather than leaving them to Forge's 28-day retention window. A board large enough not to fit in the time the platform allows is reported rather than silently half-deleted — the run records what it could not finish, and Forge's own 28-day window then removes whatever is left, so the outcome is the platform's default rather than an indefinite remainder. Write to the address above if you need that confirmed for a particular site; it is the one path here where deletion is not immediate, and it should not have to be discovered.
- When a subscription lapses, collection stops with it. What was already derived falls under the same two rules as any unwatched board — nothing is collected after that day, and everything derived from the board is deleted after 90. Uninstalling does it immediately.
Collection runs on a schedule of the app's own rather than when somebody looks at a dashboard, so processing happens without a person present — for the boards that are being watched, and only those. Nothing in it decides anything about a person: there is no profiling, no scoring and no automated decision with a legal or similarly significant effect, because there is no per-person output for one to be made from.
Cookies and tracking
The gadget: none. No cookies, no tracking pixel, no analytics script, and nothing loaded from any host.
This page is not the gadget. Three things about it, said here because a reader who opens developer tools after a sentence claiming "no analytics" should find that sentence was about the right thing:
- It is served by Cloudflare, which sees the request that fetched it.
- It carries Cloudflare Web Analytics — a script that sets no cookie and identifies no visitor, and records that a page was fetched.
- Every page runs one script of our own — 247 lines, comments included — and all of it is layout and reach. It measures the header so an anchored heading lands below it; it makes a wide table or code block reachable from a keyboard; on a page with a contents list it marks which section you are reading; it opens folded sections while the page is printing, so nothing is hidden on paper; it keeps a screenshot in the theme you are reading in when you change that theme, and opens one over the page when you ask for a closer look; and it makes a Copy button copy, by reading text already in the page and calling the clipboard, with a fallback for browsers that refuse it. It fetches nothing, stores nothing, and sets nothing that outlives the tab.
Where it is held
In your own Atlassian site's Forge storage, in the realm your site is pinned to. Because Outlier stores in-scope end-user data exclusively in Forge hosted storage — it declares no external domain, no remote and no outbound fetch — Atlassian handles hosting, pinning and migration between realms, and the app is shown as PINNED in an administrator's data residency view. If you migrate your site to another realm, the app's data migrates with it.
One distinction is worth stating rather than leaving to be discovered: Atlassian's documentation notes that Forge "may sometimes execute an app's invocation from a location other than the location where the host Atlassian app is". Residency covers where data is stored. Where a given invocation runs is Atlassian's to decide, and in every case it is Atlassian's own infrastructure — nothing in this app reaches any other host.
Sub-processors
None for the app. Nothing it reads leaves your Atlassian site, so there is no third party to name: no analytics, no vendor backend, no model, no host of ours anywhere in the path.
Three exist around it, and they are named here because "none" without them would be true only of the half a reader is not asking about:
- Apple hosts the support mailbox, so a message sent to the address above is stored on iCloud. That is the correspondence the vendor controls, not anything from your board.
- Atlassian passes the vendor the contact details attached to a paid licence — a technical contact and a billing contact, which your organisation gave them rather than us. The vendor is the controller for those, uses them only to answer a question about the licence, and keeps them while it is live and for a year after it ends. They are never joined to anything read from a board, because there is nothing to join them to: no record the app stores names a person.
- Cloudflare serves this page, and sees the request that fetched it.
None of the three touches Jira data. All three are listed so the answer stays true when somebody checks it rather than only when it was written.
Your rights
The data stays inside your own Atlassian site, and your agreement with Atlassian covers the platform holding it — not this app, which is a third party to it. Uninstalling the app deletes what it stored, with the one exception the retention section names: a board too large to finish inside the time the platform allows leaves a remainder, which the platform's own 28-day window then removes. A request about specific data should go to your Jira administrator first, since they control the site and we do not hold a copy to search.
For a support message, where the vendor is the controller, write to the address above to ask what is held, to have it corrected, or to have it deleted. You can also object to it being kept at all: the basis is legitimate interest, so an objection is a right rather than a request, and the answer is deletion unless the exchange is still open. The same address handles a request to restrict processing while a question about it is being settled.
Support correspondence is deleted after 24 months, or sooner on request. A figure rather than a criterion: "as long as needed to answer a follow-up" is unauditable, and a mailbox with no rule in it is a mailbox that keeps everything.
Portability does not apply to any of it: the right covers data processed on consent or on a contract, and everything the vendor controls here rests on legitimate interest. Said here rather than left out, because a list of rights that names five and skips one reads as an oversight.
If you are in the EU or the UK and believe either has been handled wrongly, you can complain to your national supervisory authority. You are not required to raise it with us first, though we would rather you did.
Changes
This is version 3 of this policy, and the date it was last reviewed is at the top. Twice now an edition has been narrower than the product rather than wrong about it, and both times the categories of data were unchanged: version 1 described the Rovo question as the card's text and nothing more, and version 2 listed what is stored per ticket, per column, per site and per board without naming the row kept for the installation itself. Every earlier edition is published below with its own digest. All of them change together, so a reader who kept a copy can tell whether they are holding the current one.
A change that alters what is collected, what is kept, how long, or who else sees it is announced on the listing thirty days before it takes effect, and the previous version stays available on request. Anything smaller — a clearer sentence, a corrected figure — moves the review date and not the version.
The method has been versioned from the beginning, and it would be strange to hold the arithmetic to a rule the policy about your data was not held to.
This edition
The file below is the authoritative text of this edition. This page renders it and adds navigation and this block, so the page and the file are not byte-identical - it is the file that governs, and the digest is over the file.
Current — in force from 2026-09-19 — privacy.md 19 KB
549a9078b4b4481809eba0903786f107349e8dadca5c2d729e77f5f1464e1f1c
Earlier — in force 2026-09-01 to 2026-09-19 — privacy-2026-09-01.md 19 KB
054c5540bd3e0ceca232ecf5e59f0589ee59d346df70bcd4b8ea62c90f8ee0f9
Earlier — in force 2026-08-30 to 2026-09-01 — privacy-2026-08-30.md 17 KB
b25d445fc6e6115bc72de2c8721fbac673744e1d40fa4ce15e7c9f353f1ba843
Check it in one line, and the output is the answer rather than something to compare
against: curl -sL https://outlier.chmut.com/privacy.md | shasum -a 256. With the file
already downloaded, shasum -a 256 privacy.md says the same.
On Windows, Get-FileHash privacy.md -Algorithm SHA256 in PowerShell,
which prints in capitals - the comparison is case-insensitive.
The .md files download rather than open in most browsers,
which is what the digest is computed over. The digest is published by us: it shows the
file has not drifted or been altered in transit, and it is not a third-party
attestation.