Skip to content

SwarmIdClient API Reference

The SwarmIdClient is the main class for integrating Swarm ID authentication and storage capabilities into web applications. It enables parent windows to interact with a Swarm ID iframe proxy, providing secure authentication, identity management, and data upload/download functionality to the Swarm decentralized storage network.

Terminal window
pnpm add @snaha/swarm-id
import { SwarmIdClient } from '@snaha/swarm-id'
const client = new SwarmIdClient({
iframeOrigin: 'https://swarm-id.example.com',
metadata: {
name: 'My App',
description: 'A decentralized application',
},
onConnectionChange: (info) => {
console.log('Connection changed:', info.identity?.name, 'canUpload=', info.canUpload)
},
})
await client.initialize()
// Option 1: Open authentication page manually
await client.connect()
// Option 2: Read current connection state and upload if authenticated.
// Check `canUpload` too — an authenticated user can still lack upload
// capability (no postage stamp, no subsidised gateway).
if (client.connectionInfo?.identity && client.connectionInfo.canUpload) {
const result = await client.uploadData(new Uint8Array([1, 2, 3]))
console.log('Uploaded with reference:', result.reference)
}

Creates a new SwarmIdClient instance.

Parameters:

Parameter Type Required Description
options.iframeOrigin string Yes The origin URL where the Swarm ID proxy iframe is hosted
options.iframePath string No The path to the proxy iframe (defaults to "/proxy")
options.timeout number No Request timeout in milliseconds (defaults to 30000). Bounds each call’s whole round trip through the iframe; a call’s own requestOptions.timeout replaces it for that call
options.initializationTimeout number No Initialization timeout in milliseconds (defaults to 30000)
options.onConnectionChange (info: ConnectionInfo) => void No Callback invoked when the app-visible connection state changes (identity, app key, account, auth, permissions), and whenever the app’s drives change. The current snapshot is also available synchronously via client.connectionInfo.
options.onDrivesChange () => void No Callback invoked only when the app’s drives change: one joins or leaves the grant, the primary moves, a lane moves, a drive expires. Fires once when the client initialises, connected or not, then after the onConnectionChange of the same event. Re-read getDrives() there.
options.popupMode "popup" | "window" No How to display the authentication popup (defaults to "window")
options.metadata AppMetadata Yes Application metadata shown to users during authentication
options.metadata.name string Yes Application name (1-100 characters)
options.metadata.description string No Application description (max 500 characters)
options.metadata.icon string No Application icon as a data URL (SVG or PNG, max 4KB)
options.buttonConfig ButtonConfig No Button configuration for the authentication UI
options.containerId string No ID of container element to place iframe in (optional)
options.subsidisedGatewayUrl string No URL of a subsidised gateway for uploads without user’s postage stamp. See Subsidised Gateway for details.
options.permissions Permissions No What the app asks the user for on the connect screen. permissions.drives is 'all', or a row per drive ({ kind, description?, optional? }), regular ones first (up to 8 rows, description max 120 characters); [] opts out of drives. permissions.dataSharing / permissions.writeAccess (each true) ask for the sharing switches too; see getPermissions(). See getDrives()

Throws:

  • invalid-request if the provided app metadata or permissions are invalid
  • a plain Error if constructed where there is no window (a server render)

Example:

const client = new SwarmIdClient({
iframeOrigin: 'https://id.swarm.example.com',
timeout: 60000,
metadata: {
name: 'My app',
description: 'A decentralized application built on Swarm',
icon: 'data:image/svg+xml;base64,...',
},
onConnectionChange: (info) => {
updateUI(info)
},
})

Initializes the client by creating and embedding the proxy iframe.

This method must be called before using any other client methods. It creates a hidden iframe, waits for the proxy to initialize, identifies the parent application to the proxy, and waits for the proxy to signal readiness.

Returns: Promise<void> - Resolves when the client is fully initialized

Throws:

  • invalid-state if the client is already initialized, or destroy() runs before it resolves
  • invalid-request if containerId names no element
  • init-failed if the iframe fails to load, origin validation fails on the proxy side, or the proxy does not respond within the initialization timeout period (configurable via initializationTimeout, defaults to 30 seconds)

Example:

const client = new SwarmIdClient({ ... })
try {
await client.initialize()
console.log('Client ready')
} catch (error) {
console.error('Failed to initialize:', error)
}

Destroys the client and releases all resources.

This method should be called when the client is no longer needed. It performs the following cleanup:

  • Rejects every pending request, and a pending initialize(), with a SwarmIdError of code invalid-state
  • Removes the message event listener
  • Removes the iframe from the DOM
  • Resets the client to an uninitialized state

After calling destroy(), the client instance cannot be reused. Create a new instance if you need to reconnect.

Returns: void

Example:

// Clean up when component unmounts
useEffect(() => {
const client = new SwarmIdClient({ ... })
client.initialize()
return () => {
client.destroy()
}
}, [])

Returns the authentication iframe element.

The iframe displays authentication UI based on the current auth status:

  • If not authenticated: shows a “Connect” button
  • If authenticated: shows identity info and a “Disconnect” button

The iframe is positioned fixed in the bottom-right corner of the viewport.

Returns: HTMLIFrameElement - The iframe element displaying the authentication UI

Throws:

  • invalid-state if the client is not initialized, or the iframe is not available

Example:

const iframe = client.getAuthIframe()
// The iframe is already displayed; this returns a reference to it

The authentication button in the iframe can be customized using the buttonConfig option in the constructor. This configuration allows you to customize the button text, colors, and styling.

ButtonConfig Interface:

interface ButtonConfig {
connectText?: string
disconnectText?: string
loadingText?: string
backgroundColor?: string
color?: string
borderRadius?: string
fontFamily?: string
fontSize?: string
fontWeight?: string | number
}

Example: Customizing Button Configuration

const client = new SwarmIdClient({
iframeOrigin: 'https://swarm-id.example.com',
metadata: {
name: 'My App',
description: 'A decentralized application',
},
buttonConfig: {
connectText: 'Connect with Swarm',
disconnectText: 'Disconnect',
loadingText: 'Loading...',
backgroundColor: '#4CAF50',
color: 'white',
borderRadius: '8px',
fontFamily: 'Inter, system-ui, sans-serif',
fontSize: '15px',
fontWeight: '500',
},
onConnectionChange: (info) => {
console.log('Connection changed:', info.identity?.name, 'canUpload=', info.canUpload)
},
})
await client.initialize()

ButtonConfig Properties:

Property Type Required Description Default Value
connectText string No Text for the connect button “🔐 Login with Swarm ID”
disconnectText string No Text for the disconnect button “🔓 Disconnect from Swarm ID”
loadingText string No Text shown during loading “⏳ Loading…”
backgroundColor string No Background color for buttons #dd7200 (connect), #666 (disconnect)
color string No Text color for buttons white
borderRadius string No Border radius for buttons and iframe 0
fontFamily string No CSS font-family for the button the iframe’s own font
fontSize string No CSS font-size for the button 14px
fontWeight string | number No CSS font-weight for the button 600

Notes:

  • Button configuration is passed directly to the constructor, not via postMessage
  • The borderRadius property affects both the buttons and the iframe container
  • Colors should be valid CSS color strings (e.g., '#FF0000', 'rgb(255, 0, 0)', 'red')
  • The typography properties are the only way to make the button match the page’s type: the button is painted inside the cross-origin iframe, where the page’s own CSS cannot reach it
  • fontFamily takes a CSS font stack and falls back the way a stack always does — the browser reads it left to right and takes the first family that resolves. It resolves against the IFRAME, so name web-safe or system families (a font the page loads itself is not available inside the iframe)
  • fontSize has a box to fit into. In the default floating placement the client fixes the iframe at 300×50 px and the proxy page hides the overflow, so a button too tall for 50 px is silently clipped. Pass containerId when you want a larger size — the app then owns the box
  • Text properties support plain text or emoji combinations
  • The configuration applies to both authentication states (connect/disconnect)

In addition to the iframe-based authentication (via getAuthIframe()), you can manually trigger the authentication flow by calling connect(). This opens the same authentication URL in a new window:

// Open authentication page (default: new window)
await client.connect()
// Open as popup window
await client.connect({ popupMode: 'popup' })

When to use connect():

  • When you want to trigger authentication from a custom UI element
  • When you prefer the authentication to open in a new window instead of an iframe

Authentication Flow:

  1. User calls client.connect() or clicks the iframe button
  2. Authentication page opens with the app metadata
  3. User authenticates with their Swarm ID
  4. Authentication state is shared with the iframe proxy
  5. onConnectionChange callback fires with the new connection snapshot

Checks the current authentication status with the Swarm ID proxy.

Returns: Promise<AuthStatus> - The authentication status object

Property Type Description
authenticated boolean Whether the user is currently authenticated
origin string | undefined The origin that authenticated (if authenticated)
beeApiUrl string | undefined The Bee API URL configured in the identity provider

Throws:

  • Error if the client is not initialized
  • Error if the request times out

Example:

const status = await client.checkAuthStatus()
if (status.authenticated) {
console.log('Authenticated from:', status.origin)
}

Opens Swarm ID authentication page in a new window.

This method creates the same authentication URL as used by the iframe proxy and opens it in a new browser window. The user can authenticate with their Swarm ID, and the resulting authentication will be available to the client when they return.

Parameters:

Parameter Type Required Description
options ConnectOptions No Configuration options for the authentication window
options.popupMode "window" | "popup" No Whether to open as a popup window (“popup”) or full window (“window”, default)

ConnectOptions Interface:

interface ConnectOptions {
popupMode?: 'popup' | 'window' // Default: "window"
}

Returns: Promise<void> - Resolves when the authentication popup has been opened

Throws:

  • invalid-state if the client is not initialized
  • popup-blocked if the browser blocks the popup

Example:

const client = new SwarmIdClient({ ... })
await client.initialize()
// Open authentication page (default: new window)
await client.connect()
// Open as popup window
await client.connect({ popupMode: 'popup' })

Disconnects the current session and clears authentication data.

After disconnection, the user will need to re-authenticate to perform uploads or access identity-related features. The onConnectionChange callback will fire with an un-authenticated snapshot (no identity, canUpload: false, uploadMode: "unavailable"). Note that canUpload is reported as false even when a subsidised gateway is configured, because uploads still require an authenticated app secret.

Returns: Promise<void> - Resolves when disconnection is complete

Throws:

  • invalid-state if the client is not initialized
  • internal if the proxy reports the disconnect failed
  • timeout if the request times out

Example:

await client.disconnect()
console.log('User logged out')

Derive 32 bytes of app material from this app’s secret and a label of the app’s choosing. The same account, app and label give the same bytes on every device, and nobody without the account can guess them. Use it to seed a feed topic or other app material without exposing the app’s public key.

Parameters:

Parameter Type Description
label string Domain separator chosen by the app, e.g. "state-feed"

Returns: Promise<Uint8Array> — the derived 32 bytes

Throws: Error if the client is not initialized or not authenticated

const seed = await client.deriveAppSecret('state-feed')
const topic = keccak256(seed) // a stable feed topic nobody else can compute

Synchronous accessor for the current connection state. Populated by the proxy as soon as it is ready and refreshed automatically whenever any of the derived fields change (identity rename, default-stamp change, account migration, postage stamp purchased, auth transitions). Subscribe to onConnectionChange to react to updates.

Type: ConnectionInfo

Throws: invalid-state if initialize() has not resolved yet.

Property Type Description
canUpload boolean Whether the user can upload data
uploadMode "user-stamp" | "subsidised" | "unavailable" How uploads will be handled. See Upload Availability
uploadUnavailableReason "no-stamp" | "stamper-failed" | "stamp-expired" | "stamp-not-usable" | "stamp-warming-up" | undefined Why uploadMode is "unavailable"; absent whenever uploads work. See Why Uploads Are Unavailable
storagePartitioned boolean | undefined true when the browser gave the proxy iframe its own partitioned store (Safari ITP, strict privacy settings). Reported for UI messaging; it does not decide whether you can upload
identity object | undefined The connected identity details (if authenticated)
identity.id string Unique identifier for the identity
identity.name string Display name of the identity
identity.address string Ethereum address associated with the identity
identity.publicKey string | undefined Public key of the identity
identity.sharingPublicKey string | undefined The account-wide ACT key: grant to it to share with this person in every app they use. Absent while this app’s data sharing is off (see permissions). See Which key do I grant to?
identity.postageSignerAddress string | undefined The address the account’s postage signer stamps with, bare hex like address. An app that funds storage for the account buys a batch with it as createBatch’s owner; the account then adopts the batch in the identity site (Storage, Add drive, Use existing batch) with its own key. Knowing the address lets an app buy for the account, never spend for it
identity.avatar Avatar Ready-to-render account avatar. See Avatars
appKey object | undefined The app-specific key details
appKey.address string Ethereum address of the app key
appKey.publicKey string Public key of the app key
permissions { dataSharing: boolean, writeAccess: boolean } | undefined What this app may do with the sharing key, as getPermissions() reports it; refreshed when the user flips a switch in Swarm ID. Absent without a session

Example:

const info = client.connectionInfo
if (info.canUpload) {
if (info.uploadMode === 'subsidised') {
console.log('Uploads will use the subsidised gateway')
} else {
console.log('Uploads will use your postage stamp')
}
} else if (info.uploadUnavailableReason === 'no-stamp') {
console.log('No drive yet — buy one to upload')
} else if (info.uploadUnavailableReason === 'stamper-failed') {
console.log('A drive is attached, but the write path did not build')
} else {
console.log('Not connected yet')
}

Gets the app’s primary drive: the one a write goes to when it names none. The app’s other drives, if it was granted any, are listed by getDrives().

Returns information about the postage stamp behind it, including batch ID, utilization, depth, and TTL.

Returns: Promise<PostageBatch | undefined> - The postage batch info, or undefined if none is configured

Property Type Description
batchID string The batch ID (64 hex characters)
utilization number How full the fullest bucket is, from 0 to 1, of what one partition may write into it; not Bee’s fill count. Kept from the last write, in the partition it went to, so it can trail another device’s writes. A batch stops accepting uploads when one bucket fills, before the nominal 2^depth × 4096 bytes
usable boolean Whether the batch is usable
label string Human-readable label
depth number Batch depth
amount string Batch amount
bucketDepth number Bucket depth
blockNumber number Block number when created
immutableFlag boolean Whether the batch is immutable
exists boolean Whether the batch exists
batchTTL number | undefined Remaining lifetime in seconds, as of batchTTLMeasuredAt
batchTTLSource 'chain' | 'bee' | 'estimate' | undefined Where batchTTL came from: the PostageStamp contract or the Bee node, both exact, or an estimate from the purchase amount and the current price, which knows nothing of top-ups, dilutes or price moves since. Show an estimate as one
batchTTLMeasuredAt number | undefined When batchTTL was measured, in ms since the epoch; present with it. Age the figure from here, or show “checked …”

Throws:

  • Error if the client is not initialized
  • Error if the request times out

Example:

const batch = await client.getPostageBatch()
if (batch) {
console.log('Batch ID:', batch.batchID)
console.log('Utilization:', batch.utilization)
console.log('Depth:', batch.depth)
console.log('TTL:', batch.batchTTL)
} else {
console.log('No postage batch configured')
}

Lists every drive the app was granted in Swarm ID. Each entry carries the fields of getPostageBatch() plus:

Property Type Description
kind 'regular' | 'scratch' A scratch drive overwrites its oldest data once full; its contents carry no warranty
primary boolean The drive a write goes to when it names none: the account default for an 'all' grant, otherwise the first granted regular drive. A scratch drive is never primary
partition number | undefined The write partition this session holds on the drive, as connectionInfo.partition reports it for the primary: undefined while it holds none: until the drive’s write path is built (at connect for the primary, on the first write that names it for any other), and after an idle release or a disconnect. Every lease change fires onConnectionChange, so re-read the drives there

Returns: Promise<Drive[]> — empty when the app was granted no drive

Every write takes an optional batchID (in its upload options, or as its own options where there are none) naming one of these drives. A feed update’s payload and its SOC always go to the same drive. Naming a drive outside the grant rejects with drive-not-granted.

Asking for the sharing switches. options.permissions.dataSharing: true / writeAccess: true put the switch on the connect screen when it is not already on for this app — off, for the user to turn on — and a switch turned on is pinned for the app. A switch left off is simply not granted; the app sees what it got from getPermissions() and can ask again later with requestPermissions().

Asking for drives. Without options.permissions.drives the app gets the account’s default drive. With it, the connect screen asks the user for what the app needs: one row per entry, each a select over the user’s drives of that kind with a way to create one there, or a single “full drive access” checkbox for 'all', which also covers drives the user adds later. A row’s description replaces the helper text under it (“Used to store permanent data” / “Used to store streaming data”); an optional row may be left empty, and the app sees what it got from getDrives(). Rows are granted in order, regular drives first, and the first regular one is the primary.

const client = new SwarmIdClient({
// …
permissions: {
drives: [
{ kind: 'regular', description: 'Used to store your messages' },
{ kind: 'scratch', optional: true },
],
},
})

Example:

const scratch = (await client.getDrives()).find((drive) => drive.kind === 'scratch')
await client.uploadData(frame, { batchID: scratch?.batchID })

How much a drive holds and has left for this device: the primary, or the one options.batchID names.

A drive is not filled byte by byte. Every chunk lands in one of 65,536 buckets, picked by its address, and a save fails as soon as one of its chunks lands in a bucket that is already full. So how much still fits is a likelihood, reported at DEFAULT_FIT_CONFIDENCE (0.999): leftBytes is a save that fits 999 times in 1000, and sizeBytes is the same figure for an empty drive, which is the size a drive of its depth is sold as. The figures count the bytes you save: the chunks Swarm adds to address them, and a save’s own manifest and feed update, are already taken off. They assume encrypted saves; plain ones fit under 1% more.

A drive is split into partitions, so two devices can write to it at once, and one save goes into the one partition this device writes to: the one it holds, or else the one it would claim first. The figures are that partition’s; partitions breaks the whole drive down.

Property Type Description
partition number The partition the figures describe
sizeBytes number What the partition holds when empty
usedBytes number What has been written to it, as raw slots: a save’s added chunks count here too, so leftBytes reaches 0 a little (under 2%) before usedBytes reaches sizeBytes
leftBytes number The largest save that still fits, never more than sizeBytes − usedBytes
partitions PartitionCapacity[] The same four figures for every partition whose counter could be read, this one included; another device’s partition comes from what it last published to Swarm

Returns: Promise<DriveCapacity | undefined>, undefined for a scratch drive, which overwrites its oldest data instead of filling. Rejects with not-authenticated without a session, upload-unavailable when the app has no drive, drive-not-granted for a drive outside the grant, and network or timeout when this device’s partition could not be read.

It reads Swarm for the partitions this session does not hold, so call it when you show storage, not on every connection change.

Full, a little still free. usedBytes can pass sizeBytes: sizeBytes is a cautious figure, and a drive usually takes more. leftBytes then reads 0, while a small save may still fit; ask fitProbability().

Example:

const capacity = await client.getDriveCapacity()
if (capacity) {
const { usedBytes, leftBytes, sizeBytes } = capacity
if (usedBytes >= sizeBytes) showFullButSomeFree()
else if (leftBytes < sizeBytes / 10) showLow(leftBytes)
else show(`About ${format(leftBytes)} left of ${format(sizeBytes)}`)
}

The chance, from 0 to 1, that a save of bytes fits in a drive. It asks about the partition this device writes to, the same one getDriveCapacity() reports. Always 1 on a scratch drive, which overwrites its oldest data instead.

Parameters:

Parameter Type Required Description
bytes number Yes The size of the save; a fraction is rounded up, a negative or non-finite size rejects with invalid-request
options.batchID string No The drive, from getDrives(); defaults to the primary
options.encrypt boolean No Whether the save is encrypted, as uploads are by default

Returns: Promise<number>. Rejects as getDriveCapacity() does.

Example:

import { DEFAULT_FIT_CONFIDENCE } from '@snaha/swarm-id'
if ((await client.fitProbability(file.size)) < DEFAULT_FIT_CONFIDENCE) {
showDriveFull()
}

Asks the user for more drives while the app is connected — a viewer who starts streaming and now needs a scratch drive, say. It opens the Permissions for <app> popup, which shows only what the app asks for; the user picks a drive for each row, can create one there, or grants nothing. The rows take the same shape as options.permissions.drives at connect, and what the user picks is added to what the app already holds.

Returns: Promise<Drive[]> — the drives the app holds once the popup is closed, as getDrives() reports them. When the user granted nothing, or closed the popup, that is what the app held before.

The popup grants only to an app with a live connection. An app that was tracking the account default (connected with no drive request) holds an explicit list afterwards, with that default as its first drive: it keeps its primary, and no longer follows a later change of the account default.

Throws:

  • not-authenticated if the app is not connected
  • popup-blocked if the browser blocked the popup — call it from a click, as connect()
button.onclick = async () => {
const drives = await client.requestDrives([{ kind: 'scratch' }])
const scratch = drives.find((drive) => drive.kind === 'scratch')
if (!scratch) return showStreamingUnavailable()
startStreaming(scratch.batchID)
}

The user can also change what an app holds from Swarm ID itself: the app’s page under Apps lists every drive the app was granted, and setting one to None takes it away. A write in flight on a drive taken away is aborted.

What this app may do with the account-wide sharing key (see Which key do I grant to?):

  • dataSharing — read what was shared with the sharing key, and see it as identity.sharingPublicKey
  • writeAccess — publish and manage shares as the identity (publisher: "identity", and adding or revoking grantees of such a share); never on without dataSharing

Both are on unless the user switched them off in Swarm ID — for every app (Apps), or for this one (its page under Apps). A call that needs one that is off rejects with permission-denied, with permission naming the switch; check here first to ask before that happens. The same two booleans ride connectionInfo.permissions, so onConnectionChange sees a switch flipped while the app runs.

Returns: Promise<{ dataSharing: boolean, writeAccess: boolean }>

const { dataSharing } = await client.getPermissions()
if (!dataSharing) showSharedInboxLocked()

The general form of requestDrives(): asks the user for drives and the sharing switches in one popup. permissions is { drives?, dataSharing?: true, writeAccess?: true }. The Permissions for <app> page shows only what is asked — the drive rows empty, each switch at its current value — and the user turns on what they allow, or nothing. Asking for writeAccess shows dataSharing too, which it implies.

Returns: Promise<{ dataSharing: boolean, writeAccess: boolean }> — what the app holds once the popup is closed, as getPermissions() reports it. When every switch asked for is already on and no drives were asked for, no popup opens and the call resolves at once.

Throws:

  • not-authenticated if the app is not connected
  • popup-blocked if the browser blocked the popup — call it from a click, as connect()
button.onclick = async () => {
const { writeAccess } = await client.requestPermissions({ writeAccess: true })
if (!writeAccess) return showSharingUnavailable()
await client.actUploadData(data, grantees, { publisher: 'identity' })
}

Checks whether the Bee node is reachable.

This method never throws an exception. If the client is not initialized, the request times out, or any other error occurs, it returns false.

Returns: Promise<boolean> - true if the Bee node is reachable, false otherwise

Example:

const connected = await client.isBeeConnected()
if (connected) {
console.log('Bee node is online')
} else {
console.log('Bee node is offline')
}

Gets information about the Bee node configuration. Needs a real Bee node: the public gateway has no /node endpoint and this call fails there. Do not gate uploads on it; its purpose is to detect a dev-mode node, where deferred uploads are required. Nothing else tells you: a direct upload against a dev-mode node does not fail with a mode error, it waits out the request timeout and rejects with Request timeout after 30000ms.

This method retrieves the current Bee node’s operating mode and feature flags. Use this to determine if deferred uploads are required (dev mode) or if direct uploads are available (production modes).

Returns: Promise<{ beeMode, chequebookEnabled, swapEnabled }> — an inline object; there is no exported NodeInfo type

Property Type Description
beeMode string The Bee node operating mode (“dev”, “light”, “full”, “ultra-light”)
chequebookEnabled boolean Whether the chequebook is enabled
swapEnabled boolean Whether SWAP is enabled

Throws:

  • Error if the client is not initialized
  • Error if the Bee node is not reachable
  • Error if the request times out

Example:

const nodeInfo = await client.getNodeInfo()
if (nodeInfo.beeMode === 'dev') {
// Dev mode requires deferred uploads
await client.uploadData(data, { deferred: true })
} else {
// Production modes can use direct uploads
await client.uploadData(data, { deferred: false })
}

uploadData(data, options?, requestOptions?)

Section titled “uploadData(data, options?, requestOptions?)”

Uploads raw binary data to the Swarm network. The reference it returns is read back with downloadData, or from a gateway at /bytes/<reference>; it carries no manifest, so downloadFile and /bzz/ cannot resolve it.

The data is uploaded using the authenticated user’s postage stamp. Progress can be tracked via the options.onProgress callback.

Parameters:

Parameter Type Required Description
data Uint8Array Yes The binary data to upload
options UploadOptions No Upload configuration
options.batchID string No The drive to write to, from getDrives(). Defaults to the primary drive. Every writer takes it
options.pin boolean No Whether to pin the data locally (defaults to false; ignored on a subsidised gateway)
options.encrypt boolean No Whether to encrypt the data (defaults to false). The 128-hex reference then contains the decryption key: a capability, not an address — see Quick Start
options.tag number No Tag ID for tracking upload progress (ignored on a subsidised gateway)
options.deferred boolean No Whether to use deferred upload (defaults to false). A Bee node in dev mode serves only deferred uploads, and a direct upload against one fails as a request timeout, not as a mode error — see getNodeInfo. Not needed on the public gateway
options.onProgress (progress) => void No Callback for tracking upload progress
requestOptions RequestOptions No Request configuration
requestOptions.timeout number No Request timeout in milliseconds for this call. Replaces the client’s default (30 s) for the whole upload — the round trip through the iframe as well as the Bee request; a file of a few MB over a testnet or the public gateway needs more, here or in new SwarmIdClient({ timeout })
requestOptions.headers Record<string, string> No Custom headers
requestOptions.endlesslyRetry boolean No Whether to retry endlessly

Returns: Promise<UploadResult>

Property Type Description
reference string The Swarm reference (hash) of the uploaded data
tagUid number | undefined The tag UID if a tag was created
stampedChunks number | undefined Chunks this write sent: one per stamp in user-stamp mode, one per chunk the gateway accepted in subsidised mode. Compare it with an estimate to show what a save cost. The partition lease’s own chunks (lock, intent, and the state publish after each write) are not counted: they re-use reserved slots and spend no capacity. Absent from an identity site older than the field

Throws:

  • Error if the client is not initialized
  • Error if the user is not authenticated or cannot upload
  • Error if the request times out

Example:

const data = new TextEncoder().encode('Hello, Swarm!')
const result = await client.uploadData(data, {
encrypt: true,
onProgress: (progress) => {
console.log(`Progress: ${progress.processed}/${progress.total}`)
},
})
console.log('Reference:', result.reference)

downloadData(reference, options?, requestOptions?)

Section titled “downloadData(reference, options?, requestOptions?)”

Downloads raw binary data from the Swarm network: the counterpart of uploadData. Pass an encrypted (128-hex) reference here rather than putting it in a gateway URL, since the reference contains the decryption key.

Parameters:

Parameter Type Required Description
reference string Yes The Swarm reference (64 or 128 hex chars)
options DownloadOptions No Download configuration
options.redundancyStrategy 0-3 No Strategy for handling redundancy
options.fallback boolean No Whether to use fallback retrieval
options.timeoutMs number No Download timeout in milliseconds, carried in the download options. Not the call’s bound — that is requestOptions.timeout below
options.actPublisher Uint8Array | string No ACT publisher for encrypted content
options.actHistoryAddress Uint8Array | string No ACT history address for encrypted content
options.actTimestamp number | string No ACT timestamp for encrypted content
requestOptions RequestOptions No Request configuration
requestOptions.timeout number No Request timeout in milliseconds for this call. Replaces the client’s default (30 s) for the whole round trip, not only the Bee request
requestOptions.headers Record<string, string> No Custom headers
requestOptions.endlesslyRetry boolean No Whether to retry endlessly

Returns: Promise<Uint8Array> - The downloaded data

Throws:

  • Error if the client is not initialized
  • Error if the reference is not found
  • Error if the request times out

Example:

const data = await client.downloadData('a1b2c3...') // 64 char hex reference
const text = new TextDecoder().decode(data)
console.log('Downloaded:', text)

uploadFile(file, name?, options?, requestOptions?)

Section titled “uploadFile(file, name?, options?, requestOptions?)”

Uploads a file to the Swarm network, wrapped in a manifest that carries its name and content type. The reference is read back with downloadFile. A gateway’s /bzz/<reference>/ is only for a plain reference, uploaded with encrypt: false: the default one carries the key, which never goes in a gateway URL.

Accepts either a File object (from file input) or raw Uint8Array data. When using a File object, the filename is automatically extracted unless explicitly overridden.

Content and manifest are encrypted by default, so the reference is 128 hex characters and carries the key — the same rule as uploadFiles. encryptManifest: false gives a 64-character reference whose manifest anyone can read over encrypted content; encrypt: false leaves everything plain, which is what a /bzz/ gateway link to a public file wants.

Parameters:

Parameter Type Required Description
file File | Uint8Array Yes The file to upload
name string No Filename (extracted from File object if not provided)
options UploadOptions No Upload configuration (see uploadData)
options.encrypt boolean No Encrypt the file content (defaults to true). false also leaves the manifest plain
options.encryptManifest boolean No Encrypt the manifest too, so the reference carries the key (defaults to true)
requestOptions RequestOptions No Request configuration
requestOptions.timeout number No Request timeout in milliseconds for this call. Replaces the client’s default (30 s) for the whole upload — the round trip through the iframe as well as the Bee request; a file of a few MB over a testnet or the public gateway needs more, here or in new SwarmIdClient({ timeout })
requestOptions.headers Record<string, string> No Custom headers
requestOptions.endlesslyRetry boolean No Whether to retry endlessly

Returns: Promise<UploadResult> - Contains reference and optional tagUid

Throws:

  • Error if the client is not initialized
  • Error if the user is not authenticated or cannot upload
  • Error if the request times out

Example:

// From file input
const fileInput = document.querySelector('input[type="file"]')
const file = fileInput.files[0]
const result = await client.uploadFile(file)
// From Uint8Array with custom name
const data = new Uint8Array([...])
const result = await client.uploadFile(data, 'document.pdf')

downloadFile(reference, path?, options?, requestOptions?)

Section titled “downloadFile(reference, path?, options?, requestOptions?)”

Downloads a file from the Swarm network: the counterpart of uploadFile. It resolves a manifest, so a reference from uploadData fails here inside the manifest parser; use downloadData for those.

Returns both the file data and its original filename (if available). For manifest references, an optional path can be specified to retrieve a specific file from the manifest.

Parameters:

Parameter Type Required Description
reference string Yes The Swarm reference of the file
path string No Path within a manifest to retrieve a specific file
options DownloadOptions No Download configuration (see downloadData)
requestOptions RequestOptions No Request configuration
requestOptions.timeout number No Request timeout in milliseconds for this call. Replaces the client’s default (30 s) for the whole round trip, not only the Bee request
requestOptions.headers Record<string, string> No Custom headers
requestOptions.endlesslyRetry boolean No Whether to retry endlessly

Returns: Promise<FileData>

Property Type Description
name string The filename
data Uint8Array The file contents

Throws:

  • Error if the client is not initialized
  • Error if the reference is not found
  • Error if the request times out

Example:

const file = await client.downloadFile('a1b2c3...')
console.log('Filename:', file.name)
// Create download link
const blob = new Blob([file.data])
const url = URL.createObjectURL(blob)

uploadFiles(files, options?, requestOptions?)

Section titled “uploadFiles(files, options?, requestOptions?)”

Uploads a folder as one manifest: a fork per file with its path and content type. A gateway serves a plain folder, uploaded with encrypt: false, at /bzz/<reference>/<path>; the default reference carries the key and stays out of gateway URLs. Takes what bee-js takes — the FileList of an <input type="file" webkitdirectory> or a dropped directory, a File[], or { path, file } pairs for a folder the app assembled itself. A File’s path is its webkitRelativePath with the picked folder’s own name removed, or its name. Which files to include is the app’s decision; the library uploads what it is given.

Read a folder back with listFiles and downloadData per entry, or one file with downloadFile and its path.

Every file is read into memory before the upload starts. For folders larger than that, upload the files with uploadData and build the manifest with @ethersphere/core-sdk’s MantarayNode.

Parameters:

Parameter Type Required Description
files FileList | Iterable<File | { path, file: Blob }> Yes The folder’s files
options UploadFilesOptions No Upload configuration
options.encrypt boolean No Encrypt the file content (defaults to true). false also leaves the manifest plain
options.encryptManifest boolean No Encrypt the manifest too, so the root reference carries the key (defaults to true). false gives a 32-byte root reference whose manifest anyone can read, while the content stays encrypted
options.indexDocument string No The file the bare /bzz/<reference>/ serves (website-index-document), e.g. index.html
options.errorDocument string No The file served for a path that is not in the folder (website-error-document)
options.pin boolean No Pin on the user’s own node (defaults to false; ignored on a subsidised gateway)
options.deferred boolean No Whether to use deferred upload (defaults to false); see uploadData
options.tag number No Tag ID for tracking upload progress
options.onProgress (progress) => void No Called once per file with { total, processed }
options.useWorkers boolean No Stamp in a worker pool, as uploadData does
options.workerCount number No Size of that pool
requestOptions RequestOptions No Request configuration; timeout bounds the whole upload, see uploadFile

Returns: Promise<UploadResult> - Contains reference (the manifest’s) and optional tagUid

Throws:

  • Error if the client is not initialized
  • Error if the user is not authenticated or cannot upload
  • Error if the request times out

Example:

// <input type="file" webkitdirectory>
const { reference } = await client.uploadFiles(input.files)
// a public website: plain, so a gateway serves it at /bzz/<reference>/
await client.uploadFiles(input.files, {
encrypt: false,
indexDocument: 'index.html',
})
// a folder the app assembled
await client.uploadFiles([
{ path: 'index.html', file: new Blob([html], { type: 'text/html' }) },
{ path: 'assets/app.js', file: new Blob([js], { type: 'text/javascript' }) },
])

Lists the files of a manifest — one uploaded with uploadFiles, or any other. Each entry carries the path, the content type, and the reference of the file’s content, which downloadData reads. The index-document fork is not an entry.

Parameters:

Parameter Type Required Description
reference string Yes The Swarm reference of the manifest
requestOptions RequestOptions No Request configuration

Returns: Promise<CollectionEntry[]>

Property Type Description
path string The file’s path inside the folder
reference string The reference of its content, for downloadData
contentType string Its Content-Type metadata, when the manifest records one

Throws:

  • Error if the client is not initialized
  • Error if the reference is not a manifest or is not found
  • Error if the request times out

Example:

for (const { path, reference } of await client.listFiles(root)) {
const data = await client.downloadData(reference)
console.log(path, data.length)
}

uploadChunk(data, options?, requestOptions?)

Section titled “uploadChunk(data, options?, requestOptions?)”

Uploads a single chunk to the Swarm network.

Chunks are the fundamental unit of storage in Swarm (4KB each). This method is useful for low-level operations or when implementing custom chunking strategies.

data is the chunk’s payload, not a finished chunk: the proxy builds the content-addressed chunk around it (span header, BMT address) and returns that address. A chunk that already carries its span header is wrapped a second time and stored under an address nothing else computes. To store a folder as a manifest, use uploadFiles; to save a Mantaray tree of your own, use saveMantarayTreeRecursively with uploadData, which hands back the reference each node was stored under.

Parameters:

Parameter Type Required Description
data Uint8Array Yes The chunk payload, 1 to 4096 bytes
options UploadOptions No Upload configuration (see uploadData)
requestOptions RequestOptions No Request configuration
requestOptions.timeout number No Request timeout in milliseconds for this call. Replaces the client’s default (30 s) for the whole round trip, not only the Bee request
requestOptions.headers Record<string, string> No Custom headers
requestOptions.endlesslyRetry boolean No Whether to retry endlessly

Returns: Promise<UploadResult> - Contains the reference of the uploaded chunk

Throws:

  • Error if the client is not initialized
  • Error if the user is not authenticated or cannot upload
  • Error if the request times out

Example:

const chunk = new Uint8Array(4096) // 4KB chunk
chunk.fill(0x42) // Fill with data
const result = await client.uploadChunk(chunk)
console.log('Chunk reference:', result.reference)

downloadChunk(reference, options?, requestOptions?)

Section titled “downloadChunk(reference, options?, requestOptions?)”

Downloads a single chunk from the Swarm network.

Retrieves a chunk by its reference hash. This method is useful for low-level operations or when implementing custom retrieval strategies.

Parameters:

Parameter Type Required Description
reference string Yes The Swarm reference of the chunk
options DownloadOptions No Download configuration (see downloadData)
requestOptions RequestOptions No Request configuration
requestOptions.timeout number No Request timeout in milliseconds for this call. Replaces the client’s default (30 s) for the whole round trip, not only the Bee request
requestOptions.headers Record<string, string> No Custom headers
requestOptions.endlesslyRetry boolean No Whether to retry endlessly

Returns: Promise<Uint8Array> - The chunk data

Throws:

  • Error if the client is not initialized
  • Error if the reference is not found
  • Error if the request times out

Example:

const chunk = await client.downloadChunk('a1b2c3...')
console.log('Chunk size:', chunk.length)

SOC (Single Owner Chunk) methods provide read/write helpers for SOCs, which are signed chunks owned by an Ethereum address. Uploads via SOCWriter.upload are encrypted by default and return an encryptionKey for later decryption.

makeSOCReader(ownerAddress, requestOptions?)

Section titled “makeSOCReader(ownerAddress, requestOptions?)”

Creates an SOC reader bound to the given owner address.

Parameters:

Parameter Type Required Description
ownerAddress string Yes Ethereum address of the SOC owner
requestOptions RequestOptions No Request configuration
requestOptions.timeout number No Request timeout in milliseconds for this call. Replaces the client’s default (30 s) for the whole round trip, not only the Bee request
requestOptions.headers Record<string, string> No Custom headers
requestOptions.endlesslyRetry boolean No Whether to retry endlessly

Returns: SOCReader

Method Description
getOwner() Resolves the SOC owner address
download(identifier, encryptionKey) Downloads and decrypts an encrypted SOC
rawDownload(identifier, encryptionKey?) Downloads an unencrypted SOC, or decrypts if encryptionKey is provided

Throws:

  • Error if the client is not initialized
  • Error if the request times out

Example:

const owner = '0x1234...'
const reader = client.makeSOCReader(owner)
const resolvedOwner = await reader.getOwner()
const soc = await reader.download(identifier, encryptionKey)
console.log('Payload:', new TextDecoder().decode(soc.payload))

Creates an SOC writer for uploading and downloading SOCs. If signer is omitted, the proxy uses the app signer.

Parameters:

Parameter Type Required Description
signer string No Private key hex string for the SOC signer
requestOptions RequestOptions No Request configuration
requestOptions.timeout number No Request timeout in milliseconds for this call. Replaces the client’s default (30 s) for the whole round trip, not only the Bee request
requestOptions.headers Record<string, string> No Custom headers
requestOptions.endlesslyRetry boolean No Whether to retry endlessly

Returns: SOCWriter

Method Description
getOwner() Resolves the SOC owner address
upload(identifier, data, options?) Uploads an encrypted SOC
rawUpload(identifier, data, options?) Uploads an unencrypted SOC
download(identifier, encryptionKey) Downloads and decrypts an encrypted SOC
rawDownload(identifier, encryptionKey?) Downloads an unencrypted SOC, or decrypts if encryptionKey is provided

Returns (upload): Promise<SocUploadResult>

Property Type Description
reference string SOC chunk reference
owner string SOC owner address
encryptionKey string Encryption key for decrypting the SOC
tagUid number Upload tag UID, if provided
stampedChunks number | undefined Chunks this write sent, as for uploadData()

Returns (rawUpload): Promise<SocRawUploadResult>

Property Type Description
reference string SOC chunk reference
owner string SOC owner address
encryptionKey string Optional; present only if returned by proxy
tagUid number Upload tag UID, if provided
stampedChunks number | undefined Chunks this write sent, as for uploadData()

Throws:

  • Error if the client is not initialized
  • Error if the request times out

Example:

const writer = client.makeSOCWriter()
const payload = new TextEncoder().encode('Hello SOC')
const upload = await writer.upload(identifier, payload)
const owner = await writer.getOwner()
const soc = await writer.download(identifier, upload.encryptionKey)
console.log('Owner:', soc.owner)

SOC Payload Structure (download methods): SingleOwnerChunk

Property Type Description
data Uint8Array Full SOC chunk data
identifier string SOC identifier
signature string SOC signature
span number Payload span (bytes)
payload Uint8Array SOC payload data
address string SOC address/reference
owner string SOC owner address

Epoch feed methods provide time-indexed updates backed by Single Owner Chunks (SOCs). Feed updates are addressed by (topic, owner) and can be looked up by timestamp. The interface mirrors sequential feeds with upload and download helpers.

makeEpochFeedReader(options, requestOptions?)

Section titled “makeEpochFeedReader(options, requestOptions?)”

Creates a feed reader bound to a topic and optional owner.

Parameters:

Parameter Type Required Description
options.topic string Yes Feed topic (32-byte hex string)
options.owner string No Feed owner address; if omitted, resolved via proxy
requestOptions RequestOptions No Request configuration
requestOptions.timeout number No Request timeout in milliseconds for this call. Replaces the client’s default (30 s) for the whole round trip, not only the Bee request
requestOptions.headers Record<string, string> No Custom headers
requestOptions.endlesslyRetry boolean No Whether to retry endlessly

Returns: FeedReader

Method Description
getOwner() Resolves the feed owner address
downloadReference(options?) Returns the reference for timestamp options.at (requires encryption key)
downloadPayload(options?) Downloads payload data for timestamp options.at (requires encryption key)
downloadRawReference(options?) Returns unencrypted reference for timestamp options.at (for /bzz access)
downloadRawPayload(options?) Downloads unencrypted payload for timestamp options.at (for /bzz access)

Epoch download options (options):

Option Type Required Description
at number | string | bigint No Unix timestamp (seconds); defaults to current time
after number | string | bigint No Hint for latest known update timestamp
encryptionKey Uint8Array | string No Encryption key for encrypted feed updates

Returns (downloadReference):

Property Type Description
reference string | undefined Swarm reference (hex) if found
encryptionKey string | undefined Encryption key (hex) if reference is encrypted

Returns (downloadPayload):

Property Type Description
payload Uint8Array | undefined Payload bytes if found
reference string | undefined Swarm reference (hex) if found
encryptionKey string | undefined Encryption key (hex) if reference is encrypted

Example:

const reader = client.makeEpochFeedReader({ topic })
const owner = await reader.getOwner()
const reference = await reader.downloadReference({ at: BigInt(Math.floor(Date.now() / 1000)) })
const payload = await reader.downloadPayload({ at: BigInt(Math.floor(Date.now() / 1000)) })

makeEpochFeedWriter(options, requestOptions?)

Section titled “makeEpochFeedWriter(options, requestOptions?)”

Creates a feed writer for updating and reading a topic. If signer is omitted, the proxy uses the app signer.

Parameters:

Parameter Type Required Description
options.topic string Yes Feed topic (32-byte hex string)
options.signer string No Private key hex string for the feed signer
requestOptions RequestOptions No Request configuration
requestOptions.timeout number No Request timeout in milliseconds for this call. Replaces the client’s default (30 s) for the whole round trip, not only the Bee request
requestOptions.headers Record<string, string> No Custom headers
requestOptions.endlesslyRetry boolean No Whether to retry endlessly

Returns: FeedWriter

Method Description
getOwner() Resolves the feed owner address
downloadReference(options?) Returns the reference for timestamp options.at (requires encryption key)
downloadPayload(options?) Downloads payload data for timestamp options.at (requires encryption key)
downloadRawReference(options?) Returns unencrypted reference for timestamp options.at (for /bzz access)
downloadRawPayload(options?) Downloads unencrypted payload for timestamp options.at (for /bzz access)
uploadPayload(data, options?) Uploads encrypted payload data and updates the feed
uploadReference(reference, options?) Updates the feed with an encrypted reference
uploadRawPayload(data, options?) Uploads unencrypted payload (for /bzz access)
uploadRawReference(reference, options?) Updates the feed with an unencrypted reference (for /bzz access)

Epoch upload options (options):

Option Type Required Description
at number | string | bigint No Unix timestamp (seconds); defaults to current time
encrypt boolean No Whether payload uploads are encrypted (default true)
uploadOptions UploadOptions No Upload configuration (tag, pin, deferred, etc.)
encryptionKey Uint8Array | string No Encryption key for encrypted feed updates

Returns (uploadPayload / uploadReference / uploadRawPayload / uploadRawReference):

Property Type Description
socAddress string SOC address for the feed update
reference string Swarm reference stored in the feed
encryptionKey string | undefined Encryption key (hex) if reference is encrypted
epoch { start: string; level: number } The epoch where the update was stored
timestamp string The timestamp used (stringified bigint)
stampedChunks number | undefined Chunks this update sent, the payload’s upload included, as for uploadData(); absent when either part is unknown

Example:

const writer = client.makeEpochFeedWriter({ topic })
const upload = await writer.uploadPayload('Hello feed', {
at: BigInt(Math.floor(Date.now() / 1000)),
})
const latest = await writer.downloadReference({ at: BigInt(Math.floor(Date.now() / 1000)) })

Sequential feed methods provide index-based updates backed by Single Owner Chunks (SOCs) and use the chunk API only. Payload uploads are encrypted by default; raw uploads allow supplying or omitting an encryption key.

makeSequentialFeedReader(options, requestOptions?)

Section titled “makeSequentialFeedReader(options, requestOptions?)”

Creates a sequential feed reader bound to a topic and optional owner.

Parameters:

Parameter Type Required Description
options.topic string Yes Feed topic (32-byte hex string)
options.owner string No Feed owner address; if omitted, resolved via proxy
requestOptions RequestOptions No Request configuration

Returns: SequentialFeedReader

Method Description
getOwner() Resolves the feed owner address
downloadPayload(encryptionKey, options?) Downloads payload data for the given index or timestamp (requires encryption key)
downloadRawPayload(options?, encryptionKey?) Downloads raw payload data (encryption key optional)
downloadReference(encryptionKey, options?) Downloads reference for the given index or timestamp (requires encryption key)

Sequential download options (options):

Option Type Required Description
index number | string | bigint No Feed index to read (0..2^64-1)
at number | string | bigint No Unix timestamp (seconds); resolves nearest update at or before at
hasTimestamp boolean No Whether payloads include a timestamp prefix (default true)
lookupTimeoutMs number No Timeout (ms) for sequential index lookups (default 2000)

Example:

const reader = client.makeSequentialFeedReader({ topic })
const owner = await reader.getOwner()
const payload = await reader.downloadPayload(encryptionKey, { index: 0 })

makeSequentialFeedWriter(options, requestOptions?)

Section titled “makeSequentialFeedWriter(options, requestOptions?)”

Creates a sequential feed writer for updating and reading a topic. If signer is omitted, the proxy uses the app signer.

Parameters:

Parameter Type Required Description
options.topic string Yes Feed topic (32-byte hex string)
options.signer string No Private key hex string for the feed signer
requestOptions RequestOptions No Request configuration

Returns: SequentialFeedWriter

Method Description
getOwner() Resolves the feed owner address
downloadPayload(encryptionKey, options?) Downloads payload data for the given index or timestamp (requires encryption key)
downloadRawPayload(options?, encryptionKey?) Downloads raw payload data (encryption key optional)
downloadReference(encryptionKey, options?) Downloads reference for the given index or timestamp (requires encryption key)
uploadPayload(data, options?) Uploads payload data (encrypted) and updates the feed
uploadRawPayload(data, options?, encryptionKey?) Uploads raw payload data (encryption optional) and updates the feed
uploadReference(reference, options?) Uploads a reference (encrypted) and updates the feed

Sequential upload options (options):

Option Type Required Description
index number | string | bigint No Feed index to write (0..2^64-1); defaults to next index
at number | string | bigint No Unix timestamp (seconds); used when hasTimestamp is true
hasTimestamp boolean No Whether payloads include a timestamp prefix (default true)
lookupTimeoutMs number No Timeout (ms) for sequential index lookups (default 2000)
pin boolean No Whether to pin the data locally (ignored on a subsidised gateway)
encrypt boolean No Whether to encrypt the data
tag number No Tag ID for tracking upload progress (ignored on a subsidised gateway)
deferred boolean No Whether to use deferred upload

Example:

const writer = client.makeSequentialFeedWriter({ topic })
const upload = await writer.uploadPayload('Hello feed!', { index: 0 })
const payload = await writer.downloadPayload(upload.encryptionKey, { index: 0 })

createFeedManifest(topic, options?, requestOptions?)

Section titled “createFeedManifest(topic, options?, requestOptions?)”

Creates a feed manifest for accessing feed content via URL.

A feed manifest enables accessing the latest feed content via a URL path (e.g., /bzz/{manifest-reference}/). The manifest stores metadata about the feed including owner, topic, and feed type.

Parameters:

Parameter Type Required Description
topic string Yes Feed topic (32-byte hex string)
options object No Configuration options
options.owner string No Feed owner address; if omitted, uses app signer
options.feedType "Sequence" | "Epoch" No Feed type (defaults to "Sequence")
options.uploadOptions UploadOptions No Upload configuration (pin, deferred, etc.)
requestOptions RequestOptions No Request configuration
requestOptions.timeout number No Request timeout in milliseconds for this call. Replaces the client’s default (30 s) for the whole round trip, not only the Bee request
requestOptions.headers Record<string, string> No Custom headers

Returns: Promise<string> - The feed manifest reference (64 hex characters)

Throws:

  • Error if the client is not initialized
  • Error if no owner is provided and no app signer is available
  • Error if the request times out

Example:

// Create manifest for a feed (uses app signer as owner)
const manifestRef = await client.createFeedManifest(topic)
console.log('Feed accessible at /bzz/' + manifestRef)
// Create manifest with explicit owner
const manifestRef = await client.createFeedManifest(topic, {
owner: '0x1234...',
})
// Use with feed writer
const writer = client.makeSequentialFeedWriter({ topic })
const result = await writer.uploadPayload('Hello feed!')
const manifestRef = await client.createFeedManifest(topic)
// Now feed content accessible via /bzz/{manifestRef}/

GSOC (Global Single Owner Chunk) methods enable proximity-based message routing on the Swarm network. These methods allow you to mine a private key that produces a SOC address proximate to a target overlay, then send messages using that key.

gsocMine(targetOverlay, identifier, proximity?)

Section titled “gsocMine(targetOverlay, identifier, proximity?)”

Mines a private key whose SOC (Single Owner Chunk) address is proximate to a target overlay address.

This is useful for sending messages to specific nodes in the Swarm network based on their overlay address.

Parameters:

Parameter Type Required Description
targetOverlay string Yes The target overlay address to be proximate to
identifier string Yes The identifier for the SOC
proximity number No The required proximity (number of matching prefix bits)

Returns: Promise<string> - The mined signer as a hex string (private key)

Throws:

  • Error if the client is not initialized
  • Error if mining fails
  • Error if the request times out

Example:

const targetOverlay = 'a1b2c3d4e5f6...'
const identifier = 'my-channel'
const signer = await client.gsocMine(targetOverlay, identifier, 8)
console.log('Mined signer:', signer)

gsocSend(signer, identifier, data, options?, requestOptions?)

Section titled “gsocSend(signer, identifier, data, options?, requestOptions?)”

Sends a GSOC (Global Single Owner Chunk) message using a mined signer.

Use the signer obtained from gsocMine() to send messages that will be routed to nodes with the target overlay address.

Parameters:

Parameter Type Required Description
signer string Yes The mined signer (private key) from gsocMine()
identifier string Yes The identifier for the SOC (must match the one used in mining)
data Uint8Array Yes The message data to send
options UploadOptions No Upload configuration (see uploadData)
requestOptions RequestOptions No Request configuration
requestOptions.timeout number No Request timeout in milliseconds for this call. Replaces the client’s default (30 s) for the whole round trip, not only the Bee request
requestOptions.headers Record<string, string> No Custom headers
requestOptions.endlesslyRetry boolean No Whether to retry endlessly

Returns: Promise<UploadResult> - Contains the reference of the uploaded chunk

Throws:

  • Error if the client is not initialized
  • Error if the user is not authenticated or cannot upload
  • Error if the request times out

Example:

// First, mine a signer for the target overlay
const targetOverlay = 'a1b2c3d4e5f6...'
const identifier = 'my-channel'
const signer = await client.gsocMine(targetOverlay, identifier, 8)
// Then send a message using the mined signer
const message = new TextEncoder().encode('Hello, Swarm!')
const result = await client.gsocSend(signer, identifier, message)
console.log('Message sent with reference:', result.reference)

ACT (Access Control Tries) methods enable encrypted data sharing with specific grantees. Data is encrypted and only users with the appropriate public key can decrypt it.

A grantee is a compressed public key, and a SwarmID user has two of them:

  • appKey.publicKey — that user in one app origin. It is derived from the origin, so a share made out to it cannot be read from another origin, not even a dev build of the same app.
  • identity.sharingPublicKey — that user across every app they connect. Use it to share a drive or folder between two apps, or between your dev and production origins.

The proxy tries both of the reader’s keys on download, so nothing changes on the reading side. Trust consequence: anything granted to a sharing key can be read by every app that user connects — the person granting chooses which key to grant to.

By default the ACT is published with the app key, and only that origin can add or revoke grantees afterwards. Pass publisher: "identity" to actUploadData to publish with the sharing key instead, so any of the user’s apps can manage the grantee list.

The user decides which apps get the sharing key. Two switches in Swarm ID, on by default, account-wide or per app: Data sharing (reading a share made out to the sharing key, listing the grantees of one the identity published) and Write access (publishing as the identity, adding or revoking grantees of such a share). A call that needs a switch that is off rejects with permission-denied: on download the proxy still tries both keys, and refuses only when the sharing key is the one the share names, so the error means “ask the user”, not “not a grantee”. Read the switches with getPermissions() and ask with requestPermissions(). While data sharing is off, identity.sharingPublicKey is absent.

actUploadData(data, grantees, options?, requestOptions?)

Section titled “actUploadData(data, grantees, options?, requestOptions?)”

Uploads encrypted data to the Swarm network with access control for specific grantees.

The data is encrypted using ACT (Access Control Tries) and can only be downloaded by users who have one of the grantee public keys.

Parameters:

Parameter Type Required Description
data Uint8Array Yes The binary data to upload
grantees string[] Yes Array of compressed public keys (66 hex chars each)
options ActUploadOptions No Upload configuration
options.pin boolean No Whether to pin the data locally (defaults to false; ignored on a subsidised gateway)
options.tag number No Tag ID for tracking upload progress (ignored on a subsidised gateway)
options.deferred boolean No Whether to use deferred upload (defaults to false)
options.onProgress (progress) => void No Callback for tracking upload progress
options.publisher "app" | "identity" No Key that publishes: this origin’s app key (default) or the account-wide sharing key
requestOptions RequestOptions No Request configuration
requestOptions.timeout number No Request timeout in milliseconds for this call. Replaces the client’s default (30 s) for the whole round trip, not only the Bee request
requestOptions.headers Record<string, string> No Custom headers
requestOptions.endlesslyRetry boolean No Whether to retry endlessly

Returns: Promise<ActUploadResult>

Property Type Description
encryptedReference string The encrypted Swarm reference (pass to actDownloadData)
historyReference string The history reference (pass to add/revoke grantees)
granteeListReference string Reference to the grantee list
publisherPubKey string Publisher’s compressed public key (pass to actDownloadData)
actReference string The ACT reference
tagUid number | undefined The tag UID if a tag was created
stampedChunks number | undefined Chunks this write sent, the ACT, history and grantee list included, as for uploadData()

Throws:

  • Error if the client is not initialized
  • Error if the user is not authenticated or cannot upload
  • Error if the request times out

Example:

const data = new TextEncoder().encode('Secret message')
// Grantees are compressed public keys (33 bytes = 66 hex chars)
const grantees = [
'02abc123...', // Alice's public key
'03def456...', // Bob's public key
]
const result = await client.actUploadData(data, grantees, {
onProgress: (progress) => {
console.log(`Progress: ${progress.processed}/${progress.total}`)
},
})
console.log('History Reference:', result.historyReference)
console.log('Encrypted Reference:', result.encryptedReference)
console.log('Publisher Public Key:', result.publisherPubKey)
// Save these for later download:
// - encryptedReference, historyReference, publisherPubKey

actDownloadData(encryptedReference, historyReference, publisherPubKey, timestamp?, requestOptions?)

Section titled “actDownloadData(encryptedReference, historyReference, publisherPubKey, timestamp?, requestOptions?)”

Downloads and decrypts ACT-protected data from the Swarm network.

The user must have access (their public key must be in the grantee list) to decrypt the data.

Parameters:

Parameter Type Required Description
encryptedReference string Yes The encrypted reference from actUploadData
historyReference string Yes The history reference from actUploadData
publisherPubKey string Yes Publisher’s compressed public key from actUploadData
timestamp number No Unix timestamp for historical access (optional)
requestOptions RequestOptions No Request configuration
requestOptions.timeout number No Request timeout in milliseconds for this call. Replaces the client’s default (30 s) for the whole round trip, not only the Bee request
requestOptions.headers Record<string, string> No Custom headers
requestOptions.endlesslyRetry boolean No Whether to retry endlessly

Returns: Promise<Uint8Array> - The decrypted data

Throws:

  • Error if the client is not initialized
  • Error if the user does not have access (not in grantee list)
  • Error if the reference is not found
  • Error if the request times out

Example:

// Using the references from actUploadData
const data = await client.actDownloadData(encryptedReference, historyReference, publisherPubKey)
const text = new TextDecoder().decode(data)
console.log('Decrypted:', text)

actAddGrantees(historyReference, grantees, options?, requestOptions?)

Section titled “actAddGrantees(historyReference, grantees, options?, requestOptions?)”

Adds new grantees to an existing ACT.

This method adds new public keys to the ACT’s access list. The encrypted reference remains the same, but a new history reference is returned that should be used for future operations.

Parameters:

Parameter Type Required Description
historyReference string Yes The history reference from actUploadData or previous actAddGrantees
grantees string[] Yes Array of compressed public keys to add (66 hex chars each)
requestOptions RequestOptions No Request configuration
requestOptions.timeout number No Request timeout in milliseconds for this call. Replaces the client’s default (30 s) for the whole round trip, not only the Bee request
requestOptions.headers Record<string, string> No Custom headers
requestOptions.endlesslyRetry boolean No Whether to retry endlessly

Returns: Promise<ActAddGranteesResult>

Property Type Description
historyReference string New history reference (use for future ops)
granteeListReference string Reference to the updated grantee list
actReference string The ACT reference
stampedChunks number | undefined Chunks this write sent, as for uploadData()

Throws:

  • Error if the client is not initialized
  • Error if the user is not authenticated
  • Error if the request times out

Example:

const newGrantees = [
'02xyz789...', // Charlie's public key
]
const result = await client.actAddGrantees(historyReference, newGrantees)
console.log('New History Reference:', result.historyReference)
// The encrypted reference remains the same
// Use the new historyReference for future operations

actRevokeGrantees(historyReference, encryptedReference, revokeGrantees, options?, requestOptions?)

Section titled “actRevokeGrantees(historyReference, encryptedReference, revokeGrantees, options?, requestOptions?)”

Revokes access from grantees by removing them from the ACT.

Parameters:

Parameter Type Required Description
historyReference string Yes The current history reference
encryptedReference string Yes The current encrypted reference
revokeGrantees string[] Yes Array of compressed public keys to revoke (66 hex chars)
requestOptions RequestOptions No Request configuration
requestOptions.timeout number No Request timeout in milliseconds for this call. Replaces the client’s default (30 s) for the whole round trip, not only the Bee request
requestOptions.headers Record<string, string> No Custom headers
requestOptions.endlesslyRetry boolean No Whether to retry endlessly

Returns: Promise<ActRevokeGranteesResult>

Property Type Description
encryptedReference string The content reference, unchanged — see the caution above
historyReference string New history reference, without the revoked entries
granteeListReference string Reference to the updated grantee list
actReference string The ACT reference
stampedChunks number | undefined Chunks this write sent, as for uploadData()

Throws:

  • Error if the client is not initialized
  • Error if the user is not authenticated
  • Error if the request times out

Example:

const revokeKeys = [
'02abc123...', // Alice's public key (revoke access)
]
const result = await client.actRevokeGrantees(historyReference, encryptedReference, revokeKeys)
// The history reference is new — store it, and use it for everything from here on.
console.log('New history reference:', result.historyReference)
// The content reference is the same one you passed in. It is not re-encrypted.
console.log('Content reference unchanged:', result.encryptedReference === encryptedReference) // true

actGetGrantees(historyReference, requestOptions?)

Section titled “actGetGrantees(historyReference, requestOptions?)”

Retrieves the list of current grantees for an ACT.

Parameters:

Parameter Type Required Description
historyReference string Yes The history reference of the ACT
requestOptions RequestOptions No Request configuration
requestOptions.timeout number No Request timeout in milliseconds for this call. Replaces the client’s default (30 s) for the whole round trip, not only the Bee request
requestOptions.headers Record<string, string> No Custom headers
requestOptions.endlesslyRetry boolean No Whether to retry endlessly

Returns: Promise<string[]> - Array of compressed public keys (66 hex chars each)

Throws:

  • Error if the client is not initialized
  • Error if the history reference is not found
  • Error if the request times out

Example:

const grantees = await client.actGetGrantees(historyReference)
console.log('Current grantees:', grantees.length)
grantees.forEach((pubKey) => console.log(' -', pubKey))

Every rejection a client call produces is a SwarmIdError. Its message is the text the call always carried; code is the stable part to branch on, and where Bee or the gateway answered, the response is there too:

import { SwarmIdError } from '@snaha/swarm-id'
try {
await client.uploadData(data)
} catch (error) {
if (!(error instanceof SwarmIdError)) throw error
switch (error.code) {
case 'not-authenticated':
return showConnect()
case 'upload-unavailable':
// error.reason is the same vocabulary as connectionInfo.uploadUnavailableReason
return showNoDrive(error.reason)
case 'bee-rejected':
return showFailed(`${error.status}: ${error.beeMessage ?? error.message}`)
case 'timeout':
return retry()
default:
return showFailed(error.message)
}
}
Code Meaning Also set
not-authenticated No session for this origin
upload-unavailable The session refuses to stamp; see Why Uploads Are Unavailable reason
drive-not-granted The write names a drive this app was not granted; see getDrives()
permission-denied The call needs the account-wide sharing key in a way the user has not allowed this app; see getPermissions() permission
partition-contended Every partition of the batch is held by other devices and none yielded in time
lease-lost This device’s partition was reclaimed mid-write
bee-rejected Bee or the gateway answered with a non-2xx status. A 404 on /bzz and on a chunk mean different things; url — the request’s path, never the node’s host — says which status, beeMessage, url
network The request never got a response: DNS, a refused connection, or a CORS preflight the gateway rejected
timeout A deadline ran out: the proxy’s on a Bee request, or the client’s on the whole round trip (requestOptions.timeout)
invalid-request The message or an argument failed validation
invalid-state The client cannot take the call in its current state: initialize() has not resolved, was already called, or destroy() ran. A call, or an initialize(), still pending when destroy() runs rejects with this too
init-failed The proxy iframe did not come up: it failed to load, the proxy refused the origin, or it did not answer within initializationTimeout; initialize() rejects with this
popup-blocked The browser blocked the authentication popup connect() opens: not called from a user gesture, or a blocker
internal Anything else; the message is preserved

The instance is built on the client side from the fields the proxy sends — an Error posted through the iframe bridge arrives as a plain Error, so it never crosses it. An app that bundles two copies of the package should branch on error.code rather than instanceof, which is per copy.


import type {
// Client configuration
ClientOptions,
AuthStatus,
ConnectionInfo,
Avatar,
AvatarSource,
PostageBatch,
Drive,
DriveCapacity,
PartitionCapacity,
DriveKind,
DriveRequest,
DriveRequirement,
Permissions,
DriveTargetOptions,
FitOptions,
AppMetadata,
ButtonConfig,
RequestOptions,
// Upload/Download
UploadOptions,
DownloadOptions,
UploadResult,
FileData,
Reference,
// SOC
SingleOwnerChunk,
// Feed types
FeedReader,
FeedWriter,
SequentialFeedReader,
SequentialFeedWriter,
SequentialFeedPayloadResult,
SequentialFeedReferenceResult,
SequentialFeedUploadResult,
// ACT types
ActUploadOptions,
// Errors
SwarmIdErrorCode,
SwarmIdErrorDetails,
} from '@snaha/swarm-id'

Every account has an avatar, generated from its identity id — the same image Swarm ID shows for that account, so the user recognises it in both places. It is handed to you as an image at a URL rather than as markup, so the shape still holds if an avatar ever comes from somewhere other than the generator.

It arrives already resolved on every connection snapshot — there is nothing to call:

const identity = client.connectionInfo.identity
if (identity) {
img.src = identity.avatar.url
}

Avatar:

Property Type Description
source "generated" Where the image came from. Only generated, derived from the identity id, exists today
url string Renderable as an <img> source; a data: URL for generated avatars

Branch on source rather than assuming the URL always wraps an inline SVG — that keeps your code correct if another kind of image is ever added.

The avatar at a specific size. Most apps do not need this — identity.avatar is already resolved and, being vector today, scales to any size with CSS. Reach for it when you need the image rendered at a particular pixel size. It is async so that honouring a size may involve fetching, which anything but the generated avatar would.

Parameters:

Parameter Type Description
options.size number Width and height in pixels (default 40)

Returns: Promise<Avatar | undefined> — undefined when no identity is connected

const avatar = await client.getAvatar({ size: 128 })

The generated avatar as a standalone SVG string, for callers that want to inline the markup instead of pointing an <img> at a URL. Derived from the seed alone: no network access, no other dependency.

Parameters:

Parameter Type Description
seed string Value the avatar is derived from — use identity.id
size number Width and height in pixels (default 40)

Returns: string — a complete <svg> element

import { generatedAvatarSvg } from '@snaha/swarm-id'
const identity = client.connectionInfo.identity
if (identity) {
document.getElementById('avatar').innerHTML = generatedAvatarSvg(identity.id, 48)
}

The same seed always produces the same image, so it is safe to render on every onConnectionChange without caching. generatedAvatar(seed, size?) is also exported, returning the same image as an Avatar with a data: URL.


Everything above is @snaha/swarm-id, the package root, and it is the whole surface an app needs: a SwarmIdClient, its types, and a few helpers for reading uploads back. The identity site (the trusted domain) imports its own half of the protocol from @snaha/swarm-id/internal: account state sync and the fold, key derivation, the account bus, the proxy iframe. Every function there takes the account record, the master key or derivationKey, none of which ever leaves the trusted domain, so an app cannot call them and nothing on the wire hands them out. That entry is not documented here; the design pages in the repository (docs/Account-State.md, docs/Account-Bus.md) and the Key Derivation page describe what it does. It is in the package’s exports so the identity site can import it, with one more reader: a host that embeds the identity site and writes its localStorage directly, for which Storage Layout names the few schemas and functions to use. Beyond those, it carries no stability promise, its names move whenever the UI’s needs do, and a change there is not a breaking change of the package. Do not build an app on it.