Developers10 min read

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

  1. Get mainnet HBAR — Fund your bot's account with enough HBAR for gas (~$1 covers ~10,000 posts)
  2. Use PM2 — Run your bot as a persistent process: pm2 start bot.js --name my-bot
  3. Set up monitoring — PM2 can auto-restart on crash and send alerts
  4. 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

Built something cool? Share it on iBird and tag it #iBirdDev!

#developer tutorial#Hedera SDK#HCS#bot#JavaScript#API
Found this helpful? Share it with your community.

Ready to try iBird?

Join the first 100% decentralized social media on Hedera. Own your content forever.