Reference
Service limits & data freshness
What the Service commits to, what it measures, and what your app should expect when a limit applies. Where the Terms of Service refer to the Documentation for usage limits, or for what the SDK keeps on a device, this is the page they mean.
Pharen never samples the data it receives. The only sampling is sampling you configure.
Availability
There is no availability commitment or service-level agreement: the Terms make no uptime representation. We communicate incidents and material operational changes to your organization's contact.
Availability is measured all the same, from outside the platform:
- Every five minutes, an external monitor sends
GET /readyto each of the two hosts:ingest.pharen.ai, where the SDK sends data, andapi.pharen.ai, which answers the console and the CLI and serves the hosted pages. - A check is up when it answers
200within the monitor's timeout./readyanswers503when the Service cannot reach its database, so the address, the routing, the process and its database are all counted. - A host's availability for a month is its up checks over all its checks, to two decimal places. An outage shorter than one five-minute interval may go unrecorded, and a longer one is counted to the nearest five minutes.
- The monitor does not check certificates. Certificates are checked separately, every week.
Measurement began in October 2026. A month nobody measured is never counted as a month at 100%.
Data freshness
Pharen doesn't commit to how long data takes to reach the console or a query after the app records it. What sets the pace on the device is the SDK. In the current iOS SDK:
- While the app runs, the SDK sends a batch of events on a default cadence, and again each time the app moves to the background. The platform sets how often it sends and how many events a batch carries, for every app; they are not part of your configuration, and they can change without an app update. A batch stops at 1 MB of encoded events; an event larger than that on its own is sent in a batch by itself.
- A fatal crash is written to disk when it happens and sent on the app's next launch, so it arrives only once the app is opened again, within the crash-report limits under On the device.
- An offline device sends what it holds when it is back online. A batch waiting out a rate limit or a hold arrives later than it would have.
How often the SDK sends is SDK behavior, not a commitment, and it can change between SDK releases; each release's notes say what it does.
Rate limits
Each limit is a budget that refills continuously and allows short bursts. A request over its budget is refused with 429 and an error code; where the response carries Retry-After, it is the number of whole seconds to wait before trying again.
| What is limited | The budget belongs to | Refused with |
|---|---|---|
| Requests the SDK makes with an ingest key, such as event batches, identity and configuration | The app and environment the key names. A batch costs one unit per event it carries | 429 rate.limited, with Retry-After |
| Queries from a query key or a signed-in person, including over MCP | The app and environment queried (the environment, for a lookup across apps), shared by every key and person querying it | 429 ratelimit.exceeded, with Retry-After |
| Requests with a publishable key (the report page and widget) | The key, as a share of the app's budget, and on top of it each network address | 429 ratelimit.key, with Retry-After; or ratelimit.ip, without it |
| Sign-in, onboarding, install pages and the hosted report page | Each network address | 429, without Retry-After |
| Creating or changing a link whose destination the Service screens | Your organization | 429 rate.limited, with Retry-After |
Diagnostic uploads also count against a storage quota for each app and for your organization; an upload past it is refused with 429 diagnostics.quota_exceeded, without Retry-After, until older bundles age out.
The iOS SDK handles a 429 for you: the events stay queued, the next attempt waits as long as Retry-After says, up to a day, even across relaunches, and no event is given up after a number of attempts. A rate limit never drops data by itself; only a budget that fills while it waits does, as On the device describes.
Your own code calling the API should do the same: wait out Retry-After where it is present, and back off where it is not. If your app needs more than its budget allows, write to hello@pharen.ai.
How long data is kept
The windows the Service applies to each kind of data are listed in Privacy & consent.
On the device
Until the Service accepts it, data waits on the device. In the current SDK, it waits within these limits. They are the limits of the SDK release your app ships: a release that changes them says so in its notes, and the change reaches your users only once you ship that release.
- Everything the SDK keeps for sending — the event queue, crash reports and identity updates — shares one budget: 30 MB and 15,000 items. Past either bound, room is made by dropping the oldest event your own instrumentation recorded — tracked events, screens, timings — and only once none of those is left the oldest of the SDK's core events: the session boundary, crashes, errors and hangs, identity, and what a person sent. A crash report older than that core event gives way before it, and the newest three crash reports are never dropped to make room. Detail goes before sessions. The budget is the same whatever keeps the device from sending: no network, a rate limit, a hold or a suspension.
- The event queue's share of the budget is capped by
maxQueueDepth(15,000 by default; you can set it, and a higher value does not raise the budget). - A crash report is kept, within the budget, until the Service confirms an outcome for it, with no age limit. A device sends the first five crash reports of each build, then one a day, and an app that crashes at every launch reports the first, third, tenth and thirtieth crash of the run; each report held back is deleted once it is counted onto the next one sent, so the crash count stays exact.
- On iOS, diagnostic bundles and a reporter's contact address keep their own limits, outside the budget. Diagnostic bundles waiting to upload are limited to 5 bundles and 25 MiB (26,214,400 bytes) in total, and are deleted after 30 days; past the count or size limit, the oldest goes first. A reporter's contact address waiting to send is limited to 20 records and 30 days.
Data that exists only on a device is lost if the app is removed or its data is cleared, and never arrives from a device that is lost or never runs the app again. Privacy & consent lists what the SDK keeps on the device for other reasons.
During a limit hold
When use in a period reaches your plan's session allowance (or a trial's), the Service holds further data until the hold ends, as the Terms describe: for example, when the allowances are raised or the next period begins. During the hold the Service keeps accepting crash reports, hangs that ended the app, and what people submit under the content purpose. The hold covers every environment alike: sessions in your development and staging environments draw on the same allowances as live, from the first one.
The Service tells the SDK to hold what it sends until the limit lifts. The SDK goes on sending, on its ordinary schedule — after any backoff an earlier refusal armed, five minutes at most — crash reports, a hang that ended the app, and everything a person sent — feedback reports and survey answers. Everything else it records waits on the device, within the limits above, in the order it was recorded, and is sent when the hold ends. Until a device has received the hold, an event the Service refuses for now waits at the head of the queue and the events recorded after it wait with it, up to the device's next configuration refresh; crash reports have an upload of their own and never wait behind it.
While your organization is suspended
Suspension does not extend server-side retention. Identity profiles expire at their ordinary inactivity horizon, including during suspension; restoring service does not restore a profile already deleted. See the retention schedule.
The Service tells the SDK that ingestion is suspended. The SDK goes on recording and sends none of what it records; its only request is the check below. What it records is kept on the device within the budget above, and once service is restored the SDK sends what it kept, a batch at a time; it counts against the allowances of the period in which the Service accepts it. The suspension does not itself cause the SDK to discard what it keeps. What it keeps can still be dropped when it exceeds the budget, deleted when a person asks, such as on a withdrawal of consent, or deleted when an install is stopped as described below; and data on a device is lost if the app is removed or its data is cleared. What a person would send through the SDK meanwhile, such as a feedback report or a survey answer, is refused when they try, not kept, and the SDK returns a refusal your app can show. Because no crash report is uploaded while the suspension lasts, the SDK skips its startup wait for crash reports, and it checks from time to time whether service is restored, with a request that carries your app's ingest key and names the software it runs — the SDK version, and your app's platform, version, build and kind of build, such as debug or App Store — but none of the identifiers the SDK keeps for a person, an install or a session; like any network request, it reaches the Service from the device's network address. An ingest key we revoke as a measure against your use of the Service is treated as a suspension: its installs keep what they record, as above.
Two things outrank a suspension, and stop the installs they reach even while your organization is suspended, deleting what those installs held: an SDK version retired for a privacy, security or crash defect, described below, and a release of your app whose SDK we stop for a privacy, security or crash defect.
A suspension doesn't change what your kill switch, update required or retired screens do: the same periodic check an install makes while held can still carry a new one, lift one, or change one, exactly as it would if nothing had happened to your organization with us — we count those checks in aggregate, by day, without keeping anything about any one person or device. Your other app notices — outage screens and the rest — stop being refreshed while the suspension lasts, since those ride the document fetch a held install doesn't make; an outage screen still clears itself on its own after about an hour, as it always does.
When an SDK version is retired
We retire SDK versions with notice, except where a privacy or security defect cannot wait for it. From a version's end of life, the Service no longer serves installs on it: the SDK stops recording, deletes what it holds on the device, and checks from time to time whether it is served again. An update of your app to a supported SDK version is served from its first launch. From a version's end of support, the same applies to debug builds on that version — your own runs from Xcode or Android Studio — while TestFlight, App Store and every other build keeps working until its end of life.
A version retired for a privacy, security or crash defect stops this way even while your organization is suspended, and deletes what it held then too. A version retired for any other reason is held on a suspended organization, as above, until service is restored, and then stops. Retirement for a crash defect does not shorten the notice or support commitments in our SDK support policy.
This applies to SDK releases that tell the Service which version they are. Earlier releases do not, and are never retired this way.
Once an install stops this way, its kill switch, update required and retired screens aren't affected: the same periodic check that tells it the SDK has stopped also carries whichever of those apply, so an update required screen keeps doing exactly what it's for — moving people off a version we no longer serve. Its other notices — outage screens and the rest — stop being refreshed and age out the normal way, the same freshness window that applies everywhere else.
When you revoke or rotate an ingest key
A revocation names its reason, routine or compromise, and the reason decides what the installs carrying the key do once the revocation takes effect: at once for a revoke, and at the end of the grace window for a rotation (24 hours unless you choose another).
- Routine, the default: a rotation, a key you retire, or a slip. For thirty days after the revocation takes effect, its installs are held, as they are while your organization is suspended: they go on recording, keep what they record within the budget above, and send nothing but the check, which comes at least every six hours. An owner of your organization can restore the key at any time in those thirty days, with
pharen ingest-keys restore; its installs resume at their next check, within about six hours, and send what they kept. Once the thirty days have passed, the key cannot be restored, and its installs stop as they do when your agreement ends: they record nothing, and delete what they held. - Compromise: the key has leaked. Its installs stop as soon as the revocation takes effect, deleting what they held, and the key can never be restored.
Restoring the old key of a rotation does not revoke its replacement: both work until you revoke one. Rotating, revoking and restoring each show the installs seen on the key in the last seven days and what they will be told, and act only once you confirm. A key the Service revokes as a measure against your use of the Service is not one you restore: it is treated as a suspension, as described above.
This applies to SDK releases that tell the Service which version they are. Earlier releases do not; the Service refuses their requests on a revoked key, as it always has.
When your agreement ends
The Service stops serving your apps' installs, and what the SDK still holds on a device is not delivered. Customer Data the Service already holds is kept and deleted as the Terms and the DPA provide. The next time an install reaches the Service, the SDK stops:
- It records nothing, and sends nothing but the check below.
- It deletes what it held on the device: queued events, crash reports and identity updates, and on iOS also diagnostic bundles, a reporter's contact address waiting to send and the address remembered for the reporter.
- It skips its startup wait for crash reports (2 seconds by default), since there is no upload to wait for.
- It checks from time to time whether it is served again, with the same request a suspended install makes: the check, which carries none of the identifiers the SDK keeps for a person, an install or a session; like any network request, it reaches the Service from the device's network address. Once we close your organization permanently after your agreement ends, installs stop checking; a new build of your app checks once, at its first launch.
None of this is an error your app sees. The SDK is designed to handle it internally: it does not crash your app, shows nothing to your users, and does not stop your app from working; the consent API, and the parsing of a link your app is opened with, go on working on the device. Until a device next reaches the Service, what it held stays on it, unless the app is removed or its data is cleared first.
While your installs are stopped but still checking, as above, their kill switch, update required and retired screens keep reaching them exactly as before, the same way an SDK version's do above; their other notices stop being refreshed and age out. Once we close your organization permanently, installs stop checking at all, which lifts any kill switch they were holding, so nobody is left stranded behind a stop they can no longer ask you to lift — unless you marked it permanent for a build that must never run again, which survives even that; only an update past the versions it names, or a reinstall, clears a permanent one.
An organization with no plan
When a trial ends without a plan, or a plan ends on a notice that ended only the plan, the agreement continues but the Service stops serving your apps' installs. The SDK stops as it does when your agreement ends: it records nothing, sends nothing but the check, and deletes what it held on the device the next time it reaches the Service, so nothing an install deleted arrives later, even if the organization then takes a plan. It goes on checking from time to time, and starts recording again once it is served. Where no paid term is in effect, the Terms let either side end the agreement on 15 days' written notice. We ordinarily give that notice once 90 days have passed since the trial or plan ended or, for an organization that was not offered a trial and has never had a plan, since it was created. An organization whose trial has not yet begun has no set period.