# @holochain/client

> A JavaScript client for the Holochain Conductor API

Latest version **0.21.1** (published 2026-10-15) · CAL-1.0 license · 0 weekly downloads

## Install

```sh
npm install @holochain/client
pnpm add @holochain/client
yarn add @holochain/client
bun add @holochain/client
```

## Health

**Score 75/100 (B)** — status: active.

Positive: has types; esm support; no vulnerabilities; has provenance; recently updated; high maintenance score; high quality score.

Warnings: low downloads; pre 1.0.

## Facts

| | |
|---|---|
| Version | 0.21.1 |
| Published | 2026-10-15 |
| First published | 2022-01-12 |
| Weekly downloads | 0 |
| License | CAL-1.0 |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Node | >=22.0.0 |
| Dependencies | 9 |
| Unpacked size | 219.7 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Provenance | attested (GitHub Actions) |
| GitHub stars | 266 |
| Author | Holochain Foundation |
| Maintainers | zippy314, zo-el, jost-s, matthme, thetasinner, veeso, callum.dunster, mattyg |
| Keywords | holochain, client, conductor api |

## Links

- npm: https://www.npmjs.com/package/@holochain/client
- Repository: https://github.com/holochain/holochain-client-js
- Homepage: https://github.com/holochain/holochain-client-js#readme
- Issues: https://github.com/holochain/holochain-client-js/issues
- npm.io page: https://npm.io/package/@holochain/client

## Dependencies (9)

- [ws](https://npm.io/package/ws.md) ^8.18.3
- [emittery](https://npm.io/package/emittery.md) ^1.2.0
- [js-base64](https://npm.io/package/js-base64.md) ^3.7.8
- [js-sha512](https://npm.io/package/js-sha512.md) ^0.9.0
- [lodash-es](https://npm.io/package/lodash-es.md) ^4.17.21
- [isomorphic-ws](https://npm.io/package/isomorphic-ws.md) ^5.0.0
- [@bitgo/blake2b](https://npm.io/package/@bitgo/blake2b.md) ^3.2.4
- [@msgpack/msgpack](https://npm.io/package/@msgpack/msgpack.md) ^3.1.2
- [libsodium-wrappers](https://npm.io/package/libsodium-wrappers.md) ^0.8

## Alternatives

- [launchdarkly-js-client-sdk](https://npm.io/package/launchdarkly-js-client-sdk.md) — 2.5M weekly downloads
- [@elastic/elasticsearch](https://npm.io/package/@elastic/elasticsearch.md) — 2.1M weekly downloads
- [@c8y/client](https://npm.io/package/@c8y/client.md) — 15.3K weekly downloads
- [@signaldb/maverickjs](https://npm.io/package/@signaldb/maverickjs.md) — 1.7K weekly downloads
- [@bbc/http-transport-cache](https://npm.io/package/@bbc/http-transport-cache.md) — 1.2K weekly downloads

## Recent versions

- 0.21.1 (latest) — 2026-10-15
- 0.21.1-rc.0 (next) — 2026-10-13
- 0.22.0 — 2026-10-07
- 0.21.0 — 2026-07-31
- 0.21.0-rc.1 — 2026-07-22
- 0.20.8 — 2026-07-21
- 0.21.0-rc.0 — 2026-07-17
- 0.20.7 — 2026-07-02
- 0.20.6 — 2026-06-30
- 0.20.5 — 2026-05-15
- 0.21.0-dev.3 — 2026-05-15
- 0.20.4 — 2026-05-13
- 0.20.4-rc.0 — 2026-01-23
- 0.20.3-rc.0 — 2026-01-22
- 0.21.0-dev.2 — 2026-01-16
- … 122 more at https://npm.io/package/@holochain/client/versions

## README

[![Project](https://img.shields.io/badge/Project-Holochain-blue.svg?style=flat-square)](http://holochain.org/)
[![Discord](https://img.shields.io/badge/Discord-DEV.HC-blue.svg?style=flat-square)](https://discord.gg/k55DS5dmPH)
[![License: CAL 1.0](https://img.shields.io/badge/License-CAL%201.0-blue.svg)](https://github.com/holochain/cryptographic-autonomy-license)
[![Integration Tests](https://github.com/holochain/holochain-client-js/actions/workflows/integration-test.yml/badge.svg?branch=main)](https://github.com/holochain/holochain-client-js/actions/workflows/integration-test.yml)
[![Bundling Tests](https://github.com/holochain/holochain-client-js/actions/workflows/bundling-test.yml/badge.svg?branch=main)](https://github.com/holochain/holochain-client-js/actions/workflows/bundling-test.yml)
[![Twitter Follow](https://img.shields.io/twitter/follow/holochain.svg?style=social&label=Follow)](https://x.com/holochain)

# Holochain Client - JavaScript

A JavaScript client for the Holochain Conductor API (works with browsers as well as Nodejs).

## API Reference

[Complete API reference](./docs/client.md)

## Installation

**JS client v0.21.x** is compatible with **Holochain v0.7.x**.

**JS client v0.20.x** is compatible with **Holochain v0.6.x**.

**JS client v0.19.x** is compatible with **Holochain v0.5.x**.

To install from NPM, run
```bash
npm install --save-exact @holochain/client
```

> This code is under beta development and you may wish to lock to an exact version of the library for that reason, as shown in the above command.

## Sample usage

### Use AppWebsocket with implicit zome call signing
```typescript
import {
  AdminWebsocket,
  AppWebsocket,
  CellType,
  type ActionHash,
  type CallZomeRequest,
} from "./lib/index.js";

const adminWs = await AdminWebsocket.connect({
  url: new URL("ws://127.0.0.1:65000"),
  wsClientOptions: { origin: "my-happ" },
});
const agent_key = await adminWs.generateAgentPubKey();
const role_name = "foo";
const installed_app_id = "test-app";
const appInfo = await adminWs.installApp({
  source: {
    type: "path",
    value: "./test/e2e/fixture/test.happ",
  },
  agent_key,
  installed_app_id,
});
await adminWs.enableApp({ installed_app_id });
if (appInfo.cell_info[role_name][0].type !== CellType.Provisioned) {
  throw new Error(`No cell found under role name ${role_name}`);
}
const { cell_id } = appInfo.cell_info[role_name][0].value;
await adminWs.authorizeSigningCredentials(cell_id);
await adminWs.attachAppInterface({ port: 65001, allowed_origins: "my-happ" });
const issuedToken = await adminWs.issueAppAuthenticationToken({
  installed_app_id,
});
const appWs = await AppWebsocket.connect({
  url: new URL("ws://127.0.0.1:65001"),
  token: issuedToken.token,
  wsClientOptions: { origin: "my-happ" },
});

const zomeCallPayload: CallZomeRequest = {
  cell_id,
  zome_name: "foo",
  fn_name: "foo",
  provenance: agent_key,
  payload: null,
};

const response: ActionHash = await appWs.callZome(zomeCallPayload, 30000);
console.log("zome call response is", response);

await appWs.client.close();
await adminWs.client.close();
```

### Subscribe to signals
```typescript
import { AdminWebsocket, AppWebsocket, CellType } from "./lib/index.js";

const adminWs = await AdminWebsocket.connect({
  url: new URL("ws://127.0.0.1:65000"),
  wsClientOptions: { origin: "my-happ" },
});
const agent_key = await adminWs.generateAgentPubKey();
const role_name = "foo";
const installed_app_id = "test-app";
const appInfo = await adminWs.installApp({
  source: {
    type: "path",
    value: "./test/e2e/fixture/test.happ",
  },
  agent_key,
  installed_app_id,
});
await adminWs.enableApp({ installed_app_id });
if (appInfo.cell_info[role_name][0].type !== CellType.Provisioned) {
  throw new Error(`No cell found under role name ${role_name}`);
}
const { cell_id } = appInfo.cell_info[role_name][0].value;
await adminWs.authorizeSigningCredentials(cell_id);
await adminWs.attachAppInterface({ port: 65001, allowed_origins: "my-happ" });
const issuedToken = await adminWs.issueAppAuthenticationToken({
  installed_app_id,
});
const appWs = await AppWebsocket.connect({
  url: new URL("ws://127.0.0.1:65001"),
  token: issuedToken.token,
  wsClientOptions: { origin: "my-happ" },
});

let signalCb;
const signalReceived = new Promise<void>((resolve) => {
  signalCb = (signal) => {
    console.log("signal received", signal);
    // act on signal
    resolve();
  };
});

appWs.on("signal", signalCb);

// trigger an emit_signal
await appWs.callZome({
  cell_id,
  zome_name: "foo",
  fn_name: "emitter",
  provenance: agent_key,
  payload: null,
});
await signalReceived;

await appWs.client.close();
await adminWs.client.close();
```

### Managing zome call signing credentials in a pure JavaScript browser application

Here is a pattern to manage signing keys for signing zome calls when running pure JavaScript web hApps in a web browser:
```typescript
const cellIdB64 =
    encodeHashToBase64(cell_id[0]) + encodeHashToBase64(cell_id[1]);
// in case the zome call signing credentials are stored locally in the browser
const signingCredentialsJson = localStorage.getItem(cellIdB64);
let signingCredentials: SigningCredentials | null =
  signingCredentialsJson && JSON.parse(signingCredentialsJson);

if (!signingCredentials) {
  const [keyPair, signingKey] = generateSigningKeyPair();
  const capSecret = await admin.grantSigningKey(
    cell_id,
    { [GrantedFunctionsType.All]: null },
    signingKey
  );
  signingCredentials = {
    capSecret,
    keyPair,
    signingKey,
  };
}
setSigningCredentials(cell_id, signingCredentials);
// possibly store the zome call signing credentials locally in the browser
localStorage.setItem(cellIdB64, JSON.stringify(signingCredentials));
```

### Connecting from a Tauri app with an in-process conductor

When the UI runs inside a Tauri webview served by [`tauri-plugin-holochain`](https://github.com/holochain/android-service-runtime) — which runs the conductor in the same process — `AppWebsocket.connect` automatically routes the App API through Tauri IPC instead of opening a websocket. No code change is required:

```typescript
// Inside a tauri-plugin-holochain webview, this returns an AppWebsocket backed
// by a TauriAppTransport rather than a WsClient. callZome, appInfo, signals,
// clone cells, etc. all work unchanged.
const appWs = await AppWebsocket.connect();
```

The plugin injects a `__HC_TAURI_HOLOCHAIN__` marker on `window`; `isTauriHolochain()` detects it and `connect()` constructs a `TauriAppTransport` that moves the same msgpack `{ type, value }` payloads a websocket would carry over the `plugin:holochain|app_request` command.

**Trust model.** The websocket path is scoped by a per-app auth token. The Tauri path replaces that with two guarantees enforced on the Rust side: the conductor derives the app id from the **calling window's label** (never from a JS-supplied argument), and Tauri's capability/permission system gates the `app_request` command to the intended windows. Zome calls are still signed by the in-process keystore via the host signer, so no signing key is exposed to the webview. The websocket transport is unchanged and remains the path for the separated client + service deployment and any non-Tauri consumer.

## Running tests

You need a version (`stable` toolchain) of Rust available.

You need `holochain` and `hc` on your path, best to get them from nix with `nix-shell`.

To perform the pre-requisite DNA compilation steps, and run the Nodejs test, run:

```bash
nix develop
./build-fixture.sh
npm run test
```

## Releasing

1. Open the
   [Prepare Release workflow](https://github.com/holochain/holochain-client-js/actions/workflows/release-prepare.yml)
   on GitHub Actions, select the `main` branch, and run it. You may provide an
   exact version or leave the version empty to infer it from the commits since
   the latest release.
2. Review the generated release pull request, including the package version and
   changelog, then merge it into `main`.
3. The merge publishes `@holochain/client` to npm with provenance and creates
   the matching Git tag and GitHub release. Prerelease versions are published
   with the npm `next` tag.

## Contribute

Holochain is an open source project.  We welcome all sorts of participation and are actively working on increasing surface area to accept it.  Please see our [contribution guidelines](/CONTRIBUTING.md) for our general practices and protocols on participating in the community, as well as specific expectations around things like code formatting, testing practices, continuous integration, etc.

* Connect with us on [Discord](https://discord.gg/k55DS5dmPH)

## License

 [![License: CAL 1.0](https://img.shields.io/badge/License-CAL%201.0-blue.svg)](https://github.com/holochain/cryptographic-autonomy-license)

Copyright (C) 2020-2024, Holochain Foundation

This program is free software: you can redistribute it and/or modify it under the terms of the license
provided in the LICENSE file (CAL-1.0).  This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.

---
_Source: https://npm.io/package/@holochain/client · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
