vana is the command line for Vana: it collects a person's own data into
their Personal Server, and it drives the builder side of the protocol so an
app or an agent can ask for that data, read it, and pay for it from a
terminal.
This repository also ships the JavaScript SDK the CLI is built on, which is documented further down.
Run it without installing anything:
npx vana-cli statusOr install the standalone binary, which is signed and notarized on macOS:
curl -fsSL https://raw.githubusercontent.com/vana-com/vana-cli/main/install/install.sh | sh
vana statusWindows uses install/install.ps1. Homebrew (brew tap vana-com/tap && brew install vana) is still published but lags the installer.
The npm route runs under your own Node, which some endpoint security products prefer over an unknown executable; the installer gives you a single self-contained binary with no Node required. Both are the same CLI.
Owner side collects your own data and keeps it in your Personal Server:
vana login # Vana account, or --server <url> for a self-hosted PS
vana connect github # managed browser, collects, syncs to your server
vana data show github # what was collected
vana server status # your server, local and registered URLsBuilder side is what an app or an agent uses to work with someone else's data, with their consent:
vana app register # once per machine
vana app request --scopes github.repositories # prints an approval URL, waits
vana app read github.repositories --grant <id> # signed readrequest returns the grant id once the person approves. read stops at
exit 4 with the exact price before spending anything; add --pay to settle
it from escrow and --max-fee to cap it. The rest of the group:
| Command | What it does |
|---|---|
vana app ask "<q>" --sources a,b --derived <scope> |
ask a question computed on the person's own server, without reading the sources |
vana app status <derived-scope> |
is the answer coming, and when |
vana app lineage <scope> |
what an answer was computed from, redacted where it must be |
vana app whoami |
app address, key source, network, registration state |
vana app requests list|show <id> |
what was asked, what was approved |
vana app escrow balance|fund |
what the app can spend, and funding it |
vana app onchain <scope> --owner <addr> |
data point version, hashes, deletion state |
Everything defaults to moksha, the testnet; --network mainnet spends
real money and is never implied.
Every command takes --json and --no-input, and exits with a code an
agent can branch on: 0 done, 1 failed, 2 bad usage, 3 no grant,
4 payment required, 5 no server answered, 6 not ready yet, 7 a
person has to act. The full contract is in
docs/CLI-EXIT-CODE-MATRIX.md.
Install the skills that teach an agent each half:
vana skills install builder # ask for access, read, pay
vana skills install connect-data # collect your own dataThere is also an MCP server over stdio for clients that prefer tools:
claude mcp add vana -- vana mcpYour users already have rich personal data — ChatGPT conversations, Instagram activity, Gmail, purchase history — but it's locked inside the platforms that collected it. As a builder, you can't easily use that data to personalize onboarding, tailor recommendations, or skip lengthy signup forms.
Data portability means users can export their data from these platforms and grant your app scoped access to it — with their explicit consent, cryptographic verification, and full control over what's shared and when to revoke it.
Today, getting access to user data means asking for manual file uploads (high friction), scraping on their behalf (fragile and legally risky), or negotiating enterprise API deals (slow and expensive). This SDK gives you a standardized way to request and receive personal data through Vana's Data Portability Protocol, handling session creation, grant verification, and data fetching in three function calls.
Your App Vana Protocol
────────────────────────────── ──────────────────────────────
1. connect({ scopes })
→ creates session
→ returns deep link ──▶ 2. User opens DataConnect
reviews scopes, exports data,
approves grant
3. Poll resolves with grant ◀── Grant signed & registered
4. getData({ grant }) ──▶ 5. Personal Server returns
→ structured JSON user data over TLS
The Data Portability Protocol defines how users collect data from platforms, store it under their control (on-device or hosted), and grant third-party apps scoped access. This SDK handles session creation, cryptographic request signing, polling, and data fetching. You write three function calls; the protocol handles the rest.
The fastest way to get up and running is with the examples/nextjs-starter — a complete working app which uses the development environment and has full flow of data portability wired up:
git clone https://github.com/vana-com/vana-cli.git
cd vana-connect/examples/nextjs-starter
cp .env.local.example .env.localUse the pre-registered dev key in .env.local. Note that this private key is ONLY for testing and works only with a testing Vana environment.
VANA_PRIVATE_KEY=0x3c05ac1a00546bc0b1b8d3a11fb908409005fac3f26d25f70711e4f632e720d3
APP_URL=http://localhost:3001
Install and run
pnpm install
pnpm dev
Note that while testing this example app, you should have a development version of the DataConnect app.
There is one caveat in development: the deep-link for DataConnect app doesn't open the dev version of the app.
This means that when testing your app from the end user perspective, once you see this screen:

Instead of clicking the "Launch DataConnect" button, you should right-click on it and copy its address. The address will be something like vana://connect?sessionId=....
Then, in your dev version of DataConnect (likely built from the main branch) you will see a place to copy the link in the right-bottom corner of the app:
If you prefer to integrate the SDK into an existing project, follow the steps below.
vana-connect now also ships a local collection CLI for connector setup and data export flows.
If you only care about the CLI, start with docs/CLI-README.md.
For the full CLI review surface, use:
pnpm build:sea uses Node 25's --build-sea flow to create a small vana launcher and packages the real app payload next to it under app/.
It produces a platform-specific release directory plus a release archive and matching checksum file under artifacts/sea/.
If you are building an app surface like DataConnect Desktop or a hosted orchestration layer, use the SDK modules instead of shelling out to the CLI where possible.
import { ManagedPlaywrightRuntime } from "vana-cli/runtime";
import { listAvailableSources } from "vana-cli/connectors";Intended split:
- app surfaces consume SDK/runtime APIs
- agent skills consume the CLI
data-connectorsremains the connector and schema source of truth
pnpm add vana-cliThis repo is pnpm-only for local development and examples. Use pnpm commands, not npm.
First, register your app in the Developer Portal. You will need to provide the URL where your app will be deployed, and then be given a private key after registration.
import { connect } from "vana-cli/server";
const session = await connect({
privateKey: process.env.VANA_APP_PRIVATE_KEY as `0x${string}`,
scopes: ["chatgpt.conversations"],
webhookUrl: "https://yourapp.com/api/webhook", // optional, data can be pushed to a web hook after a grant is approved
appUserId: "yourapp-user-42", // optional: correlate your app user with the data they provided
});
// Return to your frontend:
// session.sessionId — used for polling
// session.connectUrl — opens the Vana account page → launches DataConnect
// session.expiresAt — ISO 8601 expirationimport { useVanaConnect } from "vana-cli/react";
function ConnectData({ sessionId }: { sessionId: string }) {
const { connect, status, grant, connectUrl } = useVanaConnect();
useEffect(() => {
connect({ sessionId });
}, [sessionId]);
if (status === "waiting" && connectUrl) {
return <a href={connectUrl}>Connect your data</a>;
}
if (status === "approved" && grant) {
// grant.grantId, grant.userAddress, grant.scopes are available
return <p>Connected.</p>;
}
return <p>{status}</p>;
}Or use the pre-built button:
import { ConnectButton } from "vana-cli/react";
<ConnectButton
sessionId={sessionId}
onComplete={(grant) => saveGrant(grant)}
onError={(err) => console.error(err)}
/>;import { getData } from "vana-cli/server";
const data = await getData({
privateKey: process.env.VANA_APP_PRIVATE_KEY as `0x${string}`,
grant, // GrantPayload from step 2
});
// Record<string, unknown> keyed by scope
const conversations = data["chatgpt.conversations"];The DataConnect App verifies your identity by fetching your manifest. Use signVanaManifest() to generate it:
import { signVanaManifest } from "vana-cli/server";
// In your manifest route handler (e.g. Next.js /manifest.json/route.ts):
const vanaBlock = await signVanaManifest({
privateKey: process.env.VANA_APP_PRIVATE_KEY as `0x${string}`,
appUrl: "https://yourapp.com",
privacyPolicyUrl: "https://yourapp.com/privacy",
termsUrl: "https://yourapp.com/terms",
supportUrl: "https://yourapp.com/support",
webhookUrl: "https://yourapp.com/api/webhook",
});
const manifest = {
name: "Your App",
short_name: "YourApp",
start_url: "/",
display: "standalone",
vana: vanaBlock, // signed identity block
};Make sure your HTML includes <link rel="manifest" href="/manifest.json">.
Available data connectors and their scopes (schema definitions):
vana-com/data-connectors/schemas
| Import | Environment | Exports |
|---|---|---|
vana-cli/server |
Node.js | connect(), getData(), signVanaManifest(), low-level clients |
vana-cli/react |
Browser | useVanaConnect(), useVanaData(), ConnectButton |
vana-cli/core |
Universal | Types, ConnectError, constants |
Creates a session on the Session Relay. Returns sessionId, connectUrl, and expiresAt.
| Param | Type | Required | Description |
|---|---|---|---|
privateKey |
`0x${string}` |
Yes | Builder private key |
scopes |
string[] |
Yes | Data scopes to request |
webhookUrl |
string |
No | Public HTTPS URL for grant event notifications (localhost is rejected) |
appUserId |
string |
No | Your app's user ID for correlation |
Fetches user data from their Personal Server using a signed grant.
| Param | Type | Required | Description |
|---|---|---|---|
privateKey |
`0x${string}` |
Yes | Builder private key |
grant |
GrantPayload |
Yes | Grant from the approval step |
React hook that polls the Session Relay and manages connection state.
const { connect, status, grant, error, connectUrl, reset } = useVanaConnect();status transitions: idle → connecting → waiting → approved | denied | expired | error
Returned when a user approves access:
interface GrantPayload {
grantId: string; // on-chain permission ID
userAddress: string; // user's wallet address
builderAddress: string; // your registered address
scopes: string[]; // approved data scopes
serverAddress?: string; // user's Personal Server
appUserId?: string; // your app's user ID (if provided)
}For full control over individual protocol interactions:
import {
createRequestSigner, // Web3Signed header generation
createSessionRelay, // Session Relay HTTP client
createDataClient, // Data Gateway HTTP client
} from "vana-cli/server";MIT