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.
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.
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.
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.
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
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
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.
| Declaration | Means | Example detail |
|---|---|---|
| contains | The label says it is in there | "whole wheat flour" |
| may_contain | Cross-contact risk declared by the manufacturer | "shared equipment" |
| free_from | An affirmative negative claim from the package | certifier 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 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.
Ask whether an item fits a particular diet and the answer comes back as a verdict, resolved strictest-first:
| Condition | Verdict |
|---|---|
| Contains the allergen | unsafe |
| Diet explicitly marked not suitable | unsafe |
| May contain the allergen | caution |
| Diet certified or suitable | safe |
| Allergen explicitly declared free from | safe |
| Nothing on file | unknown |
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
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.
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.
Two things fall out of that shape worth pointing at:
gluten_free and nut_free and the response separates the shelf into what is safe and what is not, with per-item reasons attached. That is a different product from forty individual lookups, even though the underlying data is identical.?format=recipe returns a payload shaped for a model. Compact, carrying what is actually in the kitchen and what the household cannot eat. The allergen constraints travel with the ingredient list rather than being bolted on afterward as a prompt instruction, which is the same reasoning as everywhere else on this page: put the constraint in the data, not in a request that something might ignore.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 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.
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 type | Returns |
|---|---|
gs1:pip | Full product information. The default. |
gs1:allergenInfo | Allergens, diet codes, nutritional claims, ingredient statement |
gs1:nutritionalInfo | Nutrition panel, serving size, net content |
gs1:recipeInfo | Ingredients, allergens, quantities, storage |
?linkType=all, per RFC 9264, plus Link headers advertising every alternate on every response. A client discovers what else can be asked without being told.?format=simple returns a flatter shape for clients that would rather not walk JSON-LD.gs1: vocabulary. Per-item state like expiry, freshness, and recall status lives under a 99t: namespace, because it is not GS1 product master data and forcing it into vocabulary that does not mean that would make the document wrong in a way no validator would catch.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:
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.
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.
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.