Arkade Wallet is the entry-point to the Arkade ecosystem—a self-custodial Bitcoin wallet delivered as a lightweight Progressive Web App (installable on mobile or desktop in seconds, no app-store gatekeepers). Built around the open-source ARK protocol, it speaks natively to any arkd instance, letting you create, send, and receive Virtual Transaction Outputs (VTXOs) for instant, off-chain pre-confirmations and batched, fee-efficient on-chain settlement.
|
|
Minting with a new control asset requires two separate issuances. The wallet saves a local recovery record before submitting each one and imports the control asset as soon as its issuance is known. If the control asset is not yet spendable, the wait ends after 60 seconds; return to the mint screen and resume the original mint without issuing another control asset. This flow requires Web Locks support and a secure browser context.
If an issuance's outcome is unknown (for example, the browser closed while submitting it), the wallet cannot determine safely whether retrying would create a duplicate. Check wallet activity and contact support before discarding the recovery record. Discarding it or clearing browser storage can make a later mint incur another fee. Recovery records are stored in this browser, not in the Nostr backup; use the same wallet and Arkade server to resume.
| Variable | Description | Example Value |
|---|---|---|
VITE_ARK_SERVER |
Override the default Arkade server URL | VITE_ARK_SERVER=http://localhost:7070 |
VITE_APP_VERSION |
App version string shown in support diagnostics | VITE_APP_VERSION=1.2.3 |
VITE_CHATWOOT_WEBSITE_TOKEN |
ChatWoot website token for customer support integration | VITE_CHATWOOT_WEBSITE_TOKEN=your-token |
VITE_CHATWOOT_BASE_URL |
ChatWoot server base URL for customer support integration | VITE_CHATWOOT_BASE_URL=https://app.chatwoot.com |
VITE_DELEGATOR_URL |
Delegator service URL for the wallet service worker | VITE_DELEGATOR_URL=https://delegator.example.com |
VITE_MAX_PERCENTAGE |
Override the max fee percentage (default 10) | VITE_MAX_PERCENTAGE=5 |
VITE_NOSTR_RELAY_URL |
Override the default Nostr relay URLs for backup | VITE_NOSTR_RELAY_URL=wss://relay.example.com |
VITE_SENTRY_DSN |
Enable Sentry error tracking (only in production, not on localhost) | VITE_SENTRY_DSN=your-sentry-dsn |
VITE_UTXO_MAX_AMOUNT |
Override the server's utxoMaxAmount | VITE_UTXO_MAX_AMOUNT=-1 |
VITE_UTXO_MIN_AMOUNT |
Override the server's utxoMinAmount | VITE_UTXO_MIN_AMOUNT=330 |
VITE_VERIFIED_ASSETS_URL |
URL to fetch the verified assets list | VITE_VERIFIED_ASSETS_URL=https://arklabshq.github.io/asset-registry/mutinynet.json |
VITE_VTXO_MAX_AMOUNT |
Override the server's vtxoMaxAmount | VITE_VTXO_MAX_AMOUNT=-1 |
VITE_VTXO_MIN_AMOUNT |
Override the server's vtxoMinAmount | VITE_VTXO_MIN_AMOUNT=330 |
CI |
Set to true for Continuous Integration environments |
CI=true |
GENERATE_SOURCEMAP |
Disable source map generation during build | GENERATE_SOURCEMAP=false |
The wallet is available as a Docker image on GitHub Container Registry.
docker pull ghcr.io/arkade-os/wallet:latest
docker run -p 8080:80 ghcr.io/arkade-os/wallet:latestOpen http://localhost:8080 to view the wallet.
Environment variables can be passed at runtime to configure the wallet without rebuilding the image:
docker run -p 8080:80 \
-e VITE_ARK_SERVER=https://arkade.computer \
ghcr.io/arkade-os/wallet:latestSee the Environment Variables table for all supported variables.
docker build -t arkade-wallet .
# With build-time configuration
docker build \
--build-arg VITE_ARK_SERVER=https://arkade.computer \
-t arkade-wallet .The policy is served by nginx (nginx-security-headers.conf) for Docker and by public/_headers for Cloudflare
Pages. Both are static, so:
- Setting
VITE_CHATWOOT_BASE_URLto a host other thanhttps://app.chatwoot.comrequires adding that origin toscript-srcin the file your deployment uses. - The inline theme bootstrap in
index.htmlis allowed by hash.pnpm csp:check(run on pre-commit and beforepnpm build) verifies it;pnpm csp:fixupdates it after editing that block. public/_headersallowshttps://static.cloudflareinsights.combecause Cloudflare Web Analytics injects its beacon into HTML responses at the edge, so the script is not in the build. Beware of Cloudflare features that inject inline script — Rocket Loader, Email Obfuscation — which the hash-onlyscript-srcblocks andpnpm csp:checkcannot catch, since it only sees the builtindex.html.
- Node.js v24.22.1 (see
.nvmrc) - PNPM >=8
Install dependencies
pnpm installRuns the app in the development mode.
Open http://localhost:3002 to view it in the browser.
The page will reload if you make edits.
You will also see any lint errors in the console.
Builds the app for production to the dist folder.
It correctly bundles React in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.
Your app is ready to be deployed!
Starts the regtest environment and sets up the arkd instance.
Requires Docker and Node.js v20.19+ or v22.12+. The stack is driven by the in-house
arkade-regtest Node CLI (regtest/regtest.mjs) — no Nigiri required.
Use pnpm run regtest:stop to stop it and pnpm run regtest:clean to tear it down.
To interact with Ark features, you need Regtest coins.
- Copy your address from the wallet's Receive screen (ensure it starts with bcrt1 for Regtest).
- Run the faucet command (the
--confirmflag mines a block so the deposit confirms):
node regtest/regtest.mjs faucet <bcrt-address> <btc> --confirmnote: e2e tests require a regtest environment to be running.
pnpm run regtest:startto start and setup the regtest environment.
note: e2e tests use playwright for ui testing, you may need to run
pnpm exec playwright installonce to download new browsers.
Run the tests with:
pnpm run test:e2eRun the tests in interactive mode with:
pnpm run test:e2e --uiAccess the playwright code generator tool with:
pnpm run test:codegenOn CI the suite runs as four parallel jobs: two browser projects (Mobile Chrome,
Google Chrome) times two file groups defined in .github/workflows/playwright.yml:
assets-send:asset.test.ts,send.test.tscore: every other file insrc/test/e2e/
The groups list files explicitly, so a new test file must be added to one of them, otherwise it will never run on CI.
Another site can open the wallet with a query string. The wallet asks before it shares an address or sends funds, then returns to callback by navigating there. Build the link with URLSearchParams — a BIP21 and a callback are both URLs, and raw & / ? will be parsed as the wallet's own query.
Connect (the address a user would copy from Receive, plus the x-only public key):
https://arkade.money/?action=connect&callback=https%3A%2F%2Farkade.trade%2Fconnect
Approval opens callback?address=<ark address>&pubkey=<64 hex chars>. Decline opens callback?error=denied.
Pay (the existing send screen, prefilled — nothing is broadcast until the user signs):
https://arkade.money/?action=send&request=<percent-encoded BIP21>&callback=https%3A%2F%2Farkade.trade%2Fvault
Success opens callback?status=sent&txid=<txid> when there is a txid. sent reports that the payment was committed; for swaps, txid is the funding transaction. An onchain swap keeps the wallet open and defers this callback until its payout claim is broadcast. Backing out opens callback?error=denied. callback is optional on send.
Error codes in callback?error=<code>: denied (the user declined or backed out) and invalid (the request was malformed, such as a bad action, address, or BIP21; sent only when the request still carried a valid callback).
callback must be https, or http on localhost, 127.0.0.1, or [::1]. The whole query must stay under 6000 characters. The wallet appends its params; it does not fill a template, and it will not leave a pre-set address in place on decline.
An installed wallet on Chrome or Edge also handles the web+arkade protocol (public/manifest.json sends it to the hash). The actions are the same:
web+arkade://connect?callback=https%3A%2F%2Farkade.trade%2Fconnect
web+arkade://send?request=<percent-encoded BIP21>&callback=https%3A%2F%2Farkade.trade%2Fvault
The browser asks once before it lets the installed app own that protocol. Safari has no manifest protocol handler, so an iOS app uses the https link, which opens in the browser. That page shows Open in App: Chrome and Edge launch web+arkade:// in the installed app, and Safari explains that it cannot switch there, so the request stays on this page. Ark notes keep using web+arkade:// and are not treated as connect or send.
macOS AirPlay Receiver uses port 5000 by default, which conflicts with the regtest stack.
- Fix: Go to
System Settings > General > AirDrop & Handoffand disable AirPlay Receiver.

