Skip to main content

Listing Claims: How to Hand a Listing to Its Owner Without Handing It to a Stranger

How to build a listing claim flow: domain-matched email verification, the manual review queue, the attack surface, and what Google and Yelp actually do.

DirectoryLaunch Team13 min read
Listing Claims: How to Hand a Listing to Its Owner Without Handing It to a Stranger

Most people think of the claim flow as a button. "Is this your business?" opens a form, the owner fills it in, you approve it, done. That framing is why so many directories ship a claim flow that a bored teenager can beat.

Look at it from the other side. Your claim flow is the single endpoint where a directory voluntarily hands an anonymous visitor permanent edit rights over a page that ranks. Everything else on your site is read-only to the public or gated behind a submission you moderate. This one thing transfers control. It deserves the same design attention as your login — and structurally it is a login problem wearing different clothes.

This is a build guide for that flow: how the verification decision actually works, why the "failure" path matters more than the happy path, what people do to attack it, and what to think about the moment ownership transfers.

Why an unclaimed directory quietly stalls

If you seeded your directory the fast way — a CSV of businesses, then AI enrichment to turn each website into a description — you have a structural problem baked in from day one. Every listing belongs to you.

That's fine in month one. By month six it's the reason your directory looks abandoned. Hours are wrong. Two of the businesses moved. One closed. Four rebranded. Nobody on earth has both the knowledge and the incentive to fix that except the businesses themselves, and they can't, because the listing isn't theirs.

Claims are how you convert a scraped dataset into a maintained one. That's the real return on building the flow properly: not the claim fee, but the fact that a few hundred listings start updating themselves. It's the same logic as getting your first hundred listings — the hard part isn't the data, it's the ongoing relationship with the people the data describes.

Import unclaimed on purpose

Mark imported rows as unclaimed at import time, not later. Retrofitting an "is this claimed?" state onto a live directory means auditing every existing listing to work out which ones a real owner already touched. In DirectoryLaunch that's a checkbox in the CSV importer — existing listings stay claimed, so nothing changes until you opt in. See Listing Claims.

The decision you're actually making

Strip the UI away and a claim is one question: does this person control the business this listing describes?

You cannot answer that. What you can do is ask them to prove control of something the business already controls — a domain, a mailbox, a phone line, a physical address, a storefront. Every verification method is a proxy, and each proxy has a different combination of strength, friction and cost.

Here's how the big platforms answer it, which is worth knowing because your users have already been trained by them.

Google's Business Profile verification offers phone or SMS, email, live video call, and postcard — but the methods available are determined by Google and can't be chosen by the business, and depend on business type, public info, region and hours. Review after submission takes up to five business days. Postcard codes usually arrive within 14 days and expire after 30. Instant verification exists in one narrow case: you already verified the same website in Search Console.

Yelp goes the other way. Per their help centre, claiming is free and runs on phone verification, with a support-ticket fallback when phone verification doesn't work. One detail there is worth stealing: a claimed page can revert to unclaimed after a period of owner inactivity.

Neither of them relies on a single check. That's the lesson.

Verification methods, ranked by what they actually prove

MethodWhat it provesFrictionWhere it fails
Domain-matched emailControl of a mailbox at the business's own domainLow — code in secondsBusinesses with no domain, or that run entirely on Gmail
DNS record / meta tagControl of the website itselfHigh — needs a technical personThe owner is a plumber, not a sysadmin
Phone or SMS to the listed numberControl of the published business lineLow, if the number is rightScraped numbers go stale; IVR systems eat the code
Free-mail address + manual reviewNothing on its ownLow for the claimant, high for youDoesn't scale past a few claims a week
Postal code to the listed addressPhysical presence at the addressVery high — days to weeksOnly sane at Google's scale
Video / document reviewPresence and operationVery highYou are now running a KYC desk

For a directory that isn't Google, the honest answer is: domain-matched email as the automated path, human review as the fallback, and nothing else unless you have a specific reason.

The whole flow on one page — the automated path on the left, the queue that catches everyone else on the right
The whole flow on one page — the automated path on the left, the queue that catches everyone else on the right

Domain matching is unusually good value. If the listing's website_url is northgateplumbing.co.uk and the claimant can receive a code at dave@northgateplumbing.co.uk, they control a mailbox on the business's own domain. That is a genuinely strong signal, it costs you an email send, and it takes the claimant thirty seconds. Accept subdomains. Never accept free-mail domains as a domain match — northgateplumbing@gmail.com matches nothing, and treating it as a match is the single most common way these flows get broken.

The fallback path is the real product

Here's what trips up most implementations. Roughly half of legitimate small-business owners cannot send email from their own domain. They're on Gmail. The domain in your database is a Wix site their nephew built. The email on their invoices is a personal address they've used for fifteen years.

If your flow rejects those people, you've built a claim flow that rejects your actual users while remaining perfectly open to anyone who registers a lookalike domain.

So the mismatch case must not be a rejection. It should be a queue. The claim gets created, marked as unverified-by-domain, and lands in a review screen where a human decides. In practice you're looking at a handful of things:

  • Does the claimant's story match public information — do they appear on the business's own website, LinkedIn, or Companies House?
  • Is the free-mail address the one published as the contact address on the business's site?
  • Are there multiple pending claims on the same listing? (That's not automatically fraud. Competing agencies both "manage" a client's web presence more often than you'd think.)
  • Does anything about the timing look automated — five claims from the same address in ten minutes?

Google's model for the disputed case is a good template. When someone requests ownership of a profile that's already claimed, Google notifies the current owner by email and gives them three days to respond. Approved, denied, or no answer — and only after silence does the requester get a path to claim. Silence is a decision, and the incumbent gets a say. If you build contested claims, build that.

Never let the same claim be approved twice

Two approvals can race: an admin clicking approve at the same moment a payment webhook lands. If both transfer ownership you have two owners, or a transfer that overwrites a real one. Make the finalisation idempotent and back it with a database constraint — DirectoryLaunch uses a partial unique index on claims(app_id) WHERE status = 'approved', so the second write loses at the database level rather than depending on application timing.

Write the states down before you build the screens — every claim-flow bug is a transition nobody designed
Write the states down before you build the screens — every claim-flow bug is a transition nobody designed

Treat the verification code like a password, because it is

A verification code is a short-lived credential that grants control of a page. Everything you'd do for a login applies, and most claim implementations skip all of it.

Store the hash, not the code. If your claims table has a code column with 483920 in it, then anyone with read access to that table — a leaked service key, a misconfigured RLS policy, a backup on a laptop — can claim any pending listing. Hash it. Compare in constant time. In DirectoryLaunch, claim and quote codes are stored as SHA-256 hashes and compared with crypto.timingSafeEqual, which is documented in Built-in Protections.

Generate it with a CSPRNG. Math.random() is not a source of security values. Ever. Use crypto.randomBytes.

Cap the attempts, and count them on the claim, not the IP. A six-digit code has a million possibilities, which sounds like plenty until you notice that an attacker with a residential proxy pool can rotate IPs endlessly. If your attempt counter lives on the request origin, it resets for free. Put the counter on the claim row where it can't be rotated away, and give the code a short TTL and a resend cooldown so the attacker can't just mint fresh codes.

Don't leak state in error messages. "No pending claim for this listing" tells an attacker which listings are worth attacking. Return the same generic response either way.

Rate-limit the initiation endpoint separately. Claim initiation sends email on demand, which makes it a free mail cannon pointed at any address someone types in. It needs its own bucket, not the general one.

Should you charge for a claim?

You can. Whether you should depends on what the claim is for.

A one-time claim fee does two useful things: it filters out casual and automated claims, and it puts a real payment identity behind the person taking over the listing — a card, a name, a billing address. That's a verification signal in itself, and it's the honest argument for charging even a token amount.

It also costs you claims. Every payment step drops conversion, and in the early life of a directory the claims themselves are the asset — an owner who claims a listing and fixes their own hours is doing work for you that you'd otherwise pay someone to do. Charging $29 to let someone maintain your data for free is a strange trade in month two. It's a reasonable one in month twenty, when a listing on your site sends real enquiries.

The sequencing most directories land on:

  1. Free claims while you're building coverage. The goal is claimed, accurate listings, not revenue.
  2. Paid upgrades on top of a free claim once the directory sends traffic — featured placement, quote leads, extra photos. The owner is paying for distribution, which is defensible, rather than for permission to correct your data, which isn't.
  3. A claim fee only if fraudulent claims become a real operational problem, and then set it at the level that stops the abuse, not the level that maximises revenue.

If you do charge, make the payment step conditional rather than structural. In DirectoryLaunch the fee lives in one config value and a price of 0 skips the payment step entirely, so switching the model later is a config change rather than a refactor.

Don't put the payment before the verification

Charge after the claimant has proved control, never before. Taking money and then rejecting the claim generates refunds, chargebacks and a support thread you'll remember. The order is: verify, then bill, then transfer.

What happens after the transfer is the part nobody designs

Approving the claim isn't the end of the flow. It's the start of a permission you now have to live with.

Do owner edits go live immediately? If yes, someone will eventually rewrite their listing into an ad, or stuff it with keywords, and it'll be on a page you rank for. If no, you're moderating an edit queue forever. Most directories land somewhere in between: field-level rules, where hours, phone and photos publish instantly while name, category and description go through review.

Can ownership move again? A business gets sold. The agency that claimed it gets fired. Design for exactly one automatic transfer, then require an admin for anything after that. A flow that lets anyone re-claim an already-claimed listing has no security properties at all.

What happens when an owner goes dark? Yelp's answer — revert to unclaimed after prolonged inactivity — is worth copying if your listings need to stay current. Just make sure a warning email goes out first.

Do you tell the previous owner? If the listing was yours, no. If it was claimed by someone else, absolutely — that's the notification that turns a silent hijack into a dispute you find out about.

What to do tomorrow morning

If you already have a directory with imported listings, work through this in order. It's about half a day.

  1. Count your unclaimed listings. If it's most of them and your data is more than three months old, your accuracy problem is already live, whether or not anyone has complained.
  2. Add the entry point before you add the flow. An "Is this your business?" card on unclaimed listings, pointing at a form that emails you, is a valid v0. You'll learn who claims and why before you write any verification code.
  3. Write the domain match rule and the free-mail exclusion list first. These two rules do most of the work. Everything else is fallback handling.
  4. Build the review queue before the automated path. The manual path is what runs on day one and what catches everything the automation misses on day one thousand.
  5. Audit your code storage. If a verification code is sitting in plaintext in your database right now, fix that before you promote the feature.
  6. Decide the post-transfer edit policy in writing — which fields publish instantly, which get reviewed — and put it in the approval email so the new owner knows the rules before they break them.

Then leave the pricing decision alone for a quarter. Claims are worth more to you than claim fees are, right up until they aren't, and you'll know when that flips because owners will start asking what else they can buy.

If you're building this on a local services directory specifically, the claim flow doesn't stand alone — it comes bundled with quotes, maps and city pages, and we've written up how those fit together in local business directories.