This page demonstrates how to use custom_json operations for various social interactions on Hive.
What is custom_json?
The custom_json operation allows applications to broadcast custom JSON data to the blockchain. It’s commonly used for social actions like following, reblogging, and community interactions.
CustomJsonOperation Type
interface CustomJsonOperation {
required_auths: string[] // Accounts that must sign with active key
required_posting_auths: string[] // Accounts that must sign with posting key
id: string // Operation identifier (e.g., 'follow', 'reblog')
json: string // JSON string containing operation data
}
required_auths vs required_posting_auths
- required_auths: Use when the operation requires active key authority (transfers, financial operations)
- required_posting_auths: Use when the operation requires posting key authority (social actions like follow, reblog)
For most social operations, use required_posting_auths with an empty required_auths array.
Follow a User
Follow another user on Hive.
import { Transaction, PrivateKey } from 'hive-tx'
async function followUser() {
const tx = new Transaction()
await tx.addOperation('custom_json', {
required_auths: [],
required_posting_auths: ['your-username'],
id: 'follow',
json: JSON.stringify([
'follow',
{
follower: 'your-username',
following: 'user-to-follow',
what: ['blog'] // ['blog'] for following, [] for unfollowing
}
])
})
const key = PrivateKey.from('your-posting-key')
tx.sign(key)
const result = await tx.broadcast()
console.log('Follow successful!', result.result.tx_id)
}
Unfollow a User
Unfollow by setting what to an empty array.
import { Transaction, PrivateKey } from 'hive-tx'
async function unfollowUser() {
const tx = new Transaction()
await tx.addOperation('custom_json', {
required_auths: [],
required_posting_auths: ['your-username'],
id: 'follow',
json: JSON.stringify([
'follow',
{
follower: 'your-username',
following: 'user-to-unfollow',
what: [] // Empty array means unfollow
}
])
})
const key = PrivateKey.from('your-posting-key')
tx.sign(key)
const result = await tx.broadcast()
console.log('Unfollow successful!', result.result.tx_id)
}
Mute a User
Mute a user to hide their content from your feed.
import { Transaction, PrivateKey } from 'hive-tx'
async function muteUser() {
const tx = new Transaction()
await tx.addOperation('custom_json', {
required_auths: [],
required_posting_auths: ['your-username'],
id: 'follow',
json: JSON.stringify([
'follow',
{
follower: 'your-username',
following: 'user-to-mute',
what: ['ignore'] // 'ignore' means mute
}
])
})
const key = PrivateKey.from('your-posting-key')
tx.sign(key)
const result = await tx.broadcast()
console.log('User muted!', result.result.tx_id)
}
Unmute a User
import { Transaction, PrivateKey } from 'hive-tx'
async function unmuteUser() {
const tx = new Transaction()
await tx.addOperation('custom_json', {
required_auths: [],
required_posting_auths: ['your-username'],
id: 'follow',
json: JSON.stringify([
'follow',
{
follower: 'your-username',
following: 'user-to-unmute',
what: [] // Empty array removes mute
}
])
})
const key = PrivateKey.from('your-posting-key')
tx.sign(key)
const result = await tx.broadcast()
console.log('User unmuted!', result.result.tx_id)
}
Reblog a Post
Share another user’s post to your blog.
import { Transaction, PrivateKey } from 'hive-tx'
async function reblogPost() {
const tx = new Transaction()
await tx.addOperation('custom_json', {
required_auths: [],
required_posting_auths: ['your-username'],
id: 'reblog',
json: JSON.stringify([
'reblog',
{
account: 'your-username',
author: 'original-author',
permlink: 'post-permlink'
}
])
})
const key = PrivateKey.from('your-posting-key')
tx.sign(key)
const result = await tx.broadcast()
console.log('Reblog successful!', result.result.tx_id)
}
Delete Reblog
Remove a reblogged post from your blog.
import { Transaction, PrivateKey } from 'hive-tx'
async function deleteReblog() {
const tx = new Transaction()
await tx.addOperation('custom_json', {
required_auths: [],
required_posting_auths: ['your-username'],
id: 'follow',
json: JSON.stringify([
'reblog',
{
account: 'your-username',
author: 'original-author',
permlink: 'post-permlink',
delete: 'delete' // Special flag to delete reblog
}
])
})
const key = PrivateKey.from('your-posting-key')
tx.sign(key)
const result = await tx.broadcast()
console.log('Reblog deleted!', result.result.tx_id)
}
Subscribe to a Hive community.
import { Transaction, PrivateKey } from 'hive-tx'
async function subscribeToCommunity() {
const tx = new Transaction()
await tx.addOperation('custom_json', {
required_auths: [],
required_posting_auths: ['your-username'],
id: 'community',
json: JSON.stringify([
'subscribe',
{
community: 'hive-123456' // Community account name
}
])
})
const key = PrivateKey.from('your-posting-key')
tx.sign(key)
const result = await tx.broadcast()
console.log('Subscribed to community!', result.result.tx_id)
}
import { Transaction, PrivateKey } from 'hive-tx'
async function unsubscribeFromCommunity() {
const tx = new Transaction()
await tx.addOperation('custom_json', {
required_auths: [],
required_posting_auths: ['your-username'],
id: 'community',
json: JSON.stringify([
'unsubscribe',
{
community: 'hive-123456'
}
])
})
const key = PrivateKey.from('your-posting-key')
tx.sign(key)
const result = await tx.broadcast()
console.log('Unsubscribed from community!', result.result.tx_id)
}
Pin a post in your community (requires admin/moderator role).
import { Transaction, PrivateKey } from 'hive-tx'
async function pinCommunityPost() {
const tx = new Transaction()
await tx.addOperation('custom_json', {
required_auths: [],
required_posting_auths: ['your-username'],
id: 'community',
json: JSON.stringify([
'pinPost',
{
community: 'hive-123456',
account: 'post-author',
permlink: 'post-permlink'
}
])
})
const key = PrivateKey.from('your-posting-key')
tx.sign(key)
const result = await tx.broadcast()
console.log('Post pinned!', result.result.tx_id)
}
import { Transaction, PrivateKey } from 'hive-tx'
async function unpinCommunityPost() {
const tx = new Transaction()
await tx.addOperation('custom_json', {
required_auths: [],
required_posting_auths: ['your-username'],
id: 'community',
json: JSON.stringify([
'unpinPost',
{
community: 'hive-123456',
account: 'post-author',
permlink: 'post-permlink'
}
])
})
const key = PrivateKey.from('your-posting-key')
tx.sign(key)
const result = await tx.broadcast()
console.log('Post unpinned!', result.result.tx_id)
}
Mute a post in your community (moderator action).
import { Transaction, PrivateKey } from 'hive-tx'
async function muteCommunityPost() {
const tx = new Transaction()
await tx.addOperation('custom_json', {
required_auths: [],
required_posting_auths: ['your-username'],
id: 'community',
json: JSON.stringify([
'mutePost',
{
community: 'hive-123456',
account: 'post-author',
permlink: 'post-permlink',
notes: 'Reason for muting'
}
])
})
const key = PrivateKey.from('your-posting-key')
tx.sign(key)
const result = await tx.broadcast()
console.log('Post muted!', result.result.tx_id)
}
Assign a role to a user in your community (requires admin).
import { Transaction, PrivateKey } from 'hive-tx'
async function setUserRole() {
const tx = new Transaction()
await tx.addOperation('custom_json', {
required_auths: [],
required_posting_auths: ['your-username'],
id: 'community',
json: JSON.stringify([
'setRole',
{
community: 'hive-123456',
account: 'user-account',
role: 'mod' // Roles: 'admin', 'mod', 'member', 'guest'
}
])
})
const key = PrivateKey.from('your-posting-key')
tx.sign(key)
const result = await tx.broadcast()
console.log('User role set!', result.result.tx_id)
}
Update your community settings (requires admin).
import { Transaction, PrivateKey } from 'hive-tx'
async function updateCommunitySettings() {
const tx = new Transaction()
await tx.addOperation('custom_json', {
required_auths: [],
required_posting_auths: ['your-username'],
id: 'community',
json: JSON.stringify([
'updateProps',
{
community: 'hive-123456',
props: {
title: 'My Community Title',
about: 'Community description',
lang: 'en',
description: 'Longer community description',
flag_text: 'Rules for the community',
is_nsfw: false
}
}
])
})
const key = PrivateKey.from('your-posting-key')
tx.sign(key)
const result = await tx.broadcast()
console.log('Community updated!', result.result.tx_id)
}
Custom App-Specific JSON
You can create custom operations for your own application.
import { Transaction, PrivateKey } from 'hive-tx'
async function customAppOperation() {
const tx = new Transaction()
await tx.addOperation('custom_json', {
required_auths: [],
required_posting_auths: ['your-username'],
id: 'my-app', // Your app identifier
json: JSON.stringify({
action: 'like',
target: 'post-id-123',
metadata: {
timestamp: Date.now(),
version: '1.0.0'
}
})
})
const key = PrivateKey.from('your-posting-key')
tx.sign(key)
const result = await tx.broadcast()
console.log('Custom operation successful!', result.result.tx_id)
}
Using Active Authority
For operations requiring active key (e.g., financial operations).
import { Transaction, PrivateKey } from 'hive-tx'
async function customJsonWithActiveAuth() {
const tx = new Transaction()
await tx.addOperation('custom_json', {
required_auths: ['your-username'], // Active key required
required_posting_auths: [],
id: 'financial-operation',
json: JSON.stringify({
action: 'transfer_tokens',
amount: 100,
to: 'recipient'
})
})
const key = PrivateKey.from('your-active-key') // Active key, not posting
tx.sign(key)
const result = await tx.broadcast()
console.log('Active auth operation successful!', result.result.tx_id)
}
Common custom_json ID Values
follow - Following, unfollowing, muting users
reblog - Reblogging posts
community - Community operations
notify - Notification settings
rc - Resource credit delegations
- Custom app IDs for your application
Important Notes
- Most social operations use posting key (
required_posting_auths)
- Financial operations use active key (
required_auths)
- The
json field must be a valid JSON string
- Community operations require appropriate permissions (admin/mod)
- Custom app IDs should be unique to avoid conflicts
When developing custom operations, choose a unique id value for your app to avoid conflicts with other applications on the blockchain.