controller-sessions
Controller Sessions & Policies
Session policies define which contracts and methods your app can call.
They are required for session-based transaction execution — without policies, execute() will fail with error code 130 ("Array length mismatch") because the Controller's on-chain session validation requires a merkle proof for each call.
Without policies, Controller falls back to manual approval via the keychain modal. On local Katana, policies are required because new Controller accounts cannot be properly deployed without them.
How Sessions Work
- Define policies (which contracts/methods your app needs)
- User approves policies once during connection
- Controller creates session with approved permissions
- Transactions execute seamlessly via Paymaster
Defining Policies
import { SessionPolicies } from "@cartridge/controller";
const policies: SessionPolicies = {
contracts: {
"0x1234...": {
name: "My Game",
description: "Game contract interactions",
methods: [
{
name: "Move Player",
entrypoint: "move_player",
description: "Move player on the map",
},
{
name: "Attack",
entrypoint: "attack",
},
],
},
},
};
const controller = new Controller({ policies });
Token Spending Limits
For approve methods, specify spending limits in hex format:
const policies: SessionPolicies = {
contracts: {
// ETH contract
"0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7": {
name: "Ethereum",
methods: [
{
name: "approve",
entrypoint: "approve",
spender: "0x1234567890abcdef1234567890abcdef12345678",
amount: "0x3", // Limit: 3 ETH (hex, accounts for decimals)
},
],
},
},
};
- Use
0xfffffffffffffffffffffffffffffffffor unlimited (max uint128) - Users see USD values alongside token amounts when price data is available
Signed Message Policies
Pre-approve typed message signing:
const policies: SessionPolicies = {
messages: [
{
name: "Game Message",
types: {
StarknetDomain: [
{ name: "name", type: "shortstring" },
{ name: "version", type: "shortstring" },
{ name: "chainId", type: "shortstring" },
{ name: "revision", type: "shortstring" },
],
GameMessage: [
{ name: "content", type: "string" },
{ name: "timestamp", type: "felt" },
],
},
primaryType: "GameMessage",
domain: {
name: "MyGame",
version: "1",
chainId: "SN_MAIN",
revision: "1",
},
},
],
};
Error Handling
Error Display Modes
const controller = new Controller({
policies,
errorDisplayMode: "notification", // "modal" | "notification" | "silent"
});
- modal (default): Full error modal, blocks interaction
- notification: Toast notification (clickable to open modal), non-blocking
- silent: Console only, custom handling required
Error Handling Interaction
propagateSessionErrors |
errorDisplayMode |
Behavior |
|---|---|---|
true |
Any | Errors rejected immediately, no UI shown |
false (default) |
modal |
Opens controller modal |
false |
notification |
Shows clickable toast |
false |
silent |
No UI, logged to console |
Error Propagation
Return errors to your app instead of showing keychain UI:
import { Controller, ResponseCodes } from "@cartridge/controller";
const controller = new Controller({
policies,
propagateSessionErrors: true,
});
const result = await account.execute(calls);
if (result.code === ResponseCodes.SUCCESS) {
console.log("Tx hash:", result.transaction_hash);
} else if (result.code === ResponseCodes.ERROR) {
console.error(result.message, result.error);
}
Note: SessionRefreshRequired and ManualExecutionRequired always show modal regardless of settings.
Disconnect Redirect
For mobile apps and cross-platform logout flows:
const connector = new SessionConnector({
policies,
rpc: "https://api.cartridge.gg/x/starknet/mainnet",
chainId: "SN_MAIN",
redirectUrl: "myapp://callback",
disconnectRedirectUrl: "myapp://logout", // Where to go after logout
});
Verified Sessions
Verified policies display trust badges and streamlined approval flows.
Submit configs to @cartridge/presets for verification.
SessionOptions Type
type SessionOptions = {
rpc: string; // RPC endpoint URL
chainId: string; // Chain ID
policies: SessionPolicies; // Approved transaction policies
redirectUrl: string; // URL to redirect after auth
disconnectRedirectUrl?: string; // URL to redirect after logout
signupOptions?: AuthOptions; // Auth methods to show
};
More from cartridge-gg/docs
controller-setup
Integrate Cartridge Controller wallet into Starknet applications. Use when setting up Controller for the first time, installing packages, configuring chains/RPC endpoints, or troubleshooting basic integration issues. Covers installation, Controller instantiation, ControllerConnector vs SessionConnector choice, chain configuration, and package compatibility.
69controller-react
Integrate Cartridge Controller into React applications using starknet-react. Use when building React/Next.js web apps with Controller, setting up StarknetConfig provider, using hooks like useConnect/useAccount, or implementing wallet connection components. Covers ControllerConnector setup, provider configuration, and transaction execution patterns.
67controller-signers
Configure authentication methods for Cartridge Controller including passkeys, social login, and external wallets. Use when implementing user authentication, adding multiple signers for account recovery, customizing signup options, or integrating external wallets like MetaMask or Phantom. Covers WebAuthn passkeys, Google/Discord/Twitter OAuth, wallet connections, and dynamic authentication flows.
65controller-backend
Integrate Cartridge Controller into backend services using Node.js, Rust, or headless mode. Use when building server-side applications, game backends, automated bots, or any non-browser environment that needs to execute Starknet transactions. Covers SessionProvider for Node.js, Rust SDK setup, and headless Controller with custom signing keys.
61slot-vrng
Integrate Cartridge's verifiable random number generator (vRNG) into onchain games.
59slot-rpc
Configure Cartridge RPC endpoints with API token authentication and CORS whitelisting.
58