View-Once Message Detection
Problem
WhatsApp “view once” photos and videos can only be opened on the phone. The CRM has no way to know one was received — the user might miss it entirely.
Solution
Detect msg._data.isViewOnce on incoming messages and surface a visible alert in the conversation.
Backend — WhatsAppService
In handleMessage():
- Checks
msg._data.isViewOncebefore any media download attempt - If true: logs
[View-once photo — check your phone]to the contact’s transcript file - Sets
hasMedia: falsein the serialized message (no broken media placeholder) - Sets
isViewOnce: truein the serialized message - Returns early — skips
downloadMedia()entirely - Still emits the WebSocket event so the frontend updates in real-time
In serializeMessage():
- Reads
msg._data.isViewOnceand includes it in the serialized object
In archiveMessage():
- Stores
is_view_onceboolean in the messages table
Database
New column on the messages table:
ALTER TABLE messages ADD COLUMN IF NOT EXISTS is_view_once BOOLEAN DEFAULT FALSE;
Frontend — MessageBubble
When message.isViewOnce is true, an orange banner renders above the message body:
EyeOfficon from lucide-react- Text: “View-once — check your phone”
- Styled with
bg-orange-500/10background andborder-orange-500/20border
Key Gotcha
The isViewOnce property lives on msg._data.isViewOnce, NOT as a top-level whatsapp-web.js Message property. The library uses it for sending view-once messages (as a sendMessage option), but for received messages it’s only on the raw data object.
Files Modified
| File | Changes |
|---|---|
backend/src/services/WhatsAppService.ts |
View-once detection in handleMessage(), isViewOnce in serializeMessage(), is_view_once in archiveMessage() |
backend/src/controllers/messageController.ts |
isViewOnce field in message row mapper |
frontend/src/types/index.ts |
isViewOnce on Message interface |
frontend/src/components/MessageBubble.tsx |
EyeOff import, view-once orange banner |