• English
  • Russian


Please note that zkApp programmability is not yet available on Mina Mainnet, but zkApps can now be deployed to Berkeley QANet.

How to write a zkApp UI

Learn how to write an UI for your smart contract

To allow users to interact with your smart contract, you’ll typically want to build a website UI.

This UI can be written with any framework (e.g. React, Vue, Svelte, etc.) or plain HTML and JavaScript.


This page is a work in progress.

Adding your smart contract as a dependency of the UI


You can integrate your smart contract by publishing it to npm and adding it as a
dependency of your UI.

Publish to npm

The index.ts file is the entry point of your project. This file only imports all smart contract classes you want access to, and exports them. This pattern allows you to specify which smart contracts are available to import when consuming your project from npm within your UI.

import { YourSmartContract } from './YourSmartContract.js';

export { YourSmartContract };
  1. Create an npm account: Create one here if you don't have one yet.
  2. Login: To sign in, enter npm login on the command line. You will be prompted to enter your username, password, and email address.
  3. Publish: To publish your package, enter npm publish on the command line at the root of your smart contract project directory. If the package name already exists on npm, you will get an error. You can change the package name by changing the name property in your package.json.


You can check if a package name already exists on npm using the npm search terminal command. To avoid naming collisions, npm allows to publish scoped packages: @your-username/your-package-name. For additional details about publishing packages including scoped packages, see the full npm reference docs.

Consuming your smart contract in your UI

Once you have published your smart contract to npm, you can easily add it to any UI framework of your choosing by importing the package.

  1. Install your smart contract package: To install your package, run the following npm command: npm install your-package-name from the root of your UI project directory. Or if you published a scoped npm package, run npm install @your-username/your-project-name.
  2. Import your smart contract package into the UI using: import { YourSmartContract } from ‘your-smart-contract’; , where YourSmartContract is the named export that you chose in your smart contract.


For a more performant UI, you may want to render your UI before importing and loading your smart contract. This allows the SnarkyJS wasm workers to perform initialization without blocking the UI.

For example, if your UI is built using React, loading the smart contract in a useEffect, instead of a top level import, will give the UI time to render its components before loading SnarkyJS.

Loading your contract with React

useEffect(() => {
  (async () => {
    const { YourSmartContract } = await import("your-smart-contract");
}, []);

Loading your contract with Svelte

onMount(async () => {
  const { YourSmartContract } = await import("your-smart-contract");

Loading your contract with Vue

onMounted(async () => {
  const { YourSmartContract } = await import("your-smart-contract");

Enabling the COOP and COEP headers

To successfully load any SnarkyJS code in your UI, you must set the COOP and COEP headers to set up a cross-origin isolated environment that enables the use of SharedArrayBuffer. SnarkyJS relies on the use of SharedArrayBuffer to enable important WebAssembly features.

There are many alternatives available to enable these headers. For example, if you deploy your UI to products like Vercel or Cloudflare Pages, you can set these headers in a custom configuration file. Otherwise, you can set these headers in the server framework of your choice (e.g., Express for JavaScript).


COOP must be set to same-origin.

COEP must be set to require-corp.

Setting COOP and COEP in your Vercel configuration:

To see more details on deploying to Vercel, see their documentation on vercel.json.

  "headers": [
      "source": "/(.*)",
      "headers": [
        { "key": "Cross-Origin-Opener-Policy", "value": "same-origin" },
        { "key": "Cross-Origin-Embedder-Policy", "value": "require-corp" }

Setting COOP and COEP in your Cloudflare Pages configuration:

To see more details on deploying to Cloudflare Pages, see their documentation on _headers.

  Cross-Origin-Opener-Policy: same-origin
  Cross-Origin-Embedder-Policy: require-corp