
Most classified marketplace projects get notifications wrong for the same reason. They build the listing page, the search filters, the payment flow, and then bolt notifications on at the end. Three endpoints, a Firebase call, and a “we’ll improve it later” comment in the codebase.
The problem is that notification delivery is not a feature. It’s infrastructure. And infrastructure decisions made late in a project are the ones you pay for the longest. A buyer who never saw the price-drop alert moved on. A seller who missed a message reply left for a competitor. The listing closed without a transaction. The platform learned nothing.
This post is for developers building classified marketplace platforms who want to think through the notification layer before it becomes a problem. The architecture is not complex, but the decisions matter, and there’s a specific sequence that avoids the most common failure modes. If you’re still deciding what to build or evaluating pre-built options, the considerations in Building a Dubizzle Clone? Focus on This Before Writing a Single Line of Code are worth a read alongside this one.
Why Notifications Are an Infrastructure Problem, Not a Feature Problem
The distinction matters practically. A feature can be added at any point. Infrastructure changes touch everything downstream.
Consider what a classified platform actually fires notifications on: new message from a buyer, listing approved by admin, bid placed on your item, listing about to expire, price dropped on a saved search, suspicious activity flagged. Each of those events lives in a different part of the backend. The messaging service, the admin panel, the bidding engine, the scheduler, the search indexer. If each service fires its own notification directly, you end up with six different delivery paths, zero unified retry logic, and a preference table that nobody trusts.
According to research published in the IJARCST journal, event-driven architectures, where services emit events into a shared bus instead of calling delivery endpoints directly, are the foundation that lets notification systems scale without this kind of fragmentation. The principle is simple: services announce that something happened; the notification layer decides what to do about it.
That separation is the first architectural decision to make. Every service publishes events. One notification service consumes them.
What Notification Events Does a Classified Platform Actually Need?
It helps to map this out before choosing a transport. Not all events have the same urgency, and urgency determines delivery mechanism.
High-urgency events (new message from buyer or seller, bid received, listing flagged) need to reach the user within a few seconds. If you’re on the listing page watching for buyer interest, a 30-second delay is not real-time.
Medium-urgency events (listing approved, listing expiry warning, saved search match) can tolerate a delay of minutes. A user waiting for admin approval is checking periodically, not watching a live indicator.
Low-urgency events (weekly digest, monthly performance summary) are batch jobs, not real-time at all.
Most classified platforms conflate these. They fire WebSocket events for weekly digest summaries (wasteful) and run polling loops for new messages (too slow). Mapping urgency first tells you which transport each event category actually needs.
The Transport Layer Decision: Polling, SSE, or WebSockets?
This is where most teams over-engineer or under-engineer. The choice between the three transports depends on two questions: does the client need to send data back in real-time, and how many concurrent connections does your infrastructure need to hold?
Short Polling
The client asks the server “anything new?” on a fixed interval, typically every 3 to 10 seconds. It works. It’s easy to build. And for a classified platform with fewer than a few thousand concurrent users, it’s often entirely sufficient for medium-urgency events like listing approvals.
The cost is server load. Every connected client fires a request every few seconds regardless of whether anything has changed. At scale, that’s a lot of empty responses. Use it for admin dashboards and internal tooling, not for buyer-seller messaging threads on a busy marketplace.
Server-Sent Events (SSE)
SSE keeps a long-lived HTTP connection open and lets the server push events to the client as they happen. One direction: server to client. That’s the right direction for most notification types on a classified platform.
According to a 2026 developer guide comparing real-time transports, SSE is the correct default for notification feeds and dashboards where the client only needs to listen. It runs over plain HTTP, reconnects automatically on drop, and the browser handles it natively. No library required.
A detailed comparison on Codercops makes the over-engineering point plainly: a developer reaching for WebSockets for a notification feed adds a stateful connection layer, reconnection handling logic, and infrastructure complexity, for something that SSE handles in roughly 20 lines. That’s real development time.
WebSockets
WebSockets open a persistent bidirectional connection. The client and server can both send data at any time, with very low latency.
For classified marketplaces specifically, WebSockets are the right choice when the platform includes live messaging: buyer-seller chat where both parties are typing and reading simultaneously. That is genuinely bidirectional. A notification bell is not.
Analysis from RxDB points out that at scale, WebSocket connections cannot be load-balanced with standard HTTP round-robin — they need sticky sessions or shared state via Redis. Infrastructure to plan for, not discover.
The practical recommendation: use SSE for notification delivery, WebSockets if and only if the platform includes live bidirectional chat. If you already have a WebSocket connection open for chat, piggyback notification events on that connection. Don’t open a second one.
How Do You Handle Notifications When the User Is Offline?
SSE and WebSockets both drop when the device goes offline. That’s expected. The harder question is what happens to events that fired while the user was unreachable.
There are three paths here.
In-app notification inbox. Every event that fires gets written to a notifications table, regardless of delivery status. When the user opens the app, they query their unread count and retrieve the backlog. This is the most reliable pattern because it’s independent of any transport. The transport delivers events in real-time when the connection is live; the database is the fallback when it isn’t.
Mobile push notifications. For users on Android or iOS, push notifications via FCM (Firebase Cloud Messaging) or APNs reach the device even when the app is closed. This is the mechanism that handles the truly offline case. But push has its own edge cases.
According to Business of Apps push notification research, Android users opt in to push at roughly 91 percent, compared to about 43 percent on iOS. Design your fallback strategy around the fact that a meaningful portion of iOS users will never receive push. Email fallback for those users is not optional: it’s the only way to close the loop.
A deep look at push notification architecture failures from Netguru notes that stale device tokens are one of the most common causes of delivery failure. When a user reinstalls the app or changes devices, old tokens become invalid. Without a token rotation and cleanup strategy, push delivery rates quietly decay over weeks.
Still, keep the in-app inbox as the source of truth. Push confirms delivery in real-time; the inbox ensures nothing gets lost.
The Delivery Pipeline: Queue, Retry, and Fallback
The notification service should not call delivery endpoints directly. Put a message queue between the event bus and the delivery layer.
The reason is straightforward. If the push provider’s API is slow or briefly unavailable, a direct call blocks the event handler. A queue absorbs the traffic spike and lets the delivery worker retry on its own schedule. For a classified platform handling listing expiry warnings at 2am, potentially thousands of events fired in a short window — this matters.
A standard pattern: the event service publishes to a queue (Redis, RabbitMQ, or a managed equivalent). The notification worker consumes from the queue, attempts delivery, and writes the result back to the notification table. On failure, the message is requeued with exponential backoff. After a defined number of retries, it falls back to email.
The CleverTap analysis on undelivered Android notifications outlines how Time to Live (TTL) expiry, OEM-specific Android restrictions on devices like Xiaomi and Huawei, and stale token issues cause silently dropped notifications. OEM battery optimisation on certain Android variants is aggressive enough that standard FCM delivery fails without specific handling. Worth testing on those device families before launch, not after.
The Do You Really Need AI in a Classified Website? post touches on a related question about where to invest engineering effort. The notification pipeline is one of those places where the underlying plumbing pays more consistent dividends than the visible feature layer.
A Practical Build Sequence for Marketplace Notification Systems
Build in this order. Each step is independently testable and doesn’t require the next to go to production.
Step 1: Notification table. One table, one row per event, with columns for user ID, event type, payload (JSON), read status, and created timestamp. This is the source of truth for everything else.
Step 2: In-app notification centre. An endpoint that returns unread notifications for the authenticated user. A client-side counter that updates on page load. This works without any real-time transport; polling is fine here.
Step 3: SSE endpoint. One endpoint that keeps a connection open and streams new notification IDs to the client as they’re written to the database. The client uses those IDs to update the unread count immediately. The payload is minimal: just the ID and event type.
Step 4: Push integration. Add FCM and APNs for mobile. Store tokens on registration, rotate on reinstall, clean up expired tokens weekly. Handle the iOS opt-in gap with email fallback.
Step 5: Queue and retry. Move delivery to a background worker. Add retry logic. Add a dead-letter queue for events that exhaust retries and need manual review.
Teams building on a classified ads script that already ships with a notification foundation can often start at Step 3 or 4, since the table structure and basic delivery logic are typically part of the platform. Starting from scratch, Step 1 and 2 should go live before any real-time transport is introduced. A working inbox is more reliable than a working SSE stream with no fallback.
Closing Thoughts
Real-time notifications on a classified platform are not technically difficult. The transport choices are well-understood, the tooling is mature, and the architecture patterns are documented. The difficulty is sequence: teams that try to build push, SSE, and in-app simultaneously end up with three partial implementations that don’t cover each other’s failure modes.
Build the inbox first. Add real-time transport second. Add push third. Each layer is a fallback for the one above it. That sequence is also the easiest to test incrementally, which matters when the platform has real buyers and sellers depending on it.
The edge cases (stale tokens, OEM Android restrictions, iOS opt-in rates below 50 percent) are not obscure. They’re documented, predictable, and solvable. The teams that get caught by them are the ones who found out in production.
And the ones who planned for them? Their platforms just work. Quietly, reliably, without a 2am incident ticket — because someone thought this through before the first line of delivery code was written.
If you’ve dealt with a notification failure on a marketplace build, drop it in the comments. The edge cases are always more interesting than the happy path.