Build a Hedera Social Media Bot: Post to iBird via HCS (Developer Tutorial)
Step-by-step developer tutorial: build an autonomous bot that posts messages to Hedera Consensus Service topics. Includes code examples in JavaScript with the Hedera SDK.
What You'll Build
In this tutorial, you'll build an autonomous bot that posts messages to Hedera Consensus Service (HCS) topics — the same infrastructure that powers iBird. Your bot will be able to:
- Post messages to any HCS topic
- Read messages from topics (like a feed)
- Interact with iBird's Explorer topic
- Run on a schedule (e.g., post every hour)
This is the foundation for building AI agents, automated announcement bots, price feeds, or any application that needs to publish immutable messages on Hedera.
Prerequisites
- Node.js 18+ and npm
- A Hedera testnet or mainnet account (create one free at portal.hedera.com)
- Basic JavaScript/TypeScript knowledge
Step 1: Install Dependencies
npm init -y
npm install @hashgraph/sdk dotenv
Step 2: Set Up Environment Variables
Create a .env file with your Hedera account credentials:
# Get these from https://portal.hedera.com (free testnet account)
ACCOUNT_ID=0.0.xxxxxxx
PRIVATE_KEY=302e020100300506032b657004220420xxxxxxxx
# iBird Explorer topic on mainnet
# For testnet, create your own topic first
TOPIC_ID=0.0.10214045
# Use "testnet" or "mainnet"
NETWORK=testnet
⚠️ Never commit your .env file to git. Add it to .gitignore immediately.
Step 3: Initialize the Hedera Client
import { Client, AccountId, PrivateKey, TopicMessageSubmitTransaction } from "@hashgraph/sdk";
import dotenv from "dotenv";
dotenv.config();
const accountId = AccountId.fromString(process.env.ACCOUNT_ID!);
const privateKey = PrivateKey.fromString(process.env.PRIVATE_KEY!);
const topicId = process.env.TOPIC_ID!;
const client = Client.forTestnet();
client.setOperator(accountId, privateKey);
// For mainnet:
// const client = Client.forMainnet();
// client.setOperator(accountId, privateKey);
console.log("✅ Hedera client initialized");
console.log("Account:", accountId.toString());
console.log("Topic:", topicId);
Step 4: Post a Message to an HCS Topic
async function postMessage(content: string) {
// Format the message in iBird's JSON structure
const message = JSON.stringify({
Type: "Post",
Message: content,
Timestamp: Date.now(),
});
const transaction = new TopicMessageSubmitTransaction({
topicId: topicId,
message: Buffer.from(message).toString("base64"),
});
const txResponse = await transaction.execute(client);
const receipt = await txResponse.getReceipt(client);
console.log("✅ Message posted!");
console.log("Sequence:", receipt.topicSequenceNumber.toString());
console.log("Tx hash:", txResponse.transactionId.toString());
return receipt.topicSequenceNumber.toString();
}
// Post your first message
await postMessage("Hello from my Hedera bot! 🐦");
That's it! In ~3 seconds, your message is permanently recorded on Hedera with absolute finality. It costs ~$0.0001 in testnet HBAR.
Step 5: Read Messages from a Topic
import axios from "axios";
async function readMessages(topicId: string, limit: number = 10) {
const mirrorNodeUrl = "https://testnet.mirrornode.hedera.com";
// For mainnet: "https://mainnet.mirrornode.hedera.com"
const response = await axios.get(
`${mirrorNodeUrl}/api/v1/topics/${topicId}/messages?order=desc&limit=${limit}`
);
const messages = response.data.messages.map((msg: any) => {
const decoded = Buffer.from(msg.message, "base64").toString("utf-8");
try {
return {
sequence: msg.sequence_number,
timestamp: msg.consensus_timestamp,
sender: msg.payer_account_id,
content: JSON.parse(decoded),
};
} catch {
return {
sequence: msg.sequence_number,
timestamp: msg.consensus_timestamp,
sender: msg.payer_account_id,
content: decoded,
};
}
});
return messages;
}
// Read the latest 10 messages
const messages = await readMessages(topicId, 10);
messages.forEach((msg) => {
console.log(`#${msg.sequence}: ${JSON.stringify(msg.content)}`);
});
Step 6: Add Media (Upload to Arweave)
To post images with your messages, upload them to Arweave and include the hash:
import Arweave from "arweave";
import { JWKInterface } from "arweave/node/lib/wallet";
// Initialize Arweave
const arweave = Arweave.init({
host: "arweave.net",
port: 443,
protocol: "https",
});
async function uploadImage(buffer: Buffer, contentType: string) {
// Load your Arweave wallet key (generate one at arweave.org)
const key = require("./arweave-key.json") as JWKInterface;
const transaction = await arweave.createTransaction({
data: buffer,
});
transaction.addTag("Content-Type", contentType);
await arweave.transactions.sign(transaction, key);
await arweave.transactions.post(transaction);
return `https://arweave.net/${transaction.id}`;
}
// Post with image
const imageUrl = await uploadImage(imageBuffer, "image/jpeg");
await postMessage("Check out this image!", imageUrl);
Step 7: Run on a Schedule
import cron from "node-cron";
// Post every hour at minute 0
cron.schedule("0 * * * *", async () => {
console.log(`[${new Date().toISOString()}] Running scheduled post...`);
const message = `Hourly update: BTC price is $${await getBtcPrice()}`;
await postMessage(message);
});
console.log("🤖 Bot started. Posting every hour.");
iBird Message Format Reference
iBird recognizes specific JSON fields in HCS messages. Here's the format:
// Standard Post
{
"Type": "Post",
"Message": "Your post content here",
"Media": "https://arweave.net/xxx", // optional
}
// Reply to another post
{
"Type": "Post",
"Message": "Great point!",
"Reply_to": "0.0.10214045@123", // topicId@sequenceNumber
}
// Like a post
{
"Like_to": "0.0.10214045@123",
}
// Thread
{
"Type": "Thread",
"Message": "Starting a new thread...",
"Thread": "0.0.xxxxxxx", // thread topic ID
}
Deploying Your Bot
- Get mainnet HBAR — Fund your bot's account with enough HBAR for gas (~$1 covers ~10,000 posts)
- Use PM2 — Run your bot as a persistent process:
pm2 start bot.js --name my-bot - Set up monitoring — PM2 can auto-restart on crash and send alerts
- Keep your keys secure — Use environment variables, never hardcode
What's Next?
Now you can build:
- 🤖 AI agents that post autonomously (iBird's Elon Bot is already live!)
- 📊 Price feeds — Post real-time token prices to a topic
- 🔔 Notification bots — Monitor HCS topics and alert on new messages
- 📝 Cross-posters — Mirror content from X/Telegram to iBird
- 🏗️ Custom apps — Build your own UI on top of iBird's HCS topics
Resources
- Hedera Developer Documentation
- Hedera SDK on GitHub
- iBird App — see live HCS messages
- HashScan — Hedera Block Explorer
Built something cool? Share it on iBird and tag it #iBirdDev!
Frequently Asked Questions
How do you build a social media bot on Hedera?
Use the Hedera SDK (@hashgraph/sdk) to submit TopicMessageSubmitTransaction messages to an HCS topic — the same infrastructure that powers iBird. Initialize a client with your account ID and private key from the Hedera portal, format messages in iBird's JSON structure, and read messages back via the free mirror node REST API. A basic posting bot is under 30 lines of code.
How much does it cost to run a Hedera bot?
Each HCS message costs ~$0.0001 in fees, so $1 of HBAR covers roughly 10,000 posts. Testnet accounts are free via portal.hedera.com. This makes Hedera the cheapest major network for high-frequency bot posting — thousands of times cheaper than Ethereum or Solana for equivalent message volume.
What is the iBird HCS message format?
iBird recognizes JSON messages on HCS topics with fields like Type ('Post' or 'Thread'), Message (content), Media (optional Arweave URL), Reply_to ('topicId@sequenceNumber' format), and Like_to (for reactions). Messages are base64-encoded and rendered by any compatible client — the protocol is open.
Can AI agents post to Hedera social media autonomously?
Yes. The same HCS topic structure supports autonomous AI agents — iBird's Elon Bot is already live. Agents combine an LLM for content generation with the Hedera SDK for posting, typically scheduled via node-cron. Each post is an immutable, timestamped transaction verifiable on HashScan.