Original post:
What we're building
By the end of this guide, you'll have a Discord bot that posts live CS2 match scores to a channel, updates every 60 seconds, and shows team names, current map, and odds. No database required — everything comes straight from the API.
Prerequisites
You'll need Node.js installed (v18 or newer), a Discord bot token from the Discord Developer Portal, and a free Tachio Sports API key. Sign up on the homepage with GitHub to get yours.
Step 1 — Create the Discord bot
Go to discord.com/developers/applications and create a new application. Under the Bot tab, click Add Bot and copy the token. Invite the bot to your server with the 'bot' and 'Send Messages' permissions. Keep your token secret — it's like a password for your bot.
Step 2 — Set up the project
mkdir cs2-discord-bot
cd cs2-discord-bot
npm init -y
npm install discord.js
Step 3 — The complete bot code
const { Client, GatewayIntentBits, EmbedBuilder } = require("discord.js");
const DISCORD_TOKEN = process.env.DISCORD_TOKEN;
const API_KEY = process.env.TACHIO_API_KEY;
const CHANNEL_ID = process.env.CHANNEL_ID;
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
],
});
async function fetchLiveMatches() {
const res = await fetch(
"https://api.tachiosports.com/esports/live/cs2",
{ headers: { "x-api-key": API_KEY } },
);
if (!res.ok) return [];
const data = await res.json();
return data.matches ?? [];
}
function buildEmbed(match) {
const home = match.teams.home.name ?? "TBD";
const away = match.teams.away.name ?? "TBD";
const score = match.score?.display ?? "vs";
const map = match.current_map ?? "";
const format = match.match_format ?? "";
const league = match.league.name ?? "";
const oddsHome = match.odds.match_winner.home ?? "–";
const oddsAway = match.odds.match_winner.away ?? "–";
return new EmbedBuilder()
.setColor(0xde9b35)
.setTitle(`${home} ${score} ${away}`)
.setDescription(
`${format} | ${map}\n${league}\n\n**Odds:** ${oddsHome} — ${oddsAway}`,
)
.setTimestamp();
}
let lastMessageId = null;
async function updateScores() {
const channel = client.channels.cache.get(CHANNEL_ID);
if (!channel) return;
const matches = await fetchLiveMatches();
if (matches.length === 0) {
channel.send("No live CS2 matches right now.");
return;
}
if (lastMessageId) {
try {
const oldMsg = await channel.messages.fetch(lastMessageId);
await oldMsg.delete();
} catch {}
}
const embeds = matches.slice(0, 10).map(buildEmbed);
const msg = await channel.send({
content: `**⚡ Live CS2 Matches — ${matches.length} online**`,
embeds,
});
lastMessageId = msg.id;
}
client.once("ready", () => {
console.log(`Bot logged in as ${client.user.tag}`);
updateScores();
setInterval(updateScores, 60_000);
});
client.login(DISCORD_TOKEN);
How it works
The bot calls the Tachio Sports API every 60 seconds to get live CS2 matches. It builds a Discord embed for each match showing the teams, score, current map, league, and odds. The old message is deleted before posting a new one so the channel stays clean with only the latest scores visible.
Step 4 — Run the bot
# Set your environment variables
export DISCORD_TOKEN=your-discord-bot-token
export TACHIO_API_KEY=your-tachio-api-key
export CHANNEL_ID=your-discord-channel-id
# Start the bot
node index.js
Step 5 — Deploy (free on Railway)
To keep the bot running 24/7 without your computer, deploy it to a free hosting service like Railway or Render. Push your code to GitHub, connect the repo to Railway, set the three environment variables, and deploy. The free tier handles a single bot easily.
Going further
Want more? Add a slash command like /scores that posts live scores on demand. Monitor multiple games by changing the sport parameter. Use the WebSocket endpoint for instant updates instead of polling. Add map scores by reading the maps array. The Tachio API has everything you need to build a production-ready esports bot.
Quick tip — Slash command
// Add this before client.login()
client.on("interactionCreate", async (interaction) => {
if (!interaction.isCommand()) return;
if (interaction.commandName === "scores") {
await interaction.deferReply();
const matches = await fetchLiveMatches();
const embeds = matches.slice(0, 10).map(buildEmbed);
await interaction.editReply({
content: `Live CS2 Matches — ${matches.length} online`,
embeds,
});
}
});
// Register the command (run once):
// const { REST, Routes } = require("discord.js");
// const rest = new REST().setToken(DISCORD_TOKEN);
// await rest.put(Routes.applicationCommands(CLIENT_ID), {
// body: [{ name: "scores", description: "Show live CS2 match scores" }],
// });
And that's it. In under 50 lines of code you've built a live CS2 score bot that your Discord server will love. The Tachio Sports API handles the hard part — you just build the experience. Ready to ship? Grab your API key and start coding.
Top comments (0)