How can you automate brand mention tracking from Reddit and Hacker News?
You can automate brand mention tracking by routing F5Bot alerts from Gmail into Slack using Nexla to transform, filter, and deliver real-time notifications.
Introduction
Brand mention and keyword tracking matters more for devtool companies than for most other businesses. Your buyers live on Reddit, Hacker News, and developer Discord servers, and an offhand “has anyone tried [your tool]?” thread can move signups for a week, if someone from the team shows up in time to answer. Miss it by a day and the conversation has moved on without you.
F5Bot is the easiest way to catch those mentions: it scrapes Reddit and Hacker News for keywords you set and emails you the hits. The catch is the delivery channel. In a busy inbox, F5Bot alerts get buried alongside invoices, calendar invites, and Stripe receipts. By the time you triage your inbox, the Reddit thread already has eighty comments.
This post shows how to route those mentions to Slack with Nexla, where your team already lives. The pipeline pulls new F5Bot emails from Gmail every hour, reformats each one, and posts it to a Slack channel via chat.postMessage. The build took an afternoon, with a few rough edges worth flagging up front.
The Architecture
The pipeline has four nodes in Nexla, connected on an hourly cron:
Gmail Source: uses Nexla’s Gmail “List Threads” template to pull every thread matching from:admin@f5bot.com newer_than:1h
Raw Nexset: auto-detected schema reflecting the Gmail thread payload (messages, payload, headers, base64url body parts).
Transform Nexset: a Python rule that decodes the email body, extracts the keyword, strips F5Bot’s heading and footer, and emits the fields Slack’s chat.postMessage needs.
Slack Destination: Nexla’s Slack connector pointed at chat.postMessage, OAuthed into your workspace.
Slack’s chat.postMessage requires a channel and a text field. Nexla’s Slack template builds the request body from the Nexset record’s attributes by name, so the transform should output a record shaped like a Slack API payload: { channel, text, mrkdwn, …optional bookkeeping }. Once the schema lines up, the destination is one click.
Create the Gmail Source
In Nexla, go to Integrate → Sources → New Source and pick Gmail. Authenticate with OAuth (Nexla redirects to Google and never sees your password), then choose the List Threads API template. Two values matter:
Search query:from:admin@f5bot.com newer_than:1h
Schedule: every hour. Nexla generates a cron expression and shows the next run time in your timezone.
There’s one catch: the List Threads template defaults to format=full so it can pull message bodies in the same request. The connector version I used failed to substitute the format parameter into the URL, and saving the source threw Missing config rest.iterations.gmail_api_v2.list_threads.format. Fix: switch the source config to Advanced mode and delete the ?format=full querystring from the Step 2 URL. Gmail defaults to full when no format is set, so behavior is identical. Save, and the source provisions cleanly.
After saving, Nexla auto-creates a Nexset from the source. That’s the raw schema you’ll transform next.
Add the Python Transform
Click + on the raw Nexset and choose Transform → Transform: Code (Python). The transform:
walks the Gmail payload to find the text/plain part
base64url-decodes it
parses out the F5Bot keyword
strips the heading (“F5Bot found something!”) and the footer (the Famety/advertise/unsubscribe block)
splits the body into Reddit and Hacker News sections
emits a Slack-shaped record
Here’s the full transform:
PYTHON
import base64
import re
def _b64decode(s):
if not s:
return ""
s = s.replace("-", "+").replace("_", "/")
padding = 4 - (len(s) % 4)
if padding != 4:
s += "=" * padding
try:
return base64.b64decode(s).decode("utf-8", errors="replace")
except Exception:
return ""
def _find_plain_text(payload):
if not payload:
return ""
mime = payload.get("mimeType", "")
body = payload.get("body") or {}
data = body.get("data")
if mime == "text/plain" and data:
return _b64decode(data)
for part in payload.get("parts") or []:
text = _find_plain_text(part)
if text:
return text
if data:
return _b64decode(data)
return ""
_FOOTER_PATTERNS = [
r'Do you have comments or suggestions about F5Bot',
r'Want to advertise your company or product on F5Bot',
r'You are receiving this email because you signed up for alerts from F5Bot',
r'Try Famety today',
r'Grow your social presence with real engagement',
r'Trusted by brands and creators worldwide',
r'https?://f5bot\.com/disable-all',
]
_FOOTER_RE = re.compile("|".join(_FOOTER_PATTERNS), re.IGNORECASE)
def _strip_footer(text):
if not text:
return text
m = _FOOTER_RE.search(text)
if not m:
return text
return text[:m.start()].rstrip()
def _format_message(text):
if not text:
return ""
text = text.replace("\r\n", "\n").replace("\r", "\n")
keyword = ""
m = re.search(r'Keyword:\s*"([^"]+)"', text)
if m:
keyword = m.group(1)
body_start = 0
if m:
line_end = text.find("\n", m.end())
if line_end != -1:
body_start = line_end + 1
body = text[body_start:].strip()
body = re.sub(r'^\s*F5Bot found something!\s*\n?', '', body, flags=re.IGNORECASE)
body = _strip_footer(body)
section_re = re.compile(
r'^(Reddit Posts|Reddit Comments|Hacker News Posts|Hacker News Comments|Hacker News)\b[^\n]*',
re.MULTILINE,
)
matches = list(section_re.finditer(body))
sections = []
if matches:
for i, mt in enumerate(matches):
header = mt.group(0).strip()
start = mt.end()
end = matches[i+1].start() if i+1 < len(matches) else len(body)
content = body[start:end].strip()
sections.append((header, content))
else:
sections.append(("", body))
lines = []
if keyword:
lines.append('Keyword: "' + keyword + '"')
lines.append("")
for header, content in sections:
if header:
lines.append("- " + header)
if content:
lines.append(content)
lines.append("")
return "\n".join(lines).strip()
def transform(input, metadata, args):
out = {}
messages = input.get("messages") or []
msg = messages[0] if messages else {}
payload = msg.get("payload") or {}
headers = payload.get("headers") or []
subject = ""
for h in headers:
if (h.get("name") or "").lower() == "subject":
subject = h.get("value") or ""
break
text = _find_plain_text(payload)
snippet = msg.get("snippet") or ""
if not text and snippet:
text = snippet
out["channel"] = "#reddit-hn-notification" # channel name; channel ID (e.g. C0B2DQQC8GH) is more stable
out["text"] = _format_message(text)
out["mrkdwn"] = False
out["thread_id"] = input.get("id") or ""
out["message_id"] = msg.get("id") or ""
out["subject"] = subject
return out
Three notes on the code:
The footer-stripping uses substring patterns rather than a single anchor because F5Bot’s footer varies by recipient (mine had a Famety ad block; others may not). Cutting at the first match is conservative: if F5Bot adds a new sponsor, the pipeline still strips it as long as one known marker remains upstream.
The keyword extraction looks for the literal Keyword: “…” pattern and uses the end of that line as the boundary between F5Bot’s preamble and the results body. That keeps the keyword in the output once, even when the email repeats it later.
mrkdwn: false is intentional. F5Bot’s body contains * and _ in usernames and URLs that Slack would otherwise render as formatting. Plain text holds up better.
Wire the Slack Destination
Click + on the transformed Nexset and choose Send to Destination → Slack. Add a new credential and click Authorize to launch Nexla’s Slack OAuth flow. Pick the workspace and click Allow on Slack’s consent screen. Back in Nexla, save the credential and continue to Configure.
In the Template tab, change the Endpoint dropdown from the default “Add Reaction” to “Sends a message to a channel.” That’s the wrapper for chat.postMessage. Look at the Sample Payload pane on the right. If Step 2’s schema is right, the payload looks like this:
Slack uses channel, text, and mrkdwn; it ignores the rest. The bookkeeping fields (subject, message_id, thread_id) stay in the payload so you can dedupe or pivot to threading later. Name the destination something readable like F5Bot Slack #reddit-hn-notification and click Done.
Activate and Test
Back in the flow editor, every node should show ACTIVE. If you edited a Nexset and Nexla auto-paused it, right-click and choose Activate Flow to resume everything at once. Click RUN NOW on the cron job icon to trigger an immediate ingestion instead of waiting for the next hourly tick. Nexla shows a Starting Source “…” toast and animates dots on the nodes as records move through.
What You End Up With
Once running, Nexla checks Gmail every hour for fresh F5Bot emails. It transforms each into a Slack message that lists the keyword once at the top and groups mentions under headers like Reddit Posts and Hacker News Comments, then posts to your channel via chat.postMessage. The flow shows up as a four-box graph in the Nexla flow editor, with per-node record counts and run histories to drill into when something fails.
The pattern generalizes beyond F5Bot. Any vendor that emails you structured text on a schedule (alerting tools, CI summaries, security digests, marketing analytics) fits the same Gmail → Python transform → Slack pipeline. Only the transform code changes per source, and most cases stay under 100 lines.
The setup takes an afternoon and pays back the first time a mention lands off-hours.
You Don’t Need to Be a Data Engineer to Build This
The pipeline above took an afternoon because I wired it node-by-node in Nexla’s UI. If you’d rather skip the wiring, Express.dev lets you prompt a pipeline like this into existence. Describe what you want in plain English — “every hour, pull F5Bot emails from Gmail, parse the Reddit and Hacker News sections, and post to my #reddit-hn-notification Slack channel” and Express ships the working flow. Same architecture, no boilerplate, and no Python pasted into a Monaco editor.
If you’re a founder, marketer, or DevRel who’s tired of watching brand mentions go cold in your inbox, try Express.dev and have this pipeline running before your next stand-up.
FAQs
What is F5Bot?
F5Bot is a monitoring tool that tracks keywords across Reddit and Hacker News and sends email alerts when new mentions appear.
Why send F5Bot alerts to Slack?
Sending alerts to Slack helps teams respond faster to brand mentions without relying on crowded email inboxes.
How does Nexla automate F5Bot alerts?
Nexla pulls F5Bot emails from Gmail, transforms the content with Python, and sends formatted notifications directly into Slack.
Can this workflow monitor more than brand mentions?
Yes. The same Gmail-to-Slack automation pattern can process security alerts, CI notifications, analytics reports, and scheduled digests.
Do you need coding experience to build this workflow?
No. Nexla provides a visual flow builder, and Express.dev can generate the pipeline from a plain English prompt.
Context Engineering: The Missing Discipline in Enterprise AI
Enterprise AI agents fail when the context behind their decisions is incomplete, stale, or conflicting. Context engineering ensures agents receive accurate, permission-aware runtime context for reliable decisions.
From Hallucinations to Trust: Context Engineering for Enterprise AI
Context engineering is the systematic practice of designing and controlling the information AI models consume at runtime, ensuring outputs are accurate, auditable, and compliant.
Explore how Express.dev makes AI agents capable of generating rich, interactive UI for structured data workflows. From XML-driven forms to real-time validation and OAuth flows, generative UI turns chat into a truly collaborative experience.