Web4
Web4 is a new way to distribute decentralized apps. Deploy single WASM smart contract to deploy whole web app.
Install / Use
/learn @vgrichina/Web4README
web4
Table of Contents
- TL;DR
- What is web4?
- How it works?
- Known web4 sites
- Useful tools
- Example contract
- Rust support
- Deployment
- Running locally
- FAQ
- Priorities
- Roadmap
- Contributing
TL;DR
- Manage website frontend in smart contract
- Every
.nearaccount receives a subdomain under https://near.page- E.g.
thewiki.nearserves https://thewiki.near.page
- E.g.
- Use IPFS with Filecoin to host larger files
Quick Start:
# Create a simple website
mkdir my-web4-site && cd my-web4-site
echo '<h1>Hello Web4!</h1>' > index.html
# Deploy to your account
npx web4-deploy . --accountId your-account.near
Your site will be live at https://your-account.near.page 🎉
What is web4?
- Decentralised ownership and hosting
- Content permanence by default, no more expired links
- Offline friendly
- Web presence controlled by user
- Interactive mobile apps linked together as websites, no appstores
How it works?
You only need to deploy single smart contract using WebAssembly to host your app HTTP backend, static resources and blockchain logic. See Example contract or Rust support for implementation details.
There is an HTTP gateway to NEAR blockchain which allows smart contract to handle arbitrary GET requests.
Every smart contract on NEAR also gets corresponding API endpoint which can be accessed through regular HTTP requests.
Authentication
Web4 provides simplified authentication flow:
- Login via
/web4/loginendpoint - Logout via
/web4/logoutendpoint - Current account ID is available via
web4_account_idcookie - App-specific private key, if used, is stored in
web4_private_keycookie - Transactions can be submitted via POST requests to
/web4/contract/{contract_id}/{method_name}
Example usage in JavaScript:
// Login
window.location.href = '/web4/login'
// Check if user is logged in
const accountId = Cookies.get('web4_account_id');
// Logout
window.location.href = '/web4/logout'
// Submit transaction
await fetch('/web4/contract/example.near/someMethod', {
method: 'POST',
body: JSON.stringify({ param1: 'value1' })
})
This allows seamless integration with existing web frameworks while maintaining security through NEAR wallet.
See also:
Known web4 sites
Featured sites:
- https://devhub.near.page - NEAR Developer Hub
- https://web4.near.page - Web4 project homepage
- https://treasury-auroralabs.near.page - NEAR Treasury DAOs
- https://svelt.near.page - Svelte starter template
- https://awesomeweb4.near.page - Web4 app catalog
- https://thewiki.near.page - Decentralized wiki
Community sites:
- https://slimebook.near.page
- https://lands.near.page
- https://zavodil.near.page
- https://psalomo.near.page
- https://oracle-prices.near.page
- https://orangejoe.near.page
- https://orderly.near.page
- https://theegg.near.page
- https://twelvetone.near.page
- https://sotg.near.page
- https://pcards.near.page
- https://aclot.near.page
- https://wlog.near.page
- https://1chess.near.page
- https://vlad.near.page
See more examples at https://awesomeweb4.near.page
Useful tools
- HTTP gateway https://github.com/vgrichina/web4
- High performance RPC https://github.com/vgrichina/fast-near
- Deploy tool https://github.com/vgrichina/web4-deploy
- Rust starter projects:
- https://github.com/zavodil/near-web4-contract
- https://github.com/frol/near-web4-demo
- Self-hosted Linktree https://github.com/vgrichina/web4-littlelink
- Svelte starter http://svelt.near.page
- Web4 app catalog https://awesomeweb4.near.page
Example contract (in AssemblyScript)
export function web4_get(request: Web4Request): Web4Response {
if (request.path == '/test') {
// Render HTML with form to submit a message
return htmlResponse(form({ action: "/web4/contract/guest-book.testnet/addMessage" }, [
textarea({ name: "text" }),
button({ name: "submit" }, ["Post"])
]));
}
if (request.path == '/messages') {
const getMessagesUrl = '/web4/contract/guest-book.testnet/getMessages';
// Request preload of dependency URLs
if (!request.preloads) {
return preloadUrls([getMessagesUrl]);
}
// Render HTML with messages
return htmlResponse('messages: ' + util.bytesToString(request.preloads.get(getMessagesUrl).body)!);
}
if (request.accountId) {
// User is logged in, we can welcome them
return htmlResponse('Hello to <b>' + request.accountId! + '</b> from <code>' + request.path + '</code>');
}
// Demonstrate serving content from IPFS
if (request.path == "/") {
return bodyUrl('ipfs://bafybeib72whzo2qiore4q6sumdteh6akewakrvukvqmx4n6kk7nwzinpaa/')
}
// By default return 404 Not Found
return status(404);
}
Basically smart contract just needs to implement web4_get method to take in and return data in specific format.
Request
@nearBindgen
class Web4Request {
accountId: string | null;
path: string;
params: Map<string, string>;
query: Map<string, Array<string>>;
preloads: Map<string, Web4Response>;
}
Response
@nearBindgen
class Web4Response {
contentType: string;
status: u32;
body: Uint8Array;
bodyUrl: string;
preloadUrls: string[] = [];
cacheControl: string;
}
Loading data
You can load any required data in web4_get by returning list of URLs to preload in preloadUrls field.
E.g. contract above preloads /web4/contract/guest-book.testnet/getMessages. This class getMessages view method on guest-book.testnet contract.
After data is preloaded web4_get gets called again with loaded data injected into preloads.
Posting transactions
You can post transaction by making a POST request to corresponding URL.
E.g contract above preloads has form that gets posted to /web4/contract/guest-book.testnet/addMessage URL. This URL submits transaction which calls addMessage method on guest-book.testnet contract.
Note that both JSON and form data are supported. When transaction is processed by server user gets redirected to wallet for signing this transaction.
In future there is a plan to allow sending app-specific key as a cookie to sign limited subset of transactions without confirmation in wallet.
Caching considerations
By default all HTML responses can be cached for 1 minute (assumed dynamic content). All images, videos, audio and CSS can be cached for 1 day (assumed static content).
You can override this by setting cacheControl field in response.
It's not recommended to cache content for too long as then it not going to be hot on IPFS gateway.
See also:
- Rust support
- Known web4 sites for real-world examples
Rust support
Check out sample web4 project made with Rust.
near.page
You can access your deployed smart contract on https://near.page. This is hosted web4 gateway provided to all .near accounts. For now it's free, but in future you might have to pay depending on how much traffic you get.
Every contract gets corresponding domain, e.g. check out https://web4.near.page rendered by web4.near contract.
testnet.page
This works same as near.page but for contracts deployed on testnet. Every account.testnet gets corresponding account.testnet.page domain.
Running locally
- Install mkcert.
- Install local certificate authority (this allows browser to trust self-signed certificates):
mkcert -install - Create
*.near.pageSSL certificate:mkcert "*.near.page" - Run
web4man-in-the-middle proxy locally:IPFS_GATEWAY_URL=https://ipfs.near.social NODE_ENV=mainnet WEB4_KEY_FILE=./_wildcard.near.page-key.pem WEB4_CERT_FILE=./_wildcard.near.page.pem npx web4-near - Setup browser to use automatic proxy configuration file at
http://localhost:8080/or to uselocalhost:8080as an HTTPS proxy server.
See also:
- FAQ: How can I access my local app bundle?
- near.page and testnet.page for production deployment
Environment variables
NODE_ENV-mainnetortestnetto select network ID to use with NEAR config and key storeIPFS_GATEWAY_URL- URL of IPFS gateway to use foripfs://URLsWEB4_KEY_FILE- path to SSL key fileWEB4_CERT_FILE- path to SSL certificate filePORT- port to listen on (default:3000)PROXY_PORT- port to listen on for proxy requests (default:8080). HTTPS MITM proxy is run on this port whenWEB4_KEY_FILEandWEB4_CERT_FILEare provided.FAST_NEAR_URL- URL of fast-near RPC server to use for NEAR API
Related Skills
himalaya
350.8kCLI to manage emails via IMAP/SMTP. Use `himalaya` to list, read, write, reply, forward, search, and organize emails from the terminal. Supports multiple accounts and message composition with MML (MIME Meta Language).
taskflow
350.8kname: taskflow description: Use when work should span one or more detached tasks but still behave like one job with a single owner context. TaskFlow is the durable flow substrate under authoring layer
tmux
350.8kRemote-control tmux sessions for interactive CLIs by sending keystrokes and scraping pane output.
coding-agent
350.8kDelegate coding tasks to Codex, Claude Code, or Pi agents via background process
