Back to posts
Gaming & Tools January 20, 2025 · by Florin

Building a FACEIT Discord Bot from Scratch

Step-by-step guide to building a Discord bot that pulls FACEIT stats, tracks matches, and posts live results.

discordfaceitbotnode.jsapi

What we’re building

A Discord bot that:

  • Looks up player FACEIT stats with a command
  • Tracks live matches for registered players
  • Posts match results automatically to a channel

Prerequisites

Project setup

mkdir faceit-bot && cd faceit-bot
npm init -y
npm install discord.js axios dotenv

Create your .env:

DISCORD_TOKEN=your_bot_token
FACEIT_API_KEY=your_api_key
GUILD_ID=your_server_id

Basic bot structure

// index.js
const { Client, GatewayIntentBits, SlashCommandBuilder } = require('discord.js');
const axios = require('axios');
require('dotenv').config();

const client = new Client({
  intents: [GatewayIntentBits.Guilds],
});

const faceit = axios.create({
  baseURL: 'https://open.faceit.com/data/v4',
  headers: { Authorization: `Bearer ${process.env.FACEIT_API_KEY}` },
});

client.once('ready', () => {
  console.log(`Logged in as ${client.user.tag}`);
});

client.login(process.env.DISCORD_TOKEN);

Adding the /stats command

// Register command
const statsCmd = new SlashCommandBuilder()
  .setName('stats')
  .setDescription('Get FACEIT stats for a player')
  .addStringOption(opt =>
    opt.setName('nickname').setDescription('FACEIT nickname').setRequired(true)
  );

// Handle interaction
client.on('interactionCreate', async (interaction) => {
  if (!interaction.isChatInputCommand()) return;
  if (interaction.commandName !== 'stats') return;

  const nickname = interaction.options.getString('nickname');
  await interaction.deferReply();

  try {
    const { data: player } = await faceit.get(`/players?nickname=${nickname}`);
    const { data: stats } = await faceit.get(
      `/players/${player.player_id}/stats/cs2`
    );

    const seg = stats.segments[0]?.stats;

    await interaction.editReply({
      embeds: [{
        title: `${player.nickname} — Level ${player.games.cs2.faceit_elo}`,
        fields: [
          { name: 'ELO', value: String(player.games.cs2.faceit_elo), inline: true },
          { name: 'K/D', value: seg?.['Average K/D Ratio'] ?? 'N/A', inline: true },
          { name: 'Win Rate', value: seg?.['Win Rate %'] ? `${seg['Win Rate %']}%` : 'N/A', inline: true },
          { name: 'Matches', value: seg?.Matches ?? 'N/A', inline: true },
        ],
        color: 0xf97316,
      }],
    });
  } catch {
    await interaction.editReply('Player not found or API error.');
  }
});

Next steps

  • Add match tracking with webhooks
  • Store player registrations in a database (PostgreSQL + Prisma)
  • Build an ELO graph over time
  • Add team balance calculator for 10-mans

I’ll cover match tracking and webhooks in part 2.