What

A fully automated attendance tracking system where team members simply send “IN” or “OUT” messages to a Telegram group. An n8n workflow processes these messages, validates states, logs data to Google Sheets, and replies with confirmations—all without any manual intervention.

Components:

  • Telegram bot for message interface
  • n8n workflow for automation logic
  • Google Sheets for data storage and calculations
  • OpenAI GPT-4o-mini (optional) for intelligent message filtering

Real scenario: Your team works remotely or in office. Each person sends “IN” when they start work, “OUT” when they finish. The system automatically tracks hours, prevents errors (like double check-ins), and maintains a permanent record in Google Sheets.

Why

The Problem

Manual attendance tracking is tedious:

  • Excel sheets need constant updating
  • Easy to forget or make mistakes
  • No validation (people can mark IN twice)
  • Calculating hours is manual work
  • Hard to track across multiple team members

This Solution

  • Zero friction: Send a 2-letter message. That’s it.
  • Smart validation: Can’t check in twice, can’t check out without checking in first
  • Auto-calculation: Hours spent calculated automatically
  • AI-powered: Ignores regular chat, catches typos like “ot” instead of “OUT”
  • Historical data: Everything logged in Google Sheets with timestamps
  • Multi-org ready: Optional organization mapping for companies with multiple teams

Why These Tools?

  • Telegram: Everyone already uses it. No new app to install.
  • n8n: Free, self-hosted workflow automation. No vendor lock-in.
  • Google Sheets: Free, familiar, easy to export for payroll/reports.
  • OpenAI: Cheap (~$0.0001 per message) and accurate message classification.

How

Step 1 — Create Telegram Bot

Go to Telegram and find @BotFather:

/newbot

Follow prompts:

  • Bot name: Attendance Tracker
  • Bot username: your_company_attendance_bot

BotFather returns:

Done! Your bot token is: 123456789:ABCdefGHIjklMNOpqrsTUVwxyz

Save this token — you’ll need it for n8n credentials.

Add bot to your group:

  1. Create a Telegram group or use existing
  2. Add the bot as member
  3. Make it admin (optional but recommended)

Step 2 — Get Group Chat ID

You need the group’s chat ID for workflow configuration.

Method 1 — Using @RawDataBot:

  1. Add @RawDataBot to your group
  2. Forward any message from your group to this bot
  3. It shows the chat ID: -1002502742130 (negative number for groups)

Method 2 — Via API:

curl https://api.telegram.org/bot<YourBotToken>/getUpdates

Look for "chat":{"id":-1234567890} in the JSON response.

Step 3 — Set Up Google Sheets

Create a new Google Sheet with two sheets:

Sheet 1: “rawdata”

This stores raw attendance logs.

Headers (Row 1):

userId | name | inTime | OutTime

Example data:

7650552265 | John Doe    | 1743132592 | 1743168676
1110309276 | Jane Smith  | 1743134245 |
  • userId: Telegram user ID (auto-filled by workflow)
  • name: User’s first name from Telegram (auto-filled)
  • inTime: Unix timestamp when user sent “IN”
  • OutTime: Unix timestamp when user sent “OUT” (empty until checkout)

Sheet 2: “parsed”

This automatically processes raw data into human-readable format.

Headers (Row 1):

userId | name | inTime | OutTime | row | currentStatus | isLatestForUser | inTimeUTC | outTimeUTC | hoursSpent | inDate | inMonth | inYear | inHour | InMinute | outDate | outMonth | outYear | outHour | outMinute | trueInDateTime | trueOutDateTime

Formulas (Row 2, then copy down):

A2: =rawdata!A2
B2: =rawdata!B2
C2: =rawdata!C2
D2: =rawdata!D2
E2: =ROW()-1
F2: =IF(D2="","IN","OUT")
G2: =IF(COUNTIFS($A$2:$A,A2,$C$2:$C,">"&C2)=0,"LATEST","")
H2: =IF(C2="","",TEXT(C2/86400 + DATE(1970,1,1) + TIME(5,30,0), "yyyy-mm-dd hh:mm:ss"))
I2: =IF(D2="","",TEXT(D2/86400 + DATE(1970,1,1) + TIME(5,30,0), "yyyy-mm-dd hh:mm:ss"))
J2: =IF(D2="","",TEXT((D2-C2)/86400,"h""h"" m""m"""))
K2: =IF(C2="","",DAY(C2/86400 + DATE(1970,1,1) + TIME(5,30,0)))
L2: =IF(C2="","",MONTH(C2/86400 + DATE(1970,1,1) + TIME(5,30,0)))
M2: =IF(C2="","",YEAR(C2/86400 + DATE(1970,1,1) + TIME(5,30,0)))
N2: =IF(C2="","",HOUR(C2/86400 + DATE(1970,1,1) + TIME(5,30,0)))
O2: =IF(C2="","",MINUTE(C2/86400 + DATE(1970,1,1) + TIME(5,30,0)))

Continue similar patterns for outDate through trueOutDateTime columns.

Timezone adjustment: Change TIME(5,30,0) to your offset:

  • IST (India): TIME(5,30,0)
  • EST: TIME(-5,0,0)
  • PST: TIME(-8,0,0)
  • UTC: TIME(0,0,0)

Key columns explained:

  • currentStatus: “IN” if OutTime is empty, “OUT” if filled
  • isLatestForUser: “LATEST” for each user’s most recent record (used by workflow)
  • hoursSpent: Auto-calculated time difference (e.g., “9h 33m”)

Sample sheet: View live example

Copy the spreadsheet ID from URL:

https://docs.google.com/spreadsheets/d/1RsUStkD-LC6179-IK0CnjjC4fA19N-sSOGij4R7Tit8/edit
                                      ↑________________ID________________↑

Step 4 — Get OpenAI API Key (Optional)

Why: AI distinguishes between attendance commands and regular chat.

Without AI:

  • “in” → ✓ Check in
  • “Good morning” → ✗ Ignored (no exact match)
  • “ot” (typo for “OUT”) → ✗ Ignored

With AI:

  • “in” → ✓ Check in
  • “Good morning” → ✗ Ignored (AI recognizes it’s chat)
  • “ot” → ✓ AI suggests: “Please send ‘IN’ or ‘OUT’”

Get API key:

  1. Go to OpenAI Platform
  2. Sign up / log in
  3. Navigate to API keys
  4. Create new secret key
  5. Copy and save it

Cost: GPT-4o-mini costs ~$0.15 per 1M input tokens. For attendance messages, that’s roughly $0.0001 per message (one-hundredth of a cent).

Skip AI?: Remove these nodes from the workflow:

  • “If message not empty”
  • “decide if attendance mistake message”
  • “If attendance mistake message”

Connect “if OUT” false branch directly to “suggest user” node.

Step 5 — Import n8n Workflow

Download the workflow JSON: attendance_template.json

In n8n:

  1. Click WorkflowsAdd workflowImport from File
  2. Upload attendance_template.json
  3. Workflow opens in editor

Step 6 — Configure n8n Credentials

Add Telegram credential:

  1. Click any Telegram node
  2. Credential for Telegram → Create New
  3. Access Token: Paste bot token from BotFather
  4. Test → Save

Add Google Sheets credential:

  1. Click any Google Sheets node
  2. Credential for Google Sheets → Create New
  3. Sign in with Google → Allow access
  4. Save

Add OpenAI credential (if using AI):

  1. Click “decide if attendance mistake message” node
  2. Credential for OpenAI → Create New
  3. API Key: Paste OpenAI key
  4. Save

Step 7 — Update Configuration Values

⚠️ Critical: Replace dummy values

A. Group IDs

Node: “allow only specific group”

Find and replace:

-1001234567890  →  Your actual group ID
-1009876543210  →  Delete or add second group ID

Click the node → Edit conditions → Update the rightValue fields.

B. Spreadsheet ID

Nodes to update (7 total):

  • get latest data for user for in
  • get latest data for user for OUT
  • insert IN
  • insert IN1
  • insert IN2
  • update OUT
  • get data with hours spent

In each node:

  1. Click node → Document dropdown
  2. Delete current value
  3. Type to search → Select your spreadsheet
  4. Sheet Name → Select “rawdata” or “parsed” as needed

Or manually replace:

REPLACE_WITH_YOUR_SPREADSHEET_ID  →  Your actual ID

Sheet mapping:

  • Nodes with “insert” or “update OUT” → Use rawdata (gid=0)
  • Nodes with “get latest” or “get data with hours” → Use parsed (gid=1)

Step 8 — Activate Workflow

  1. Save the workflow (Ctrl+S or click Save)
  2. Toggle Active switch in top-right (should turn green)
  3. Execute workflow once manually to verify credentials

Step 9 — Test

In your Telegram group:

Send: IN

Expected:

Your check-in has been recorded, [YourName]

Send: OUT

Expected:

Your check-out has been recorded, [YourName]. You spent 0h 1m.

Check Google Sheets:

  • rawdata should have a new row with your userId, name, inTime, OutTime
  • parsed should show the same data with calculated fields

Test error cases:

Send: IN (while already checked in)

You are already marked as IN. Please check out before checking in again, [YourName].

Send: OUT (without checking in first)

You need to check in before you can check out, [YourName].

Send: Good morning team (with AI enabled)

(No response - AI recognizes it's not attendance)

Send: ot (with AI enabled)

Please send either "IN" or "OUT" to record your attendance, [YourName].

Workflow Logic Explained

Message Flow

Telegram Message
    ↓
Extract fields (userId, name, chatId, message, timestamp)
    ↓
Filter by allowed groups (reject if wrong group)
    ↓
Sanitize message (remove punctuation, uppercase, trim)
    ↓
┌─────────────┴──────────────┐
│                            │
Message = "IN"          Message = "OUT"
│                            │
Get user's latest status     Get user's latest status
from parsed sheet            from parsed sheet
│                            │
Check: not already IN?       Check: currently IN?
│                            │
✓ Insert to rawdata          ✓ Update OutTime in rawdata
│                            │
✓ Reply: "Checked in"        Wait 1 second (formulas calculate)
                             │
                             ✓ Read hoursSpent from parsed
                             │
                             ✓ Reply: "Checked out, spent Xh Ym"

State Validation

The workflow uses the isLatestForUser flag in the parsed sheet to track each user’s current state.

Example data:

userId     | currentStatus | isLatestForUser
-----------|---------------|----------------
123456     | OUT          | LATEST         ← User's most recent record
123456     | IN           |                ← Previous record (ignored)
789012     | IN           | LATEST         ← Another user's latest

When user sends “IN”:

  1. Query parsed sheet for rows where userId = <user> AND isLatestForUser = "LATEST"
  2. If no rows found → First time check-in → Allow
  3. If row found with currentStatus = "OUT" → Last action was checkout → Allow
  4. If row found with currentStatus = "IN" → Already checked in → Reject with error

When user sends “OUT”:

  1. Query parsed sheet for latest record
  2. If no rows found → Never checked in → Reject
  3. If currentStatus = "OUT" → Already checked out → Reject
  4. If currentStatus = "IN" → Valid checkout → Update rawdata

10-Hour Safety Window

Problem: User checks in Monday 9 AM, forgets to check out, tries to check in Tuesday 8 AM.

Without safety: Error: “Already marked as IN”

With safety (10-hour rule):

hoursSinceCheckIn = (now - lastInTime) / 3600
if (hoursSinceCheckIn > 10) {
    // Allow new check-in (day rollover assumed)
} else {
    // Reject (probable mistake)
}

Customize: Edit “If before 10 hours” node → Change 10 to your preferred value.

AI Message Classification

AI node prompt:

You are a Telegram chatbot assistant that manages attendance.

Users send messages like "in" or "out" to mark attendance.
Sometimes they make mistakes like "ot", "OUT @9", or "in noww"
  → These are *mistaken attempts* at attendance.

Other times users send *real messages* like greetings or comments
  → These should be IGNORED by the attendance bot.

Classify each message as:
- "attendance_mistake" — typo/variation of IN/OUT
- "real_message" — general conversation

Respond in JSON with type, confidence (0-1), and reason.

Examples:

  • “in” → Not sent to AI (already exact match)
  • “ot” → AI: {"type": "attendance_mistake", "confidence": 0.9}
  • “Good morning team” → AI: {"type": "real_message", "confidence": 0.95}
  • “out at 5” → AI: {"type": "attendance_mistake", "confidence": 0.85}

The workflow only responds to attendance_mistake classification.

Advanced Features

Multi-Organization Support

Use case: Track attendance for multiple companies/teams in one sheet.

Add third sheet “orgMapping”:

Unique Ids | Name      | Org
-----------|-----------|----------
123456     | John Doe  | CompanyA
789012     | Jane      | CompanyB

Benefits:

  • Segregate reports by organization
  • Single workflow for multiple teams
  • Easy filtering in Google Sheets

Usage:

=VLOOKUP(A2, orgMapping!A:C, 3, FALSE)

Add this to parsed sheet to auto-populate organization.

Custom Messages

Edit Telegram reply nodes to customize responses:

Check-in message (node: “reply to IN”):

✅ Welcome back, {{ $json.name }}! Your attendance has been marked.

Check-out message (node: “reply to OUT”):

👋 See you tomorrow, {{ $json.name }}! You worked {{ $json.hoursSpent }} today.

Error messages: Edit nodes like “suggest mark OUT before IN again”

Additional Commands

Add “BREAK” command:

  1. Duplicate “if IN” node
  2. Change condition: message = "BREAK"
  3. Insert special marker to rawdata (e.g., inTime = 0)
  4. Add filter in parsed sheet to exclude breaks from hours calculation

Add “STATUS” command:

  1. Add new IF node: message = "STATUS"
  2. Query parsed sheet for latest record
  3. Reply with current status:
You are currently marked as {{ $json.currentStatus }}.
Last check-in: {{ $json.inTimeUTC }}

Export Automation

Daily summary via email:

  1. Add Schedule Trigger node (every day at 6 PM)
  2. Add Google Sheets node → Read parsed sheet (today’s date only)
  3. Add Send Email node → Attach CSV
  4. Send to manager/HR

Slack integration:

  1. Add Slack node after check-in/out
  2. Post to #attendance channel:
John Doe checked in at 9:30 AM

Troubleshooting

Bot Doesn’t Respond

Check:

  • Workflow is Active (green toggle)
  • Telegram credentials valid (test connection)
  • Bot added to group (check Telegram group members)
  • Group ID configured correctly (verify it’s negative number)

Debug:

  1. n8n → Executions tab
  2. Find recent execution
  3. Check error messages

Google Sheets Not Updating

Symptoms: No new rows in rawdata after sending messages

Solutions:

  • Verify Google Sheets credential has write permission (not just read)
  • Check spreadsheet ID is correct (compare URL)
  • Ensure sheet names are exactly “rawdata” and “parsed” (case-sensitive)
  • Test manually: Click “insert IN” node → Execute node

Permission error:

Error: Insufficient Permission

Fix: Re-create Google Sheets credential → Allow all requested permissions

Wrong Timezone

Symptoms: inTimeUTC shows 5:30 hours off

Cause: Incorrect TIME() offset in formulas

Fix:

  1. Open Google Sheets → “parsed” sheet
  2. Find formula with TIME(5,30,0)
  3. Change to your offset (see Step 3)
  4. Copy formula down all rows

Verify: Check if inTimeUTC matches your local time when you sent message

AI Responds Incorrectly

Issue: Regular chat triggers attendance response

Solution 1 — Adjust AI prompt:

  1. Edit “decide if attendance mistake message” node
  2. Add examples to system prompt:
More examples:
- "Anyone going to lunch?" → real_message
- "I'm out" → attendance_mistake (context matters)

Solution 2 — Increase confidence threshold:

  1. Edit “If attendance mistake message” node
  2. Add condition: confidence > 0.8

Solution 3 — Disable AI:

  • Remove AI nodes entirely
  • Only exact “IN”/“OUT” matches trigger attendance

Duplicate Entries

Symptoms: Same check-in recorded multiple times

Cause: Race condition (user clicked multiple times fast)

Prevention: Add Merge node with “Wait for first message” mode

Cleanup:

  1. Open rawdata sheet
  2. Sort by userId, then inTime
  3. Manually delete duplicates
  4. parsed sheet auto-updates

Costs

Monthly Estimate (10 users, 22 working days)

Google Sheets: Free

  • Storage: Unlimited (within Google Drive quota)
  • API calls: Free (100 requests/100 seconds limit)

OpenAI GPT-4o-mini: ~$0.50/month

  • 10 users × 22 days × 2 messages (IN/OUT) = 440 messages
  • 440 × $0.0001 = $0.044/month
  • Add ~10x for mistakes/chat = $0.50/month

n8n: Free (self-hosted)

  • Cloud version: $20/month for starter plan
  • Self-hosted: $0 (just server costs)

Telegram: Free

Total: $0 (self-hosted n8n) or ~$20.50 (n8n cloud)

Cost Optimization

Reduce OpenAI costs:

  • Disable AI for small teams (just use exact matching)
  • Cache recent messages (avoid re-analyzing)
  • Use shorter prompts (fewer input tokens)

Google Sheets alternative:

  • Use Airtable (free tier: 1,200 records/base)
  • Use Supabase (PostgreSQL, free tier: 500MB)
  • Self-host PostgreSQL

Security Considerations

Keep Private

Telegram bot token: Never commit to git, share publicly, or expose in client-side code.

Google Sheets credential: Store securely. Anyone with this can access all sheets in your account.

OpenAI API key: Set spending limits in OpenAI dashboard ($5/month max).

Group Access Control

Problem: Anyone in Telegram group can mark attendance for themselves.

Solution: This is by design (trust-based system).

Alternative: Add authentication:

  1. Maintain whitelist of allowed userIds in Google Sheet
  2. Add filter node: userId in whitelist
  3. Reject messages from unknown users

Data Privacy

What’s logged:

  • Telegram userId (visible to group admins anyway)
  • First name (public in Telegram)
  • Timestamps

Not logged:

  • Telegram username
  • Phone number
  • Message history (only current message processed)

GDPR compliance: Add data export/deletion workflow if needed.

Improvements

Better UI

Telegram Bot Commands:

/status — Show current status (IN/OUT)
/today — Show today's hours
/week — Show this week's total
/help — Show usage instructions

Implement using additional IF nodes in workflow.

Analytics Dashboard

Google Data Studio:

  1. Connect to Google Sheets
  2. Create dashboard:
    • Total hours per user (this month)
    • Average check-in time
    • Late arrivals (after 10 AM)
    • Overtime (>8 hours/day)

Chart types:

  • Bar chart: Hours by user
  • Line chart: Check-in time trend
  • Pie chart: Department-wise hours

Notifications

Late check-in alert:

// Add to workflow after check-in
if (hour > 10) {  // After 10 AM
    sendSlackMessage("#alerts", "Late check-in: ${name} at ${hour}:${minute}")
}

End of day reminder:

Schedule Trigger (every day at 7 PM)
  ↓
Query users with currentStatus = "IN"
  ↓
Send Telegram message: "Don't forget to check out!"

Mobile App

Progressive Web App (PWA):

  • Create simple HTML form
  • Submit via Telegram Bot API
  • Install as home screen app on mobile
  • No need to open Telegram group

Advantages:

  • Cleaner UX than Telegram
  • Can add features (geolocation, camera)
  • Still uses same n8n backend

Notes

  • Reliability: n8n has built-in retry logic. If Google Sheets API fails, workflow retries up to 5 times.
  • Scalability: Tested with 50 users. Google Sheets handles 5M cells per sheet.
  • Backup: Google Sheets auto-saves. Export CSV weekly for local backup.
  • Offline: Users can send messages offline. Telegram queues them, workflow processes when online.

Summary

You’ve built a production-ready attendance system:

  1. ✓ Telegram bot for user interface
  2. ✓ n8n workflow for automation logic
  3. ✓ Google Sheets for data storage
  4. ✓ AI-powered message filtering (optional)
  5. ✓ Smart validation (no double check-ins)
  6. ✓ Auto-calculated hours
  7. ✓ Error handling and retries
  8. ✓ Multi-user support

Use it for:

  • Office attendance tracking
  • Remote team time logging
  • Freelancer hour tracking
  • Event check-in/check-out
  • Any simple IN/OUT tracking need

Next steps:

  • Add your team members to the group
  • Monitor for a week, adjust messages as needed
  • Add analytics dashboard for insights
  • Extend with custom commands based on feedback

n8n template: View on n8n.io (share publicly after setup)