A Personal Server is the user’s access engine: it holds (a reference to) the user’s data and decides, per request, whether to release a scope to a builder. It is where grants are enforced, data is served, and access is logged. It is the only protocol component that works with plaintext data.
It runs the Vana SDK — encryption, decryption, permission checks, and identity — so the trust-bearing logic executes under the user’s control, not on a builder’s servers. Today the Personal Server is client-side: it runs on the user’s own device, bundled into the desktop app, or in a browser tab for the web.
A Personal Server is a protocol participant — it registers onchain and can act under the scopes the user allows. A Vana app (the desktop app, or a web app) is a client that bundles and controls a Personal Server, but is not itself a protocol participant. Think of it like email: the app is your mail client, the Personal Server is your mail server.
What every Personal Server does
- Syncs data from the user’s connected sources into their own storage, organized by scope
- Serves data to builders who hold a valid grant, scope by scope, over an authenticated API
- Encrypts data before uploading to storage backends
- Validates grants on every request — registered grantee, unrevoked, unexpired, scope covered, and (where fee gating is enabled) fee paid
- Exposes an MCP interface so agents can work with the user’s data under the same grant permissions — bounding what an agent may access (see Agents)
- Keeps an access log the user can review
Today the Personal Server is the entity that decrypts and returns a requested scope to a grantee. With Protocol-Governed Encryption (PGE) the grantee receives a per-request key and decrypts the data itself; the grant interface a builder integrates with is the same regardless of where decryption happens.
| Form | Where it runs | Storage | Status |
|---|
| Desktop (Full) | Bundled in the desktop app, running locally on the user’s machine | Filesystem | Live |
| Web (Lite) | A separate browser tab on the user’s device | In-browser (IndexedDB) | Live |
| User compute | A compute environment the user fully controls (see below) | Filesystem | Future |
The desktop and web forms share one codebase and one SDK; they differ only in where they run and how they store data. Both keep the data and keys on the client. The desktop form keeps keys in the OS filesystem; the Web (Lite) form keeps them in the browser (IndexedDB) for zero-install convenience.
Registration
Every Personal Server must be registered onchain via the DataPortabilityServers contract. Registration records the server’s address, public key, and URL. Users then trust a server to act on their behalf.
The DP RPC provides signature-based registration so a Vana app can register a server without the user sending an onchain transaction directly:
See Identity for the full registration flow and the DataPortabilityServers contract interface.
API
The Personal Server exposes a versioned REST API under /v1.
Data endpoints
| Method | Path | Description |
|---|
POST | /v1/data/{scope} | Create a new data document for a scope |
GET | /v1/data | List available scopes and latest version metadata |
GET | /v1/data/{scope} | Read data for a scope (latest or specific version) |
GET | /v1/data/{scope}/versions | List available versions (metadata only) |
DELETE | /v1/data/{scope} | Delete data for a scope (user-only) |
Grant endpoints
| Method | Path | Description |
|---|
GET | /v1/grants | List all grants for this user |
POST | /v1/grants | Create a new grant (user-only) |
POST | /v1/grants/verify | Verify a grant signature |
Other endpoints
| Method | Path | Description |
|---|
GET | /v1/access-logs | Get access log history |
GET | /health | Health check (unversioned) |
Query parameters for GET /v1/data
| Parameter | Description |
|---|
scopePrefix | Filter by scope prefix (e.g. instagram) |
limit | Maximum number of results |
offset | Pagination offset |
Query parameters for GET /v1/data/{scope}
| Parameter | Description |
|---|
fileId | Return a specific version by DataRegistry fileId |
at | Return the version closest to this ISO 8601 timestamp (closest ≤ at) |
If neither parameter is provided, the latest version by collectedAt is returned.
Write flow (POST /v1/data/{scope})
When a data document is written:
- Look up
schemaId for the scope via the DP RPC
- Validate the request body against the schema
- Generate a
collectedAt timestamp (UTC)
- Construct the data file envelope with schema URL, version, scope, and timestamp
- Store locally in
~/.vana/data/{scope}/{collectedAt}.json
- Return
201 Created immediately
- Asynchronously: encrypt with the scope key, upload to the storage backend, and register in the DataRegistry
Builder data access
Builders read data from the Personal Server using signed HTTP requests. Every builder request must include an Authorization: Web3Signed header.
Web3Signed authorization
Authorization: Web3Signed <base64url(json)>.<signature>
The payload is a JSON object with keys sorted alphabetically:
{
"aud": "https://user-abc.server.vana.com",
"bodyHash": "",
"exp": 1737500300,
"grantId": "0x...",
"iat": 1737500000,
"method": "GET",
"uri": "/data/instagram.profile"
}
| Field | Description |
|---|
aud | Personal Server origin (must match) |
method | HTTP method of the request |
uri | Request path and query string |
bodyHash | Hash of request body (empty string for GET) |
iat | Issued-at timestamp (Unix seconds) |
exp | Expiration timestamp (Unix seconds) |
grantId | Onchain permissionId — required for raw data reads |
Signing: The JSON is canonicalized (keys sorted alphabetically), then base64url-encoded (no padding). The signature is an EIP-191 signature over the ASCII bytes of the base64url string.
In practice a builder does not build these requests by hand — the
Vana SDK signs them and handles the paid-read challenge. See the
Build a Vana App guide.
Verification
When the Personal Server receives a builder request, it:
- Recovers the signer address from the
Authorization header
- Verifies the signer is a registered builder onchain
- Checks
aud matches the server’s own origin
- Checks
method and uri match the actual request
- Validates
iat/exp are within the allowed skew window (e.g. 5 minutes)
- For data reads: verifies
grantId exists onchain and the signer matches the grantee
- Confirms the requested scope is within the granted scopes
- Where fee gating is enabled, confirms the grant’s fee shows as paid (see Payments & fees)
- Logs the access
Access control summary
| Endpoint | Who can call |
|---|
POST /v1/data/{scope} | User only |
GET /v1/data, GET /v1/data/{scope} | User or builder with valid grant |
GET /v1/data/{scope}/versions | User or builder with valid grant |
DELETE /v1/data/{scope} | User only |
POST /v1/grants, GET /v1/grants | User only |
GET /v1/access-logs | User only |
Reachability
A client-side Personal Server must be reachable from the internet for a builder to read from it. A desktop-bundled server is reachable while the app is open; when the app is closed, builder requests fail until it reopens. To expose it, Vana provides FRP tunneling (Fast Reverse Proxy): the app connects to proxy.server.vana.org and receives a public URL at {userId}.server.vana.org with automatic TLS. A self-hosted server (advanced users, run as a Docker container on their own infrastructure) controls its own URL and uptime.
Bring your own compute (future)
The forthcoming addition is bring your own compute: an option to run your Personal Server in a dedicated compute environment instead of on your own device — so a web user gets an always-available Personal Server without keeping a tab open or installing the desktop app.
This is one of the products Open Data Labs will offer: a compute environment designed so that the user controls it and only the user can see the data. Data stays encrypted inside the environment, and the intended guarantee is that no one else — including ODL, which provides the environment — can see what runs in it or read the data. This rests on hardware-attested execution and PGE, both in active development.
Status. Live: the client-side Personal Server — bundled in the desktop app and running in a browser tab for the web, on a single SDK. Coming: bring your own compute, a user-controlled compute environment (an ODL product) where only the user can see the encrypted data.
Sync
When a user has multiple Personal Server instances, they stay synchronized through the storage backend and Data Registry. See Storage & Encryption — Data sync for the full sync model.
Local data hierarchy
Personal Server implementations that use a filesystem store the same directory layout:
~/.vana/
├── data/ # Decrypted user data
│ ├── instagram/
│ │ ├── profile/
│ │ │ └── 2026-01-21T10-00-00Z.json
│ │ ├── posts/
│ │ └── likes/
│ ├── chatgpt/
│ │ └── conversations/
│ └── youtube/
│ ├── watch_history/
│ └── subscriptions/
├── logs/ # Access logs (JSON lines, daily rotation)
│ └── access-2026-01-21.log
├── index.db # Local registry index (SQLite)
└── server.json # Server configuration
Files are named {YYYY-MM-DDTHH-mm-ssZ}.json using the collectedAt timestamp.