DEV Community

Profile Tap
Profile Tap

Posted on

Letting a stranger contact a car owner without giving them the number

Letting a stranger contact a car owner without giving them the number

There is a small, very common problem in Indian cities that turns out to be a surprisingly good systems design exercise.

A car is parked badly. It is blocking a gate, a driveway, another car. Someone needs the owner to move it, right now. The traditional fix is a phone number written on a sticker on the windscreen.

That works. It also means a stranger — any stranger, forever — has the owner's personal number.

Why the sticker is worse than it looks

Once a number is visible on a windscreen, a few things follow:

It gets scraped. Numbers on vehicles end up in marketing lists.
It cannot be revoked. Change your number and every sticker you own is now wrong.
It has no context. A 2am call could be a genuine emergency or someone who saw the number three months ago.
It is a safety issue for some owners in a way it is not for others. A number attached to a vehicle, at a known parking spot, at predictable times, is more information than most people realise they are publishing.

So the requirement is oddly specific: a stranger must be able to reach the owner, immediately, without ever learning how to reach them again.

That constraint is what makes this interesting.

The naive version, and why it fails

First instinct: put a QR code on the vehicle that opens a page with a "call owner" button, and put the number behind the button.

This solves nothing. The number is still in the page source. Anyone who wants it can get it, and now you have added a scan step for the honest majority while stopping none of the dishonest minority.

Second instinct: put a contact form behind the QR. The stranger types a message, the owner gets a notification.

Better on privacy, useless in practice. The person needs the car moved in the next ninety seconds. They are not filling in a form and waiting for an email. If the fast path is not there, they go back to writing an angry note.

The real requirement is synchronous contact with asynchronous identity — a live call, where neither party's number is exposed to the other.

What actually works: masked call routing

The pattern is well known in cab and delivery apps, but it fits this case cleanly.

You need a pool of virtual numbers. When someone scans the vehicle's code:

  1. Scan resolves to vehicle → owner (server-side, no number in response)
  2. Server leases a virtual number from the pool for this session
  3. Server binds: virtual_number → owner_number, TTL 10 minutes
  4. Page shows a "call" button pointing at the virtual number
  5. Caller dials it. Bridge connects to the owner.
  6. Neither side sees the other's real number.
  7. TTL expires. Binding is torn down. Number returns to the pool.

The owner's phone rings from a number they do not recognise, which is expected and fine. The caller's number is also masked, which matters more than people assume — otherwise you have just moved the privacy problem onto the person who was trying to help.

A few things that are easy to get wrong here:

Pool sizing is a real constraint. Virtual numbers cost money and you only need one per concurrent session, not per vehicle. Sizing follows peak concurrency, not user count. Getting this wrong is how the economics break.

TTL needs to be short but not hostile. Ten minutes covers the "please move your car" case comfortably. Twenty-four hours turns the lease into a persistent channel, which is exactly what you were trying to avoid.

Bindings must be one-to-one within their window. If two people scan different vehicles and get the same virtual number in the same window, you have a routing bug that connects strangers to the wrong owners. This is the kind of bug that is invisible in testing and obvious in production.

The abuse surface you inherit

The moment you build "anyone can make this stranger's phone ring," you have built a harassment tool. This is not hypothetical — it is the predictable outcome, and it needs handling at design time rather than after the first complaint.

What helped:

Rate limit per scanning device and per target. A vehicle should not be reachable fifteen times in ten minutes by the same person.
Let the owner mute a tag. Not delete — mute, with a timer. Overnight, or while parked at home. The scan still resolves, it just shows a message instead of a call button.
Log every session. Not the call content, just the fact of it: which tag, when, from which region. When someone reports harassment you need something to look at.
Do not expose the owner's name by default. "Owner of a vehicle at this location" is enough information for the interaction to work. A name is not.

The general principle: every contact route you create is also an attack surface, and the owner needs a control for it that does not involve peeling a sticker off their windscreen.

Why the identifier has to be permanent

Here is the part that shapes everything else.

The code on the vehicle is physical. It is printed, stuck on, and then it is out of your control. You cannot push an update to a sticker.

That means the identifier it encodes must be permanent, and everything it resolves to must be mutable:

tag_id (immutable, printed)
└── vehicle record (mutable)
└── owner record (mutable)
└── contact routing config (mutable)

Owner changes their number? Update the owner record. Sticker keeps working. Sells the car? Reassign the tag to the new owner, or unbind it entirely. Sticker keeps working — it just resolves to a different place, or to nothing.

If you build the sticker to encode a URL that contains anything mutable — a number, a username, a profile slug that users can edit — you have shipped something that will break, on physical objects you cannot recall.

This sounds obvious. It is not how most QR-sticker products are built, because when you are moving fast, encoding the current URL is one line of code and encoding a stable ID means building a resolver.

The same primitive, different schemas

Once the resolver exists, the vehicle case turns out to be one instance of a general shape:

Object Who scans What they need
Vehicle Someone blocked in Reach the owner, now
Pet collar Someone who found a lost dog Reach the owner, now
Luggage Airline staff, a stranger Reach the owner, eventually
Person Someone you just met Save your contact details

Identical plumbing — permanent ID, mutable record, resolver, contact policy. Only the record schema and the default contact policy differ. The pet and vehicle cases both want urgent masked contact. The luggage case tolerates asynchronous. The person case wants no masking at all, because you are handing the code over deliberately.

Recognising that early saved us from building four products. We build one resolver and four schemas, which is roughly the architecture we ended up with.

What I would tell someone building this

Do not start with the hardware. Everyone starts with the hardware because it is tangible. The hardware is the easy part. The resolver, the masking layer, and the abuse controls are where the actual work is.

Decide your masking economics before you design the UX. If virtual numbers are too expensive at your scale, you will end up compromising the privacy model to make the numbers work, and you will do it late, badly, under pressure.

Assume the sticker outlives your product decisions. Anything printed is a promise you cannot take back. Design as if every tag will still be on a vehicle in five years, because some of them will be.

If you want the non-technical version of this — what actually goes on a vehicle tag and how owners in India use them day to day — I wrote that up separately: bike and car QR code tags in India.

Curious whether anyone has solved the pool-sizing problem more elegantly than "provision for peak and eat the cost." It feels like there should be a better answer than there is.

Top comments (1)

Collapse
 
fibonachi profile image
Opstan

The masked-call approach is thoughtful, especially the recognition that every new contact route also creates an abuse surface.

Because privacy and abuse controls are central promises of the product, how will owners verify that those rules have not quietly changed after their tag was purchased? A physical QR identifier may remain for years while the service policy evolves.

Would it make sense to preserve every important privacy, retention and abuse-prevention policy in a permanent public history, including the original version and all later changes?