Dashboard
What happened each day — and whether it is trending up or down.
Daily Briefing
What moved, what to do, what to leave alone.
AI Briefing
Since yesterday
Needs attention
Running & next experiments
Experiments
Your ASA lab notebook — every theory, the change that tests it, and the verdict.
🌱 Learnings & rules adopted
The durable knowledge experiments leave behind — these constrain every future recommendation.
Campaigns
One row per campaign. Click a header to sort.
Purchases
Every RevenueCat purchase, newest first, with the campaign each is attributed to.
Keywords
Last 7 days · band by TTR · click a header to sort.
Search Terms
What people actually typed — the source of negative-keyword discovery.
Reports
Pick a dimension, a window and a timezone; filter it; sort any column. Save it and it comes back.
All reports
A saved report stores the query, never the numbers — opening one re-runs it against today's data.
Timeline
Every account change on one axis — so you can read results against the change that caused them.
Blended TTR, with change marker
Change log
AI Usage
Every call we made to a model, what it cost, and why.
Data & Sync
Where this account's data came from, and when.
Sync history
Every run this account has made — scheduled and manual alike.
The pipeline
Webhook deliveries
Every inbound RevenueCat delivery, newest first — and what Sift did with it.
REVENUECAT_WEBHOOK_SECRET shows up here, not only in the server logs. The
Payload of an accepted delivery is the body as received, secret-scrubbed. Rows past the
retention window are swept nightly.Remote Config
What the shipped app is told at launch — changeable without a release.
Live payload
Exactly what GET /api/v1/app-config returns for this account right now, from
the same code path — so it cannot disagree with what the app receives. A disabled key is
absent, never null: absence means the binary uses its compiled default,
and {} is a complete, correct answer for an account with nothing turned on.
Loading…
Keys
Every key on the account, enabled or not — a staged-off key is the thing you came here to turn on, so hiding it would hide the workflow. Enabled is the staging mechanism: there is no draft/publish step, so turning a key on is what puts it in the payload above on every client's next launch.
Deleting a key does not restore a previous value — it reverts every client to its compiled default on the next launch, the same blast radius as a value change and easier to do by accident. Only the audit trail keeps the last value. Reordering rules is a config change too: first match wins, so moving one above another can invert the answer for a whole storefront.
Deliveries
Every launch that asked this account for its config, newest first. A 304 is a successful delivery — a warm cache revalidating — and it means that device is actively running that version. Click a version to see the exact document it carried.
Every delivery is recorded — no sampling, and nothing is ever deleted. So an empty result means no such request was served, provided the delivery log has been on and healthy for the window you are looking at. A version with no payload to expand was still served: the account's snapshot budget was exhausted, or that write failed.
Add a rule
A default plus an ordered list of overrides — first match wins. New rules are
appended last and staged off. (The AND-only rule and the eight-condition cap are
stated under the conditions themselves, so the editor on an existing rule says the same
thing in the same words.)
⚠ Do not write the negative. country ≠ CA → false is not a rule, it is
the key's value. Encoding both directions is how a rule set acquires two rules that disagree
and a serving order nobody can reconstruct.
Add a key
The key and its type are immutable after creation — a key that changes type
mid-flight is a decoding crash in a binary already on people's phones that cannot be
patched. To change a type, add a new key and retire the old one. Type the value the way
JSON carries it: a string as-is with no quotes, an int or
float as a number, a json value as JSON.
Alerts
What the pipeline noticed — and what has already been acknowledged.
Opening this screen is what raises — and what clears — the pipeline heartbeat. sync stale is the one alert no background job can raise, because the failure it reports is the job not running, so it is evaluated when this screen reads the inbox. The check runs both ways: while the data is stale a row is raised, and the moment the pipeline is healthy again every still-open sync stale row is moved to resolved — by the read itself, on the spot. So a sync-stale row that appears the moment you look, or that reads resolved with a timestamp from a second ago, is the check working rather than a coincidence. It is the one status change here that nobody clicked, and All statuses is the view it is visible in. Acknowledging needs the operator role or higher; a viewer sees the inbox without the button.
Suggestions
What the engine would change, why, and what it expects to happen.
A suggestion is a proposal, not a change: nothing here has touched a bid, and nothing here will. The queue exists so the decision is made by a person looking at the evidence.
Settings
Your account and password, the provider keys Sift holds, and the API reference for Claude Code.
Credentials
Provider API keys for the vault. The secret travels inbound only — it is verified against the provider before it is stored, and what comes back is a masked fingerprint, never the key itself. Submitting for a provider that already has a key rotates it.
Deleting destroys Sift's copy of the key; the row is kept for audit and can be replaced by adding the provider again. It does not revoke the key at the provider — do that in their console too.
API reference for Claude Code
A single Markdown file describing every Sift endpoint and the conventions a client needs — auth, money units, the report filter grammar, rate limits, and what it can and cannot do. Hand it to the Claude Code CLI so it can drive Sift over HTTP instead of guessing.