Founder & Lead Engineer, RAITHub
Listing moderation on a property portal is a pipeline: automated checks catch duplicates, impossible prices, reused photos, missing fields and invalid permit numbers, then a human review queue handles what the checks flag, within an agreed response time. We model it as 11 states, from draft to archived, so every listing has exactly one status, an owner and an audit trail, and every rejection can be appealed.
If you would rather have it built for you, see how RAITHub would build this below.
Why do property portals need listing moderation?
Because a portal's product is trust. A buyer or renter who calls about a flat that was let three months ago, or priced at half the market to collect phone numbers, stops believing the other listings too. Agents who play fair lose leads to the ones who do not.
The problems repeat across markets:
- Duplicates. The same unit listed by three agents, or by one agent three times to fill the first page of results.
- Bait listings. A property that is not available, or a price set far below market, posted to collect inquiries for something else.
- Stale listings. Units already sold or let that nobody took down.
- Bad data. Missing size, wrong bedroom count, a pin in the sea, rent entered as a sale price.
- Images. Stock photos, photos of a different property, watermarks from another portal, contact details burned into the image to bypass lead tracking.
- Regulatory gaps. In some markets an advert needs a permit or a licensed broker, and the portal is expected to show it.
What checks should run automatically on every listing?
Run cheap, deterministic checks first, and save human attention for what they flag. Each check returns pass, fail (with a reason the agent can fix) or flag (send to a reviewer).
| Check | How it works | Typical outcome on failure |
|---|---|---|
| Required fields | Schema validation per property type: price, size, bedrooms, location, tenure or rental period, permit number where required | Fail: the agent fixes and resubmits |
| Location sanity | Geocode the address and compare it with the pin and the chosen area | Fail if the pin is outside the area; flag if close |
| Duplicate detection | Fingerprint of normalised address, unit, type, bedrooms and size band, plus perceptual hashes of photos | Flag: a reviewer merges, keeps one, or allows co-listing |
| Price sanity | Price per square metre or foot compared with recent listings of the same type in the same area | Flag outside a band, for example below half or above double the area median, tuned on your own data |
| Image checks | Minimum count and resolution, near-duplicate detection across other listings, unsafe-content detection, text or phone numbers in images | Fail for count and resolution; flag for reuse or contact details |
| Agent verification | Agent account linked to a verified agency, and a broker registration where the market has one | Block publishing until verified |
| Permit number | Format check, uniqueness, and a match against the permit record where the regulator offers a lookup | Fail if missing or malformed; flag if unverified |
| Freshness | Listings expire unless the agent confirms availability every N days | Move to expired; one click to renew |
For unsafe-content detection you do not need to train a model. Managed APIs exist; Amazon Rekognition's pricing page, for example, lists image moderation at $0.0010 per image for the first 1 million images a month in US East. Duplicate-photo detection is different: it compares a listing's photos with every other listing on your portal, so it is a hash index you own, not a third-party call.
How do you verify agents and permit numbers, such as Dubai's Trakheesi?
Verify the agency once, the agent once, and the permit on every listing. The first two are onboarding; the third is per advert and changes with each property.
Dubai is a clear example. The Dubai Land Department's Real Estate Advertisement Permit service, issued through Trakheesi, covers 14 advert types including electronic advertisements. For most types it lists a fee of AED 1,000 plus a AED 20 Knowledge and Innovation fee, a service time of 1 working day, and, for brokers, a copy of the marketing contract with the property owner. A portal serving Dubai therefore needs a permit field on each listing, checks on its format and reuse, and a clear place to show it.
How the permit must be displayed, and whether your portal must verify it against DLD's records or only collect it, is a regulatory question with an answer that can change. Regulator data access in the UAE runs through the DLD API Gateway, which a licensed UAE entity subscribes to. This is general information; confirm the current rules with your adviser before launch. Other markets have their own rules: in the UK, for example, National Trading Standards' Part A guidance sets out material information such as price and council tax band that listings should include. The wider UAE picture is in building a UAE real estate platform with Ejari and DLD.
Make the rule per market, not global. Store which fields are required, which format a permit number follows, and whether verification is a lookup or a manual check, as configuration for each country or emirate. The same portal can then launch a second market without rewriting moderation.
What does a listing moderation state machine look like?
Eleven states cover the whole life of a listing. The point of a state machine is that only the listed moves are legal, so a rejected listing cannot quietly become published because someone edited a field. This is our recommended design for a portal, written as engineering guidance.
| State | Meaning | Can move to |
|---|---|---|
| draft | The agent is still editing | submitted, archived |
| submitted | Queued for checks | auto_checks |
| auto_checks | Automated checks running | published, in_review, rejected |
| in_review | A reviewer must decide | published, changes_requested, rejected |
| changes_requested | Returned to the agent with reasons | submitted, archived |
| published | Live in search | submitted (material edit), suspended, expired, archived |
| rejected | Refused, with a reason code | appealed, archived |
| appealed | The agent disputes a rejection | published, rejected |
| suspended | Taken down after a report or audit | in_review, archived |
| expired | Availability not confirmed in time | submitted, archived |
| archived | Closed for good: sold, let or withdrawn | none |
type ListingState =
| 'draft' | 'submitted' | 'auto_checks' | 'in_review' | 'changes_requested'
| 'published' | 'rejected' | 'appealed' | 'suspended' | 'expired' | 'archived'
const transitions: Record<ListingState, ListingState[]> = {
draft: ['submitted', 'archived'],
submitted: ['auto_checks'],
auto_checks: ['published', 'in_review', 'rejected'],
in_review: ['published', 'changes_requested', 'rejected'],
changes_requested: ['submitted', 'archived'],
published: ['submitted', 'suspended', 'expired', 'archived'],
rejected: ['appealed', 'archived'],
appealed: ['published', 'rejected'],
suspended: ['in_review', 'archived'],
expired: ['submitted', 'archived'],
archived: [],
}
const needsReason: ListingState[] = ['changes_requested', 'rejected', 'suspended']
interface Move {
from: ListingState
to: ListingState
actorId: string
reasonCode: string | null
originalReviewerId?: string // set when deciding an appeal
}
export function assertMove(m: Move): void {
if (!transitions[m.from].includes(m.to)) {
throw new Error('Illegal move: ' + m.from + ' -> ' + m.to)
}
if (needsReason.includes(m.to) && !m.reasonCode) {
throw new Error('A reason code is required for ' + m.to)
}
if (m.from === 'appealed' && m.actorId === m.originalReviewerId) {
throw new Error('An appeal must be decided by a different reviewer')
}
}
Call the guard inside the same database transaction that updates the listing and writes an audit row: who moved it, from which state, to which, and why. The audit pattern is in SaaS audit log design. Two rules are easy to miss. A material edit to a published listing (price, photos, permit number) sends it back to submitted, so a clean listing cannot be swapped for a bait one after approval. And the move from auto_checks straight to published should be allowed only when every check passes and the agency has a clean record; everything else goes to a person.
How should review queues and SLAs work?
An SLA (service-level agreement) here is the time you promise agents between submission and decision. Agents care about it because an unpublished listing earns no leads; buyers care because a slow queue tempts staff to approve without looking.
| Queue | What lands in it | Example target |
|---|---|---|
| New agency or agent | First listings from an unverified or new account | Same business day |
| Flagged listing | Duplicate, price, image or permit flags | Within a few business hours |
| User reports | Reports of unavailable, fake or wrong listings | Within one business day, faster for repeat reports |
| Appeals | Agents disputing a rejection or suspension | Within two business days, by a different reviewer |
The targets are illustrations; set yours from your volume and staffing. Order each queue by deadline, not by arrival, and show reviewers the time left. Record the decision time on every item so you can report the SLA you actually hit, per queue and per reviewer. Reject with reason codes from a fixed list ("permit number does not match the property", "photos belong to another listing") rather than free text, so agents know exactly what to fix and you can see which problems are growing.
How should appeals work?
An appeal is a request for a second decision, by someone other than the first reviewer, with the agent's explanation and any new evidence attached. Allow one appeal per rejection, keep the original reason visible, and close the loop with a reason code either way. Agencies on a multi-tenant portal should see the history for their own listings only; tenant isolation is covered in the multi-tenant SaaS guide.
Should you buy, build or hire a listing moderation system?
| Option | Example and cited price | Choose this when | Watch out for |
|---|---|---|---|
| Off-the-shelf component | Amazon Rekognition image moderation from $0.0010 per image | You already have a portal and need one check, such as unsafe images, without building a model | It is one check, not a workflow; duplicates, prices and permits are still yours |
| Marketplace template or no-code | Sharetribe Build at $39 a month, Live at $199 a month billed yearly | You are testing demand with a small number of agencies and can moderate by hand | Property-specific checks, per-market permit rules and SLA reporting are limited to what the platform offers |
| Custom build | Market figures in the PropTech software development guide | Moderation quality is how you compete, you serve regulated markets, or you run many agencies on one portal | You own the rules, the reviewer tools and their tests |
Prices are from the vendors' pricing pages when this post was written; check them before deciding. The rest of a portal's build, from search to agent dashboards, is in how to build an app like Property Finder or Bayut.
How long does it take to build listing moderation yourself?
For a team that already has a portal: about 3–5 weeks for the state machine, required-field and permit checks, duplicate fingerprints, a reviewer queue and appeals. Image hashing and price sanity add a week or two, mostly in tuning on real data.
The main risk is false positives. A price band set too tight, or a duplicate rule that cannot tell two identical flats in one building apart, sends honest agents into a slow queue, and they stop listing. Run new checks in "flag only" mode against existing listings first, measure how many they would have blocked, and only then let them reject.
Why RAITHub for this
- We have built the platform moderation sits in. BlockEstate is a multi-tenant listing and inquiry platform RAITHub built, with listing intake, agent dashboards, lead routing and a document workflow; its MVP shipped in 6 weeks. The 11-state design above is our recommended pattern, not a description of BlockEstate's code.
- Tested state machines. Every legal and illegal move gets a test, so a release cannot reopen a path from rejected to published.
- Straight about scope. BlockEstate has no MLS integration, and we will say so. If your listings come from feeds rather than agents typing them in, we will scope the feed as new work.
When you don't need us
- You have a handful of agencies and a person can review every listing in a spreadsheet. Do that until volume says otherwise.
- You only need unsafe-image detection on an existing portal. Call a managed API directly.
- You need a legal opinion on what your portal must check in a market. That is your adviser's job; we build what they specify.
How RAITHub would build this
- Scope: the 11-state listing lifecycle with an audit trail; automated checks for required fields, location, duplicates, price bands, images and permit numbers, configured per market; reviewer queues ordered by SLA deadline with reason codes; agent appeals decided by a second reviewer; reporting on volumes, decision times and rejection reasons. Lead handling is covered in real estate lead routing.
- Timeline: a new portal with moderation built in as a fixed-scope MVP in 4–6 weeks; moderation added behind an existing portal as backend and API work in about 6–12 weeks.
- What you receive: automated tests and CI covering every transition and check, handover docs and runbooks for reviewers and engineers, and full IP assigned to you under an NDA.
- Next step: a free 15-minute technical audit, then a written fixed quote. Book the audit with your markets, listing volume and current moderation process. Our wider real estate work is on the PropTech page.
Frequently asked questions
What is listing moderation on a real estate portal?
The checks and review steps a listing passes before and after it goes live: required fields, duplicates, price and image checks, agent and permit verification, a reviewer queue for flagged listings, and an appeal route for rejections.
How do property portals detect duplicate listings?
By fingerprinting each listing from its normalised address, unit, type, bedrooms and size band, and hashing its photos to find near-identical images across other listings. Matches go to a reviewer, who merges, keeps one or allows co-listing.
How can a portal spot fake or bait listings?
Compare price per square metre with the area median, look for photos reused from other listings, expire listings whose availability is not confirmed, and act on user reports. None is proof alone, so flagged listings go to a person.
Do property listings in Dubai need a permit number?
Dubai Land Department issues real estate advertisement permits through Trakheesi, including for electronic adverts. How the number must be displayed and verified on a portal is a regulatory question; confirm the current rules with your adviser.
What states should a listing moderation workflow have?
We use 11: draft, submitted, auto_checks, in_review, changes_requested, published, rejected, appealed, suspended, expired and archived, with only defined moves allowed and a reason code required to reject or suspend.
How fast should listings be reviewed?
Set a target per queue from your volume and staff, for example the same business day for new agents and a few hours for flagged listings, then measure the time you actually achieve on every decision.
Can RAITHub build listing moderation for my property portal?
Yes. RAITHub built BlockEstate, a multi-tenant listing and inquiry platform, and would scope moderation as a fixed-scope MVP of 4–6 weeks or backend work of 6–12 weeks. It starts with a free 15-minute audit.
Related posts
Ready to discuss your project?
Book a free 15-minute technical audit with our engineering team.