The personal namespace methods manage private keys and should only be used on trusted nodes. Never use these methods over untrusted connections or expose them publicly.
Overview
The personal namespace provides methods for managing accounts, signing messages, and handling wallet operations.
Account Management
personal_newAccount
Creates a new account and returns its address.
curl -X POST -H "Content-Type: application/json" \
--data '{"jsonrpc":"2.0","method":"personal_newAccount","params":["your-password"],"id":1}' \
http://localhost:8545
Password to encrypt the account
The address of the newly created account
Example Response:
{
"jsonrpc" : "2.0" ,
"id" : 1 ,
"result" : "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"
}
personal_listAccounts
Returns a list of addresses owned by the client.
curl -X POST -H "Content-Type: application/json" \
--data '{"jsonrpc":"2.0","method":"personal_listAccounts","params":[],"id":1}' \
http://localhost:8545
Array of account addresses
Example Response:
{
"jsonrpc" : "2.0" ,
"id" : 1 ,
"result" : [
"0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb" ,
"0x1234567890123456789012345678901234567890"
]
}
personal_unlockAccount
Unlocks an account for a specified duration.
curl -X POST -H "Content-Type: application/json" \
--data '{"jsonrpc":"2.0","method":"personal_unlockAccount","params":["0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb","password",300],"id":1}' \
http://localhost:8545
Address of the account to unlock
Password to decrypt the account
Duration in seconds to keep the account unlocked (default: 300)
true if the account was successfully unlocked
Unlocking accounts on production nodes is a security risk. Use signed transactions instead.
personal_lockAccount
Locks an account, removing the decrypted private key from memory.
curl -X POST -H "Content-Type: application/json" \
--data '{"jsonrpc":"2.0","method":"personal_lockAccount","params":["0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"],"id":1}' \
http://localhost:8545
Address of the account to lock
true if the account was successfully locked
Key Import
personal_importRawKey
Imports a private key and creates a new account.
curl -X POST -H "Content-Type: application/json" \
--data '{"jsonrpc":"2.0","method":"personal_importRawKey","params":["0x1234...","password"],"id":1}' \
http://localhost:8545
Private key (hex encoded, 64 characters without 0x prefix)
Password to encrypt the account
Address of the imported account
Never share your private keys. Only import keys on secure, trusted nodes.
Wallet Operations
personal_listWallets
Returns a list of wallets managed by the node.
Array of wallet objects Wallet status (e.g., “Locked”, “Unlocked”)
Array of account objects in the wallet
personal_openWallet
Opens a hardware wallet.
Wallet URL (e.g., “ledger://”, “trezor://”)
Passphrase (optional, required for some hardware wallets)
personal_deriveAccount
Derives a new account from a hardware wallet.
Derivation path (e.g., “m/44’/60’/0’/0/0”)
Whether to pin the derived account
Derived account information
Transaction Signing
personal_sendTransaction
Sends a transaction from an unlocked account.
curl -X POST -H "Content-Type: application/json" \
--data '{"jsonrpc":"2.0","method":"personal_sendTransaction","params":[{"from":"0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb","to":"0x1234567890123456789012345678901234567890","value":"0xde0b6b3a7640000"},"password"],"id":1}' \
http://localhost:8545
Transaction object Value to transfer in wei (hex)
personal_signTransaction
Signs a transaction without sending it.
Transaction object (same structure as personal_sendTransaction)
Signed transaction RLP-encoded signed transaction (hex)
Transaction object with signature fields (r, s, v)
Message Signing
personal_sign
Signs arbitrary data with an account.
curl -X POST -H "Content-Type: application/json" \
--data '{"jsonrpc":"2.0","method":"personal_sign","params":["0x48656c6c6f20576f726c64","0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb","password"],"id":1}' \
http://localhost:8545
Data to sign (hex encoded)
65-byte signature (hex encoded)
Example Response:
{
"jsonrpc" : "2.0" ,
"id" : 1 ,
"result" : "0x1234567890abcdef..."
}
The signature includes the prefix “\x19Ethereum Signed Message:\n” + message length before hashing, following EIP-191.
personal_ecRecover
Recovers the address that signed a message.
curl -X POST -H "Content-Type: application/json" \
--data '{"jsonrpc":"2.0","method":"personal_ecRecover","params":["0x48656c6c6f20576f726c64","0x1234567890abcdef..."],"id":1}' \
http://localhost:8545
Original message (hex encoded)
Signature (65 bytes, hex encoded)
Address that signed the message
Usage Examples
JavaScript (Web3.js)
const Web3 = require ( 'web3' );
const web3 = new Web3 ( 'http://localhost:8545' );
// Create new account
const newAccount = await web3 . eth . personal . newAccount ( 'password' );
console . log ( 'New account:' , newAccount );
// List accounts
const accounts = await web3 . eth . personal . getAccounts ();
console . log ( 'Accounts:' , accounts );
// Sign message
const signature = await web3 . eth . personal . sign (
'Hello World' ,
accounts [ 0 ],
'password'
);
console . log ( 'Signature:' , signature );
// Recover signer
const signer = await web3 . eth . personal . ecRecover (
'Hello World' ,
signature
);
console . log ( 'Signer:' , signer );
// Send transaction
const txHash = await web3 . eth . personal . sendTransaction ({
from: accounts [ 0 ],
to: '0x1234567890123456789012345678901234567890' ,
value: web3 . utils . toWei ( '1' , 'ether' )
}, 'password' );
console . log ( 'Transaction:' , txHash );
Python (Web3.py)
from web3 import Web3
w3 = Web3(Web3.HTTPProvider( 'http://localhost:8545' ))
# Create new account
new_account = w3.geth.personal.new_account( 'password' )
print ( f 'New account: { new_account } ' )
# List accounts
accounts = w3.geth.personal.list_accounts()
print ( f 'Accounts: { accounts } ' )
# Sign message
message = 'Hello World'
signature = w3.geth.personal.sign_typed_data(
accounts[ 0 ],
message,
'password'
)
print ( f 'Signature: { signature.hex() } ' )
# Send transaction
tx_hash = w3.geth.personal.send_transaction({
'from' : accounts[ 0 ],
'to' : '0x1234567890123456789012345678901234567890' ,
'value' : w3.toWei( 1 , 'ether' )
}, 'password' )
print ( f 'Transaction: { tx_hash.hex() } ' )
Security Best Practices
Critical Security Considerations
Never expose personal namespace methods over public RPC endpoints
Always use strong, unique passwords for accounts
Never share private keys or passwords
Use hardware wallets for production environments
Prefer signing transactions offline and using eth_sendRawTransaction
Recommended Approach
Instead of using personal_sendTransaction, consider:
// Better: Sign offline and send raw transaction
const signedTx = await web3 . eth . accounts . signTransaction ({
to: '0x1234567890123456789012345678901234567890' ,
value: web3 . utils . toWei ( '1' , 'ether' ),
gas: 21000
}, privateKey );
const receipt = await web3 . eth . sendSignedTransaction (
signedTx . rawTransaction
);
Account Storage
Accounts created with personal_newAccount are stored encrypted in the keystore directory:
~/.ethereum/keystore/ (default location)
Backup these files securely and never lose your password.