Ghost & view-as
Impersonate is a permission, never a role. Sessions are read-first, banner-flagged, time-boxed and fully audited — and the banner + acting-as state derive from the SERVER session, never client state: when the session ends, acting-as ends, fail-closed (ledger #239 P1: the live banner outlived the server session and actions then hit the admin’s OWN account — this concept renders the fix: server-derived state, hard expiry, no action without a live grant). The discipline live Folo support already runs (“ghost sessions in the inbox are read-first, banner-flagged, time-boxed and fully audited”), made a first-class surface.
Demo dataPattern from live FG + Folo
Start a session
Pick who, then how deep. The entity type scopes the search — a fan, a creator, an agency and a chatter are different records with different blast radii.
⌕
👁 View as Read-only
See exactly what they see. Nothing can be sent, bought, changed or deleted — the session cannot write, so it needs no reason and no expiry ceremony. Still logged.
⚠ Act as Impersonate
Full control of the account. Requires the Impersonate/act-as permission, a written reason, and an auto-expiry — the session ends itself.
15m1h4h
Opens in a new window with the banner below pinned.
↗
Low-stakes variant (investors-dibi reference): for harmless previews — “view as investor” there — plain one-click links per named test account beat a modal flow. We keep that shape for sandbox/test personas only; anything touching a real person’s account goes through this picker.
The in-session banner Live demo
Pinned to the top of every page for the whole session — you can never forget whose eyes you’re borrowing.
Countdown is real in-app; expiry force-ends the session and writes ghost.expire. The demo above ticks for illustration only.
Session log Demo data
Audited history — opens, closes, and every action taken while inside.
| When | Event | Admin | Target | Platform | Detail |
|---|---|---|---|---|---|
| Today 13:12 | ghost.open | Simon O. | @delisha | read-only · 1h box | |
| Today 11:48 | ghost.action | Dana R. | Marta V. (fan) | act-as · resent a stuck receipt email · reason: “support #4187” | |
| Today 11:31 | ghost.open | Dana R. | Marta V. (fan) | act-as · 15m box · reason: “support #4187” | |
| Today 11:46 | ghost.close | Dana R. | Marta V. (fan) | ended by admin, 1m before expiry | |
| 2026-08-08 | ghost.expire | Kavi N. | Northlight Agency | read-only · hit the 4h box, force-ended | |
| 2026-08-08 | ghost.denied | Owen P. | @missaria | act-as refused — lacks the Impersonate permission |
Active sessions 2 open
👁
Simon O. → @delisharead-only · started 13:12 · 42m left
⚠
Mara T. → Velvet Studioact-as · started 12:50 · 3h 08m left
Any super-admin can end any session; the target’s record shows an open-session flag while one runs.
What ghost can never do
Hard limits, sourced from live FG behaviour — not preferences.
⛔ Move money. No payout approval, no purchase, no refund from inside a session — finance actions bounce to the Finance admin under the admin’s own identity.
⛔ Read credentials. Passwords, tokens and payment details are never rendered — the live services page states “no endpoints/tokens ever read” and ghost inherits that rule.
⛔ Outlive its box. Auto-expiry is mandatory on act-as; there is no “until further notice” session.
⛔ Run silent. The banner cannot be dismissed, and open/close/action/expiry all write to the audit log with the admin’s identity.
⛔ Be a role. Impersonate is granted per person as a permission chip in Roles & access — no role ships with it by default.