Quickstart — Node.js (Testnet)

Encrypt and decrypt data with TACo in a Node.js environment — no browser or wallet extension required.

This guide walks through a complete encrypt → decrypt flow in Node.js. Unlike the browser quickstart, there's no MetaMask or window.ethereum — we use private keys and JsonRpcProvider directly.

circle-info

A full working example lives in the taco-web repo: examples/taco/nodejsarrow-up-right

1

Install dependencies

npm install @nucypher/taco @nucypher/taco-auth [email protected]
circle-exclamation
2

Configure provider, domain, and ritual ID

You'll need three things:

Parameter
Value
Notes

RPC URL

A Polygon Amoy RPC endpoint

This reads DKG coordination contracts — it's not your application's chain. Any public Amoy RPC works.

Ritual ID

6 (for TAPIR testnet)

See the testnets page for other environments.

Private keys

Two test wallets

One for the encryptor, one for the consumer. Any Ethereum wallets — no testnet funds required.

import { ethers } from 'ethers';
import { domains } from '@nucypher/taco';

// This provider reads DKG coordination contracts on Polygon Amoy.
// It is NOT your application's RPC — it's infrastructure.
const provider = new ethers.providers.JsonRpcProvider(
  'https://polygon-amoy.drpc.org'
);

const domain = domains.TESTNET;  // "tapir"
const ritualId = 6;
3

Encrypt data

import { conditions, encrypt, initialize } from '@nucypher/taco';
import { ethers } from 'ethers';

await initialize();

// Any condition works — here's a simple balance check
const hasBalance = new conditions.base.rpc.RpcCondition({
  chain: 80002,  // Polygon Amoy — the chain where this condition is evaluated (can be any supported chain)
  method: 'eth_getBalance',
  parameters: [':userAddress', 'latest'],
  returnValueTest: {
    comparator: '>=',
    value: 0,
  },
});

const encryptorSigner = new ethers.Wallet('<ENCRYPTOR_PRIVATE_KEY>');

const messageKit = await encrypt(
  provider,
  domain,
  'my secret message',
  hasBalance,
  ritualId,
  encryptorSigner,
);

// Serialize for storage or transmission
const encryptedBytes = messageKit.toBytes();
circle-exclamation
4

Decrypt data

import {
  ThresholdMessageKit,
  conditions,
  decrypt,
  initialize,
} from '@nucypher/taco';
import {
  EIP4361AuthProvider,
  USER_ADDRESS_PARAM_DEFAULT,
} from '@nucypher/taco-auth';
import { ethers } from 'ethers';

await initialize();

// Deserialize
const messageKit = ThresholdMessageKit.fromBytes(encryptedBytes);

const consumerSigner = new ethers.Wallet('<CONSUMER_PRIVATE_KEY>');

// Build condition context
const conditionContext =
  conditions.context.ConditionContext.fromMessageKit(messageKit);

// In Node.js, EIP4361AuthProvider needs explicit SIWE parameters
// (in the browser, these come from the page origin)
const authProvider = new EIP4361AuthProvider(
  provider,
  consumerSigner,
  { domain: 'localhost', uri: 'http://localhost:3000' },
);
conditionContext.addAuthProvider(USER_ADDRESS_PARAM_DEFAULT, authProvider);

const decryptedBytes = await decrypt(
  provider,
  domain,
  messageKit,
  conditionContext,
);

const decryptedMessage = new TextDecoder().decode(decryptedBytes);
console.log(decryptedMessage); // "my secret message"

Key differences from browser usage

Browser:

const provider = new ethers.providers.Web3Provider(window.ethereum);

Node.js:

const provider = new ethers.providers.JsonRpcProvider('https://polygon-amoy.drpc.org');

Next steps

Last updated