Self-hosted service
soruly/trace.moe-telegram-bot avatar
soruly/trace.moe-telegram-bot

trace.moe-telegram-bot answers a screenshot with an anime, episode and timestamp

This Telegram Bot can tell the anime when you send an screenshot to it

561 stars77 forksTypeScriptMIT

At a glance

What is it?
This Telegram bot forwards a screenshot to trace.moe and replies with the anime title, episode and time code, plus a muted-on-request video preview, and it can be self-hosted with a token, a webhook and a Node or Docker runtime.
Who is it for?
Use trace.moe-telegram-bot if you want the hosted bot at t.me/WhatAnimeBot for quick lookups, or run your own instance if your screenshots should not pass through a third party, since the whole deployment is a token, a webhook and a small Node service. Do not use it as a general reverse image search, since it is built for the trace.moe anime index specifically.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The answer is a title, an episode and a time code

The bot does one thing: you send it a screenshot of an anime scene and it tells you what you are looking at. The output has three parts, the anime title, the episode, and the timestamp within that episode, and the bot also sends a video preview of the matched scene so you can confirm it by ear as well as by eye.

The input side is more forgiving than a plain picture message. Images, GIFs, video and stickers are all supported, as is a URL, and you can forward an image from another chat to the bot rather than uploading it yourself. Languages are handled on the reply side, with English, Japanese and two Chinese variants available, and the language preference is set with a command rather than inferred.

Under the hood the bot is a thin front end over trace.moe, the anime frame search service. The repository topics list it as cbir, image-retrieval, image-search and visual-search, and the package description says the same thing in plain words. That framing matters for expectations: it finds the closest match in an anime frame index, so it answers scene questions and will not identify a poster, a logo or a Western film.

Search options are keywords in the caption

Three keywords control the behaviour, and they are typed into the message text or the caption of the image. The mute keyword mutes the audio of the generated preview video, which is the one you will use most in a place where sound is unwelcome. The nocrop keyword disables the automatic border cropping that happens before the search, so a frame with a letterbox or a black bar goes to trace.moe unaltered. The skip keyword skips generating the preview video altogether and returns only the text result.

The README gives a concrete example of combining them, a message reading the bot mention followed by mute and nocrop, and separately mentions captioning an image with skip. The options are plain text keywords rather than menu buttons, which means they work in a one-to-one chat and in a group reply alike, and there is no separate command to learn for them beyond the two that do exist.

There are only two bot commands, /help for the usage information and /lang or /setlang for changing the preferred language, which can be set to English, Japanese, either Chinese variant, or Auto.

Group use needs Privacy Mode switched off

The bot works in group chats, and the mechanics differ from a private chat. In a group you reply to an anime screenshot and mention the bot, and it answers in the thread. If you want the mention to autocomplete while you type, you add the bot to the group, and the README is direct about the cost of that: the bot then has access to your group messages.

That is a Telegram platform constraint rather than a design choice in the bot, and it has a matching setup requirement. Privacy Mode has to be disabled if you want to use the bot in a group chat, and the README asks you to read Telegram's own tutorial for creating a bot first. Privacy Mode is what stops a bot from reading messages that do not mention it, so disabling it is the price of a bot that can respond to a reply plus a mention.

There is a Guest Mode as well, and the practical advice for anyone worried about the hosted instance is that self-hosting is the answer: the README says that if you have a privacy concern you can host the bot on your own, which puts the screenshot traffic on infrastructure you control.

Self hosting needs a token, a webhook and five settings

Running your own instance is a small job, and the configuration is a short environment file. The .env.example in the repository is the reference, and it holds six keys:

bash
TELEGRAM_TOKEN=       # e.g. 111111111:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
TELEGRAM_WEBHOOK=     # e.g. https://your.host.com/
PORT=                 # (optional) Default: 3000
ADDR=                 # (optional) Default: 0.0.0.0
TRACE_MOE_KEY=        # (optional)
FILTER_ADULT=         # (optional) Default: true

Two of these deserve attention. The token is the Telegram bot credential, and the webhook is the public URL Telegram posts updates to, which is why the service needs a stable address on the internet. PORT and ADDR are the listen address, defaulting to port 3000 on 0.0.0.0, and TRACE_MOE_KEY is optional, so an unauthenticated deployment against the public trace.moe service is possible but is likely to hit rate limits.

FILTER_ADULT is the setting people forget. It defaults to true, meaning adult results are filtered, and the flag exists because the underlying service indexes content that is not always appropriate to return in a chat. Setting it is a decision about your instance, not a default you inherit silently.

The Docker image is an Alpine Node image with tini in front

An image is published on Docker Hub and on the GitHub Container Registry, and the README gives the run command with the environment passed inline:

bash
docker run -it --rm --name trace-moe-tg-bot \
  -e TELEGRAM_WEBHOOK=https://your.host.com/ \
  -e TELEGRAM_TOKEN=111111111:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA \
  -p 443:3000 \
  ghcr.io/soruly/trace.moe-telegram-bot:latest

The port mapping in that command is worth noticing, because the container listens on 3000 while the host publishes 443, and the README states plainly that you need to configure a reverse proxy if you need HTTPS. The bot receives webhook traffic from Telegram over the public internet, so in practice the reverse proxy is not optional for a deployment that has to work.

The image itself is small by design. The Dockerfile starts from node:lts-alpine, installs tini as the init process and sets it as the entrypoint, sets NODE_ENV to production, copies package.json and the lock file, installs with npm install --omit=dev, and then copies server.ts and the src directory before running node server.ts. Excluding dev dependencies and shipping a single entry file keeps the image lean, and tini is there so signals and zombie processes are handled properly in the container.

Node on bare metal, and a version requirement that changed

Running without a container is three commands and a configuration file. The README asks for Node.js 22.18 or newer, then clones the repository, moves into the directory and installs the dependencies:

bash
git clone https://github.com/soruly/trace.moe-telegram-bot.git
cd trace-moe-telegram-bot
npm install

After that you copy .env.example to .env and edit it, and start the service:

bash
npm start

The package manifest is where the detail sits. The project is version 3.0.0, its type is module, its main entry is server.ts, and the start script runs node with the --dns-result-order=ipv6first flag, which is a deliberate choice about how the process resolves DNS and which matters on hosts where IPv6 is advertised but unreachable. The manifest also lists an engines requirement of Node 24 or newer, which is stricter than the 22.18 the README mentions, and the dev dependency on the Telegram bot API client is a development dependency while the service itself is written in TypeScript and run directly by Node.

So check the manifest rather than the README before provisioning a runtime.

A systemd unit for a long-running service

For a bare metal install that should survive a reboot, the README supplies a systemd unit file to place at /etc/systemd/system/trace.moe-telegram-bot.service:

bash
[Unit]
Description=trace.moe-telegram-bot
Wants=network-online.target
After=network-online.target

[Service]
User=____
Group=____
WorkingDirectory=/home/____/project/trace.moe-telegram-bot
Environment=NODE_ENV=production
ExecStart=/usr/bin/node --dns-result-order=ipv6first /home/____/project/trace-moe-telegram-bot/server.ts
Restart=always

[Install]
WantedBy=multi-user.target

The placeholders are for the user and group the service runs as, and for the checkout path, and the ExecStart line repeats the same --dns-result-order=ipv6first flag the npm start script uses, so the ordering preference survives even if the service is started by systemd rather than by the package script. Restart=always with the unit ordered after network-online.target gives you a service that comes back after a crash and waits for the network before its first start.

Running the bot as a dedicated unprivileged user, rather than as root, is the other thing this file gets right by default, and it is a small but real hardening win over a container run with default credentials.

MIT licensed, no releases, and a security policy in the tree

The licence is MIT and the LICENSE file sits at the root of the repository. There are no GitHub releases, so version tracking is done through the package manifest, which currently reads 3.0.0, and through the CHANGELOG.md in the repository root. The last push was on 2026-10-14 and the repository is not archived, so the project is being worked on.

The repository is a TypeScript project with a src directory, a single server.ts entry point, a tsconfig.json, a package-lock.json, a Dockerfile and an .oxfmtrc.json. The toolchain is oxfmt for formatting and oxlint for linting, with the test script defined as a format check followed by a lint pass, so the whole quality gate is two commands and no test framework in the manifest.

There is also a SECURITY.md and a CODE_OF_CONDUCT.md, and an AGENTS.md that tells automated coding assistants how to work in the repository. For a bot whose job is to receive images from strangers, the presence of a security policy in the tree is a reasonable signal, though the README does not document a vulnerability reporting process beyond that file, and the hosted bot at t.me/WhatAnimeBot remains the path of least resistance for a one-off lookup.

Editorial conclusion

Use trace.moe-telegram-bot if you want the hosted bot at t.me/WhatAnimeBot for quick lookups, or run your own instance if your screenshots should not pass through a third party, since the whole deployment is a token, a webhook and a small Node service. Do not use it as a general reverse image search, since it is built for the trace.moe anime index specifically. Before you self-host, check three things: that your Node version satisfies the package requirement of 24 or newer, which is stricter than the 22.18 the README asks for, that TELEGRAM_WEBHOOK is reachable over HTTPS through your own reverse proxy, and that you decide the FILTER_ADULT setting deliberately, because it defaults to true. The code is MIT licensed, there are no GitHub releases, and the last push was on 2026-10-14.

Frequently asked questions

What does the trace.moe Telegram bot do with a screenshot?

It sends the image to trace.moe and replies with the anime title, the episode and the timestamp of the scene, and it can also send a video preview of that scene. Images, GIFs, video, stickers and URLs are accepted, and images forwarded from other chats work too.

How do I self-host the trace.moe Telegram bot?

Copy `.env.example` to `.env` and set `TELEGRAM_TOKEN` and `TELEGRAM_WEBHOOK`, then run `npm install` and `npm start` on Node.js, or use the published container image with `docker run`. HTTPS needs your own reverse proxy in front of the service.

What do the mute, nocrop and skip keywords do in trace.moe-telegram-bot?

They are optional keywords you type in the message or caption. `mute` mutes the audio of the preview video, `nocrop` disables automatic border cropping before the search, and `skip` returns only the text result without generating a preview video.

Can the trace.moe Telegram bot work in a group chat?

Yes. In a group you reply to a screenshot and mention the bot. You have to disable Privacy Mode in the bot settings for group use, and adding the bot to a group gives it access to that group's messages, which the README flags.

What Node.js version does the trace.moe Telegram bot need?

The README asks for Node.js 22.18 or newer, but the package manifest declares an engines requirement of Node 24 or newer, so provision against the manifest. The service runs a TypeScript entry point, server.ts, with node and the --dns-result-order=ipv6first flag.

Official sources

  1. Issues
  2. License: MIT
  3. Project website
  4. README
  5. soruly/trace.moe-telegram-bot on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/soruly-trace-moe-telegram-bot.svg)](https://hysenlabs.com/projects/soruly-trace-moe-telegram-bot)

Was this useful?