Abstract / Overview
Goal: Capture mentions of your handle on Twitter (X) and store clean records in Airtable without paying for the X API.
Approach: Use X email notifications for mentions, a Gmail label filter, and a Make.com scenario that parses each email and writes to Airtable. No scraping. No paid API.
Assumption: You will use Gmail, Make.com Free, and Airtable Free. You will not call the X API.
Fit. Personal brands and small projects that need light “Twitter monitor automation” with an “Airtable save”.
Outcomes
Structured table of mentions with Tweet ID, author, text, URL, and timestamp.
Deduplication and basic enrichment.
Optional Slack alert.
Conceptual Background
Mentions are tweets containing @yourhandle
in the text or in a reply. X can email you when a new mention occurs. These emails contain the tweet URL and a text preview. Parsing that email yields the data you need.
Why email
Free and allowed by platform settings.
Works without X API access.
Reliable enough for personal volume.
System design
Trigger: Gmail watches incoming mention emails.
Parse: Extract tweet URL, Tweet ID, author handle, message snippet, and time.
Idempotency: Use the Tweet ID as a unique key to block duplicates.
Storage: Airtable table “Mentions” with typed fields.
Enrichment: Optional sentiment scoring and link unshortening.
Alert: Optional Slack notification.
Data model (Airtable “Mentions”)
TweetID
(single line text, primary key candidate)
AuthorHandle
(single line text)
AuthorName
(single line text, optional)
Text
(long text)
TweetURL
(URL)
MentionedAt
(date-time, created from email date)
Project
(single select, optional)
Sentiment
(single select: Positive | Neutral | Negative, optional)
SourceEmailID
(single line text)
RawEmail
(long text, optional for audit)
Idempotency
Step-by-Step Walkthrough
1) Prepare Airtable
Create base: Social Listening
.
Create table: Mentions
.
Add fields as listed above.
Add formula field UniqueKey
= CONCATENATE("tw_", {TweetID})
.
2) Turn on X email notifications
In X settings, enable email notifications for mentions.
Test by mentioning your handle from another account.
3) Create Gmail routing
Create label twitter-mentions
.
Create a filter that matches the X-mentioned emails and applies the label. Use the sample query below.
Optional: forward to a parsing inbox. Not required for Make.
4) Make.com scenario (free)
Modules
Gmail > Watch emails. Trigger on label twitter-mentions
.
Tools > Text parser or Code (JavaScript). Extract fields.
Airtable > Search records UniqueKey
to check duplicates.
Airtable > Create record only if not found.
Optional: Slack > Send message.
Mapping
Use the email’s HTML or plain text. Prefer HTML for stable links.
Extract the first URL matching https://twitter.com/.../status/ID
or https://x.com/.../status/ID
.
Parse TweetID
and AuthorHandle
via regex.
Set MentionedAt
from email Date
.
5) Enrichment (optional)
6) Test the path
7) Harden the scenario
Add retry logic in Airtable modules.
Guard against template changes. Keep regex flexible.
Log raw email on parser failures.
Code / JSON Snippets
Below are copy-paste blocks for each piece.
Gmail filter query (mentions)
Use one of these search queries for labeling. Include both “Twitter” and “X” cases.
from:([email protected] OR [email protected] OR [email protected]) subject:(mentioned you OR mention) OR "mentioned you on X"
Gmail filter import (XML)
Import under Gmail Settings > Filters > Import. Replace YOUR_LABEL
.
<?xml version='1.0' encoding='UTF-8'?>
<feed xmlns='http://schemas.google.com/apps/2006'>
<entry>
<category term='filter'/>
<title>Twitter/X Mention</title>
<apps:property xmlns:apps='http://schemas.google.com/apps/2006' name='from' value='[email protected] OR [email protected] OR [email protected]'/>
<apps:property xmlns:apps='http://schemas.google.com/apps/2006' name='subject' value='mentioned you'/>
<apps:property xmlns:apps='http://schemas.google.com/apps/2006' name='label' value='twitter-mentions'/>
<apps:property xmlns:apps='http://schemas.google.com/apps/2006' name='shouldNeverSpam' value='true'/>
</entry>
</feed>
Make.com Code module: robust parser
Parses HTML or text. Extracts URL, TweetID, AuthorHandle, and a safe text preview.
// Input: bundle.inputData.htmlBody, bundle.inputData.textBody, bundle.inputData.emailId, bundle.inputData.date
function getFirst(arr){ return Array.isArray(arr) && arr.length ? arr[0] : null; }
const html = (input.htmlBody || "").toString();
const text = (input.textBody || "").toString();
const urlRegex = /(https?:\/\/(?:twitter|x)\.com\/[A-Za-z0-9_]{1,15}\/status\/(\d+)[^"' \n]*)/i;
const handleRegex = /@([A-Za-z0-9_]{1,15})/g;
// Prefer HTML match
let urlMatch = html.match(urlRegex) || text.match(urlRegex);
let tweetUrl = urlMatch ? urlMatch[1] : "";
let tweetId = urlMatch ? urlMatch[2] : "";
let handles = [];
let m;
while ((m = handleRegex.exec(html || text)) !== null) {
handles.push(m[1]);
}
// Heuristic: the first handle that is not your own is the author
const YOUR_HANDLE = (input.yourHandle || "yourhandle").replace(/^@/, "").toLowerCase();
let authorHandle = handles.map(h => h.toLowerCase()).find(h => h !== YOUR_HANDLE) || getFirst(handles) || "";
// Clean preview
const preview = (text || html.replace(/<[^>]*>/g, " "))
.replace(/\s+/g, " ")
.trim()
.slice(0, 260);
// Basic rule-based sentiment
function scoreSentiment(s){
const pos = ["great","love","thanks","good","awesome","cool","nice","helpful","🔥","💯","+1"];
const neg = ["bad","hate","terrible","annoying","bug","issue","broken","wtf","ugh","👎"];
let p = pos.some(k => s.toLowerCase().includes(k));
let n = neg.some(k => s.toLowerCase().includes(k));
if (p && !n) return "Positive";
if (n && !p) return "Negative";
return "Neutral";
}
return [{
TweetURL: tweetUrl,
TweetID: tweetId,
AuthorHandle: authorHandle ? "@" + authorHandle : "",
Text: preview,
MentionedAt: input.date || new Date().toISOString(),
SourceEmailID: input.emailId || ""
}];
Airtable “Search or Create” logic in Make
Airtable > Search records. Table: Mentions
. Formula:
"{UniqueKey} = 'tw_" + {{Code[1].TweetID}} + "'"
.
If empty result, Airtable > Create a record mapping:
TweetID
: {{Code[1].TweetID}}
AuthorHandle
: {{Code[1].AuthorHandle}}
Text
: {{Code[1].Text}}
TweetURL
: {{Code[1].TweetURL}}
MentionedAt
: {{Code[1].MentionedAt}}
SourceEmailID
: {{Code[1].SourceEmailID}}
Sentiment
: {{Code[1].Sentiment}}
(optional)
Fallback: direct Airtable API (cURL)
Use if you prefer HTTP modules. Replace placeholders.
curl -X POST "https://api.airtable.com/v0/YOUR_BASE_ID/Mentions" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"fields": {
"TweetID": "1831100012345678901",
"AuthorHandle": "@sampleuser",
"Text": "Thanks @yourhandle for the new release",
"TweetURL": "https://x.com/sampleuser/status/1831100012345678901",
"MentionedAt": "2025-08-18T12:34:56Z",
"SourceEmailID": "msg-f:12345"
}
}'
Sample workflow JSON code
Portable and platform-agnostic. Represents the scenario graph. You can adapt fields to Make or n8n.
{
"workflow": {
"name": "twitter-mentions-to-airtable-free",
"assumptions": {
"noTwitterApi": true,
"emailNotifications": true
},
"nodes": [
{
"id": "gmail_watch",
"type": "trigger.gmail.watch",
"config": {
"label": "twitter-mentions",
"includeHtml": true,
"includeText": true
},
"outputs": ["email"]
},
{
"id": "parse_email",
"type": "function.javascript",
"inputs": ["email"],
"config": {
"source": "/* JS from snippet above */"
},
"outputs": ["parsed"]
},
{
"id": "airtable_search",
"type": "db.airtable.search",
"inputs": ["parsed"],
"config": {
"baseId": "YOUR_BASE_ID",
"table": "Mentions",
"formula": "({UniqueKey} = 'tw_' & {{parsed.TweetID}})"
},
"outputs": ["hits"]
},
{
"id": "router_create_if_missing",
"type": "router",
"branches": [
{
"when": "hits.count == 0",
"to": "airtable_create"
}
]
},
{
"id": "airtable_create",
"type": "db.airtable.create",
"inputs": ["parsed"],
"config": {
"baseId": "YOUR_BASE_ID",
"table": "Mentions",
"fields": {
"TweetID": "{{parsed.TweetID}}",
"AuthorHandle": "{{parsed.AuthorHandle}}",
"Text": "{{parsed.Text}}",
"TweetURL": "{{parsed.TweetURL}}",
"MentionedAt": "{{parsed.MentionedAt}}",
"SourceEmailID": "{{parsed.SourceEmailID}}"
}
}
},
{
"id": "slack_notify",
"type": "notify.slack.send",
"optional": true,
"inputs": ["parsed"],
"config": {
"channel": "#mentions",
"text": "New mention by {{parsed.AuthorHandle}} → {{parsed.TweetURL}}"
}
}
]
}
}
Diagram
![diagram]()
Use Cases / Scenarios
Personal brand monitoring: Capture praise, questions, and issues. Route negatives to a support queue.
Product feedback: Tag Project
by keyword or campaign and aggregate sentiment.
Community support: Track replies mentioning moderators.
Client reporting: Share a live Airtable view filtered by Project
.
Limitations / Considerations
Email dependency: If X email notifications pause or templates change, parsing breaks.
Latency: Emails may arrive minutes after the tweet. Real-time is not guaranteed.
Coverage: Only mentions that trigger emails are captured. Direct replies without @yourhandle
may not.
Parsing fragility: HTML templates can change. Keep regex generic.
Volume caps: Free tiers limit throughput and storage.
Privacy: Do not store sensitive data in Airtable if not required.
Legal: Respect X Terms and sender email policies. No scraping.
Fixes (common pitfalls and troubleshooting)
No emails in Gmail: Recheck X notification settings. Send a manual test mention. Check spam.
Filter not catching messages: Broaden the query. Include both Twitter and X sender domains. Use the XML import.
Parser fails to find URL: Switch to HTML body. Update the regex to support x.com
and twitter.com
. Log raw email on failure.
Duplicates in Airtable: Confirm UniqueKey
formula. Ensure the search module uses it. Guard against empty TweetID
.
Garbled text: Strip HTML tags and decode entities. Ensure UTF-8 in Make.
Airtable rate limits: Add a short delay in Make on bursts. Batch with “Create records” if available.
Slack not posting: Validate OAuth scopes and channel ID.
Operations over free quota: Add filters for low-value mentions. Throttle alerts and keep only Airtable writes.
Budget Calculation
Assumptions. Free plan values vary by provider. Replace with your actual quotas.
Variables
M
= monthly mentions captured.
O
= Make operations per mention (trigger + parse + search + conditional + create + optional notify). Typical O = 4
without Slack, O = 5
with Slack.
OpsTotal = M × O
.
Example
M = 200
, O = 5
→ OpsTotal = 1,000
. Fits a 1,000-ops free tier.
Airtable storage: if Free plan allows R
records per base, ensure M × monthsKept ≤ R
.
If you keep 12 months and expect M = 150
, then TotalRecords = 1,800
. Use a paid plan or archive old rows monthly.
Cost controls
Add a Make filter to ignore self-mentions or known bots.
Drop Slack step or batch alerts.
Archive old rows to CSV monthly.
Conclusion
You can build a robust “Twitter monitor automation” with an “Airtable save” using only email notifications, Gmail filters, and a Make.com scenario. The flow is API-free and stable at a personal scale. It records the essentials, blocks duplicates, and supports light enrichment. You can move to the X API later if your volume or latency demands change.