.near
account receives a subdomain under https://near.pagethewiki.near
serves https://thewiki.near.pageQuick 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
🎉
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.
Web4 provides simplified authentication flow:
/web4/login
endpoint/web4/logout
endpoint web4_account_id
cookieweb4_private_key
cookie/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:
Featured sites:
Community sites:
See more examples at https://awesomeweb4.near.page
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.
@nearBindgen
class Web4Request {
accountId: string | null;
path: string;
params: Map<string, string>;
query: Map<string, Array<string>>;
preloads: Map<string, Web4Response>;
}
@nearBindgen
class Web4Response {
contentType: string;
status: u32;
body: Uint8Array;
bodyUrl: string;
preloadUrls: string[] = [];
cacheControl: string;
}
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
.
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.
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:
Check out sample web4 project made with Rust.
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.
This works same as near.page
but for contracts deployed on testnet. Every account.testnet
gets corresponding account.testnet.page
domain.
mkcert -install
*.near.page
SSL certificate:mkcert "*.near.page"
web4
man-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
http://localhost:8080/
or to use localhost:8080
as an HTTPS proxy server.See also:
NODE_ENV
- mainnet
or testnet
to select network ID to use with NEAR config and key storeIPFS_GATEWAY_URL
- URL of IPFS gateway to use for ipfs://
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 when WEB4_KEY_FILE
and WEB4_CERT_FILE
are provided.FAST_NEAR_URL
- URL of fast-near RPC server to use for NEAR API. Overrides NEAR RPC config selected by NODE_ENV
.Authentication is handled through /web4/login
and /web4/logout
endpoints. Account information is stored in cookies, with the current account ID available in web4_account_id
cookie. Example usage:
// Login
window.location.href = '/web4/login'
// Get current user
const accountId = Cookies.get('web4_account_id')
See the Authentication section above for more details.
Using web4's authentication endpoints allows your application to remain wallet-agnostic. Your app will continue working without modifications as wallet implementations change. See wallet integration guide for comparison.
NEARFS is the recommended way to store large files on web4. Deploy files using:
npx web4-deploy --nearfs ./path/to/files
See web4-deploy docs for more options.
Yes! Start with the Rust starter project:
git clone https://github.com/zavodil/near-web4-contract
cd near-web4-contract
./build.sh
Use web4-deploy:
npx web4-deploy ./dist
This uploads files to IPFS/NEARFS and updates your smart contract. See deployment guide.
Use the web4 RPC endpoint:
curl https://rpc.web4.near.page/account/your-account.near/state
Deploy a web4 contract implementing the NEP-171 standard. Example:
git clone https://github.com/near-examples/NFT
cd NFT
yarn deploy
Run local web4 gateway:
npx web4-near
Then access your app at https://your-account.near.page
Yes, if the RPC indexer falls behind the latest blocks. Check indexer status:
curl https://rpc.web4.near.page/status
Subaccounts are not currently supported by web4. Use custom domains instead - see custom domain setup guide.
This project aims to make trade offs based on these priorities:
npx
web4_raw_get
)We welcome contributions to web4! Here's how you can help:
Join our Telegram group to discuss ideas, ask questions, and connect with other developers.
We need more example applications, especially: