Skip to content

Broadcast safely

Broadcast operations submit signed transactions to Blurt Layer 1. They can change account state, create content, vote, transfer funds, update custom JSON and perform other irreversible actions.

Use this guide before adding client.broadcast to an application. If you only need blockchain data, use Read chain data or Use Nexus social data instead.

The broadcast boundary

A safe application keeps three stages separate:

text
1. Query blockchain data
   No private key. No chain change.

2. Build an operation
   Local payload construction. Still no broadcast.

3. Sign and broadcast
   Private key or wallet approval required. Real chain effect.

Do not collapse these stages in user interfaces. Let users inspect what will be signed and broadcast.

Authority selection

Different operations require different authorities.

Operation familyTypical authorityExamples
Social/content actionspostingvote, comment, delete comment, follow, reblog, community subscribe
Funds and account-sensitive actionsactivetransfer, vesting, delegation, savings, escrow, proposals
Witness and governance actionsactive/owner by operationwitness vote/proxy/update, witness properties, proposal create/vote/remove
Account recovery / ownership changesowner or recovery-account authorityrecovery request, recovery confirmation, recovery-account change
Memo decryption/encryptionmemo keynot a broadcast authority

Use the least powerful authority that satisfies the operation. Read Accounts and authorities before asking users for keys.

Never hard-code private keys

Private keys are application secrets. Do not commit them, paste them into examples, or bake them into browser bundles.

Prefer:

  • wallet integrations;
  • user-controlled signing flows;
  • environment variables for local scripts;
  • encrypted stores for backend services;
  • short-lived explicit approval flows.

Avoid:

  • source-code key literals;
  • logging private keys or signed payloads with secrets;
  • asking for active/owner keys when posting authority is enough;
  • browser signing flows without an XSS and supply-chain threat model.

Build before broadcasting

Use operation builders when your application needs previews, tests or external signing.

ts
import { buildPostOperation } from '@beblurt/dblurt';

const operation = buildPostOperation({
    author: 'alice',
    title: 'Hello Blurt',
    body: 'Body text',
    tags: ['blurt', 'sdk']
});

console.log(operation);

This creates a Layer 1 operation. It does not sign and does not broadcast.

Builders are useful when you want to show the exact operation payload before handing it to a wallet or signing workflow.

Broadcast a vote

This example shows the shape of a direct broadcast workflow. It assumes your application already has a safe key-handling path.

ts
import { Client, PrivateKey } from '@beblurt/dblurt';

const client = new Client(['https://rpc.blurt.blog']);
const key = PrivateKey.fromString(process.env.BLURT_POSTING_KEY ?? '');

const confirmation = await client.broadcast.vote({
    voter: 'alice',
    author: 'bob',
    permlink: 'hello-blurt',
    weight: 10_000
}, key);

console.log(confirmation.id);

For application code, validate all identities and the vote weight before signing.

Broadcast custom JSON

Social helpers such as follows, reblogs and community actions are custom_json operations.

ts
const confirmation = await client.broadcast.follow('alice', 'bob', key);
console.log(confirmation.id);

For custom application payloads, use customJson directly:

ts
await client.broadcast.customJson({
    required_auths: [],
    required_posting_auths: ['alice'],
    id: 'my-app',
    json: JSON.stringify({ action: 'ping', ts: Date.now() })
}, key);

Keep custom JSON payloads deterministic and inspectable before signing.

Broadcast helper families

client.broadcast provides first-class helpers for the Layer 1 operation families normal applications are likely to own:

WorkflowHelpers
Contentcomment(), commentOptions(), deleteComment()
Voting/social custom JSONvote(), follow(), unfollow(), mute(), unmute(), reblog(), undoReblog(), community helpers
Funds and vestingtransfer(), transferToVesting(), withdrawVesting(), setWithdrawVestingRoute(), delegateVestingShares()
SavingstransferToSavings(), transferFromSavings(), cancelTransferFromSavings()
EscrowescrowTransfer(), escrowApprove(), escrowDispute(), escrowRelease()
Account recoveryrequestAccountRecovery(), recoverAccount(), changeRecoveryAccount()
Witness managementaccountWitnessVote(), witnessUpdate(), witnessSetProperties()
Deprecated compatibilityaccountWitnessProxy(), claimAccount(), createClaimedAccount() remain serializable, but current Blurt Layer 1 evaluators reject them after hardfork activation; see Deprecations.
Governance proposalscreateProposal(), updateProposalVotes(), removeProposal()

Use sendOperations() when you need to submit a valid Layer 1 operation that intentionally has no dedicated helper.

Prepare and sign without broadcasting

Some applications need to prepare and sign before submitting through a separate channel.

ts
const transaction = await client.broadcast.prepareTransaction([
    ['vote', {
        voter: 'alice',
        author: 'bob',
        permlink: 'hello-blurt',
        weight: 10_000
    }]
]);

const signed = client.broadcast.sign(transaction, key);
console.log(signed.signatures);

This still handles sensitive signing material. Treat it as a high-risk path even if submission happens later.

Ambiguous failures

Broadcast failures are different from failed blockchain queries.

If a network timeout happens after submission, the transaction may have been:

  • accepted and included;
  • rejected by the node;
  • still propagating;
  • never received by the endpoint.

Applications should retain and surface enough local context to help users reconcile the result. Do not blindly retry a broadcast operation as if it were an ordinary data query.

When public RPC nodes expose transaction_status_api, use client.transactionStatus.findTransaction(confirmation.id) to check a transaction id after broadcast. Status lookup is an observation step; it does not make a retry automatically safe.

Timeout and retry semantics

Treat broadcast timeouts as ambiguous. A timeout after submission is not proof that the transaction failed and not proof that it succeeded.

Recommended application behavior:

  1. keep the locally generated transaction id;
  2. show the user that the result is unknown;
  3. query transaction status where the selected RPC endpoint exposes transaction_status_api;
  4. avoid automatic duplicate broadcasts unless the application has a protocol-aware idempotency plan.

client.transactionStatus.findTransaction(id) is an observation helper, not a retry policy. Applications still own duplicate-submission, UX and reconciliation decisions.

Before you broadcast

Check all of the following:

  1. The user intended the action.
  2. The operation payload is visible or otherwise auditable.
  3. The operation uses the least powerful authority.
  4. The signing key or wallet belongs to the expected account.
  5. The endpoint list is trusted.
  6. The UI can explain success, rejection and ambiguous network failures.
  7. The application has a plan for duplicate submissions and retries.

API details

Use the API reference for exact method signatures and transaction types: