99t.biz

RAIN RFID is arriving in phones. Point one at a shelf and ask the manufacturer directly.

What is this made of. Is it safe for me. Is it good for me. Answered by the company that made it, not guessed at from a photograph.

A Phone That Can Read the Whole Shelf

RAIN RFID readers are now built into handsets. Not clipped on, not a sled, not a separate gun on a lanyard - integrated into the device, in the same form factor as the phone already in a pocket. Point one at a shelf and it does not read one item. It reads everything in front of it, at once, through packaging, with no line of sight and nothing to line up.

That changes the question a shopper can ask. Today the question is what is this thing I picked up. With a reader that takes in the whole shelf, the question becomes which of these forty things is safe for me, and the answer arrives before anyone has picked anything up at all.

The reader is only half of it. The other half is having something worth asking, and something that will answer truthfully. That is what this is.

Somebody with a severe allergy should be able to walk down an aisle and have their phone tell them, quietly and instantly, which of these products are not for them.

Not a best guess. Not a crowd-sourced database that was accurate in 2019. The manufacturer's own answer, current as of the last time the manufacturer changed it, for the specific item on the shelf in front of them.

The radios are arriving. This is the part that has to be waiting for them.


Ask the Manufacturer. Do Not Guess at the Label.

There are two ways to answer "what is in this product," and the difference between them matters enormously once somebody is making a health decision on the result.

Photograph it and infer

  • Point a camera at a package, run OCR, hand the text to a model, hope
  • Defeated by glare, curved surfaces, shrink wrap, and the panel facing backward on the shelf
  • Defeated by a language the reader does not speak
  • Silently out of date the moment a product is reformulated
  • Cannot see which specific unit it is looking at, so lot-level recalls are invisible
  • Asked "is this gluten free," a model will answer. It will answer even when it does not know.

Read the identifier and ask

  • Read the tag, resolve the identifier, retrieve what the manufacturer published
  • Works through packaging, in a pocket, in a case, in any orientation
  • Language-independent, because an identifier is not words
  • Reformulation reaches every unit already on every shelf on the next read
  • Resolves to the individual item, so lot and serial-scoped recalls arrive
  • Asked "is this gluten free," it can say the manufacturer has not declared

The second approach has a property the first one structurally cannot have: accountability. The answer is the manufacturer's own assertion about their own product, published deliberately, attributable to them, and correctable by them. An inference drawn from a photograph belongs to nobody.

Where AI does belong in this

None of that means the technology is useless here. It means it is pointed the wrong way when it is aimed at the shelf.

Building a product record from label copy is genuinely tedious work, and a model is good at it. So on the way in, a deterministic parser handles the standard panels and a model fills the gaps it could not reach: awkward layouts, OCR noise, product names, categories. A person confirms the result before it is published.

What a model never does here is answer the shopper. By the time anyone scans anything, every assertion in the record is the manufacturer's, made on purpose. The model helped transcribe it. It does not get a vote on what is true.


Question one

What Is This Made Of?

The ingredient statement comes back verbatim, exactly as it appears on the package, because paraphrasing an ingredient list is a way of introducing errors into one.

Alongside it, the same list structured: each ingredient in declaration order, sub-ingredients nested under their parents the way the label nests them, and each one flagged if it is an allergen. "Enriched flour (niacin, reduced iron, thiamine)" survives as a parent with three children rather than collapsing into a string, because a client that needs to search inside a compound ingredient can only do that if the structure was preserved.

Net content, serving size, servings per container, country of origin, storage, and preparation come with it.


Question two, and the one that matters most

Is It Safe For Me?

Allergen data has an asymmetry that most product information systems quietly ignore, and it is the single most important design constraint in this resolver.

Getting contains milk wrong is a bad experience. Somebody puts back a product they could have eaten. Getting free from milk wrong is an ambulance. The two directions carry completely different consequences, so this system does not treat them the same way.

Three declarations, and one non-answer

DeclarationMeansExample detail
containsThe label says it is in there"whole wheat flour"
may_containCross-contact risk declared by the manufacturer"shared equipment"
free_fromAn affirmative negative claim from the packagecertifier on file

And a fourth outcome that is not a declaration at all: nothing on file. Which is the rule the whole thing is built around.

The model is never permitted to say "free from"

The extraction pass described above can add contains. It is structurally prevented from ever emitting free_from.

Not because the prompt tells it not to, although the prompt does tell it not to. The response is stripped of every free_from row before it is written, regardless of what the model returned. A prompt instruction is a request. It is not an enforcement mechanism, and the difference matters when the failure mode is anaphylaxis.

A free_from row can only originate one way: explicit text on the package, confirmed by a human.

Absence of evidence is not a negative claim

Ask whether an item fits a particular diet and the answer comes back as a verdict, resolved strictest-first:

ConditionVerdict
Contains the allergenunsafe
Diet explicitly marked not suitableunsafe
May contain the allergencaution
Diet certified or suitablesafe
Allergen explicitly declared free fromsafe
Nothing on fileunknown

unknown is a real answer, and it is deliberately not safe. A system that quietly resolves "we have no data" into "you can probably eat it" is worse than no system at all, because it converts a shopper's healthy caution into misplaced confidence. The verdict comes back as unknown, it says so, and the shopper reads the package the way they would have anyway.

Every verdict carries its reasons, so a caution is never a bare colour on a screen. It says which allergen, and why. You can watch it happen in the panel further down: the demo item resolves unsafe for dairy-free because it contains milk, and unknown for gluten-free because nobody has declared either way.


Question three

Is It Good For Me?

The nutrition panel comes back structured rather than as a picture of a table: calories, fat, saturated fat, sodium, carbohydrate, sugars, fibre, and protein, each with its unit, and each declared against an explicit basis so a client knows whether it is looking at per-serving or per-100g before it starts comparing anything.

Nutritional claims and diet certifications travel alongside, with the certifying body named where there is one. "Gluten free" carries more weight when it says who certified it.

Because this is structured data rather than a photograph of a label, comparison becomes trivial. Sweep a shelf, and sorting nine products by sodium is a client-side operation on data that is already in hand.


One Sweep, Forty Products, One Answer

This is the part that only works with radio, and it is the reason the phone hardware matters.

A reader taking in a shelf, a cart, or a fridge picks up dozens of tags in a moment. Resolving those one at a time is dozens of round trips and a spinner. So the resolver takes the whole population in a single request and answers once.

// A phone sweeps a shelf and posts everything it read
POST https://99t.biz/scan?diet=gluten_free,nut_free
{ "epcs": [ "https://99t.biz/01/00030000570524/21/12345", "..." ] }

// One response: every item, partitioned into what this person can and cannot eat

Two things fall out of that shape worth pointing at:


When Something Goes Wrong

A recall today reaches a shopper as a press release they did not read, or a sign taped to a shelf they walked past. The person holding the affected package is usually the last to know.

A recall issued here is scoped three ways: to a product, to a lot, or to an explicit range of serial numbers. Instead of "withdraw all of product X," it can be "these forty units, and nothing else on the shelf." And because the manufacturer holds the record rather than the packaging, a recall issued at 09:00 is live on the next read of an affected item. Nothing is re-encoded. No app ships an update. No store has to receive a bulletin and act on it.

The next scan of an affected serial comes back carrying the recall, its severity, its scope, and a contact. The scan of the identical-looking package beside it does not. That is a materially better outcome for the person holding it than anything the current system can do.


The Record Stays Correctable, Forever

The tag carries an identifier: a GTIN, a serial, and where to ask. That is deliberate, and it is what makes everything above possible.

Products get reformulated. Allergen statements get corrected. A supplier changes and a "may contain" becomes a "contains." If those assertions had been printed onto the item at the factory, correcting them would mean finding and replacing every unit already in the supply chain, which in practice means they never get corrected at all.

Because the item carries an identifier and the manufacturer holds the answers, a correction reaches every affected unit already sitting on every shelf, on the next read.

Nothing is stranded. Nothing has to be recalled just to fix a label. The unit encoded eighteen months ago answers with what the manufacturer knows today.

It also keeps the tag small, which is what makes tagging an item that costs a couple of euros viable at all. Every character of hostname is bits on every tag, and at retail volumes bits are money - which is why the domain is four characters long.


Built on the Standards, Not Beside Them

This is a conformant GS1 Digital Link resolver, not a private API with GS1 vocabulary sprinkled over it. Anything that speaks Digital Link can talk to it without being told anything in advance.

Link typeReturns
gs1:pipFull product information. The default.
gs1:allergenInfoAllergens, diet codes, nutritional claims, ingredient statement
gs1:nutritionalInfoNutrition panel, serving size, net content
gs1:recipeInfoIngredients, allergens, quantities, storage

And it does not depend on which radio wins

Integrated RAIN readers are what make the shelf sweep possible, and they are what the live demonstrations run on. But the identifier syntax underneath is GS1 Digital Link, which means the exact same URL is what a 2D barcode carries under GS1 Sunrise 2027, and what an NFC tag hands over on a tap:

// From a RAIN read, dozens at a time
https://99t.biz/01/00030000570524/21/12345

// From a 2D barcode, any phone camera, today
https://99t.biz/01/00030000570524/21/12345

// From an NFC tap
https://99t.biz/01/00030000570524/21/12345

Same syntax, same endpoint, same answer. The resolver has no idea which radio delivered the identifier and no reason to care. That means a shopper with any phone can get the answer today through the camera, and the moment they are holding one that reads RAIN, they get the whole shelf instead of one package. Nothing gets rebuilt in between.


Try It Live

This panel calls the public resolver from your browser. Nothing is proxied and nothing is staged - it is the same endpoint, returning the same data, that a phone gets when it reads one of these products off a shelf.

Diet filter

Serial is optional. Drop it and you get product data with no item state, which is what a GTIN-only Digital Link resolves to. Today moves the clock, for showing how an item's freshness reads at a different point in its life.

API Endpoints

GET  /01/{GTIN}/21/{SERIAL}?linkType=gs1:pip  // one item, full document
GET  /01/{GTIN}?linkType=gs1:allergenInfo      // product data, no item state
GET  /01/{GTIN}/21/{SERIAL}?linkType=all        // RFC 9264 linkset
POST /scan?diet=gluten_free,nut_free              // the shelf sweep
POST /recipe                                     // compact payload for a recipe model

// Modifiers, on any of the above
&diet=gluten_free,vegan   // adds a per-item verdict with reasons
&format=simple           // flat shape instead of GS1 JSON-LD
&today=2027-01-24       // move the clock, for demonstrations