EAN/GTIN für Lidl-Plus-Bons – Recherche-Bericht
Stand: 05.06.2026 · Recherche: 2 parallele Web-Recherchen + eigene Live-Tests gegen die Lidl-APIs (mit echtem Konto/Token)
Kernbefund
Die Aussage „die Mobile-App-API liefert die EAN mit" war richtig – ist aber seit
Q3/2024 tot. Das v2-Bon-Detail (tickets.lidlplus.com/api/v2/…/tickets/{id})
lieferte pro Position das Feld codeInput = EAN-13. Lidl hat diesen Endpoint
serverseitig abgeschafft; der Nachfolger v3 liefert den Bon nur noch als
gerendertes HTML (ticketType: "HTML") mit der internen 7-stelligen
Artikelnummer (data-art-id) – ohne EAN. Es gibt Stand Juni 2026 keinen
bekannten API-Weg mehr zur EAN pro Bon-Position. Die gesamte
Reverse-Engineering-Community bestätigt das; O-Ton aus dem maßgeblichen Projekt
(lidl-plus PR #22, 10/2024):
"unfortunately yeah, there's no way to get the barcode now."
Konsequenz: Die EAN muss außerhalb der Lidl-API beschafft werden (OpenFoodFacts-Matching, Selbst-Scannen). Genau dafür ist unser Hybrid-Ansatz gebaut – Details unten.
1. Eigene Live-Befunde (mit echtem Token verifiziert, 05.06.2026)
| Endpoint | Ergebnis |
|---|---|
GET api/v2/DE/tickets (Liste) |
✅ funktioniert (467 Bons) |
GET api/v2/DE/tickets/{id} (das alte EAN-Detail) |
❌ 405, Allow: DELETE – Lesen abgeschaltet |
GET api/v3/DE/tickets/{id} |
⚠️ 200, aber ticketType:"HTML" – nur data-art-id, kein codeInput, keine 13-stellige Zahl im gesamten HTML |
GET api/v1|v4/DE/tickets/{id} |
❌ 404 |
v3 mit App-Headern / ?format=json u. ä. |
❌ identisches HTML, kein JSON-Schalter |
appgateway.lidlplus.com/app/V24|v24|v23/DE/tickets… (Spur aus alter Postman-Doku) |
❌ 502 Bad Gateway – Route existiert nicht mehr |
www.lidl.de/p/x/p0081315 (Bon-artId als Shop-ID) |
❌ 404 – Bon-Artikelnummer ≠ lidl.de-SKU, kein Mapping |
Header App-Version: 999.99.9 |
⚠️ triggert Akamai (Request hängt bis Timeout) – Fake-App-Header vermeiden |
2. Geprüfte Spuren aus der Web-Recherche
Tot (belegt)
- Alle bekannten Bibliotheken/Forks: Andre0512/lidl-plus
(PR #22 offen, parst HTML ohne EAN), zsobix/lidlplus-api
(aktivster Fork, 04/2026: nutzt v3 roh, keine EAN), bluewalk/.NET (archiviert 2024),
KoenZomers/LidlApi (archiviert), MrKrisKrisu/Lidl-eReceipt-Parser (OCR!, archiviert 2025).
→ Niemand hat einen Ersatz-Endpoint gefunden; keine Hinweise auf
searchableData, GraphQL oder einen purchases-Service mit Positionen. - lidl.de-Produktseiten: JSON-LD enthält
sku, Name, Marke, Preis – keingtin13/EAN (per curl verifiziert). Auch kommerzielle „liefert EAN"-Scraper (Apify & Co.) geben real nur die interne SKU zurück. - Angebots-/Prospekt-APIs (
offers./brochures.lidlplus.com): keine EAN+Artikelnummer-Paare, nur Aktionsartikel – als Mapping-Quelle unbrauchbar. - opengtindb/ean-suche/GS1/Codecheck: EAN→Daten-Richtung (wir brauchen die Gegenrichtung), Eigenmarken-Abdeckung schwach bzw. kein offener API-Zugang.
Offen mit gedämpfter Erwartung
- DSGVO-Datenkopie (Art. 15): enthält laut Lidl-Datenschutzhinweisen „Kauf-/Bestellhistorie"; kein Erfahrungsbericht belegt EANs darin. Da Lidl die EAN sogar aus der eigenen API entfernt hat, ist sie im Export unwahrscheinlich. Kostet nichts außer Wartezeit (max. 1 Monat) → trotzdem anfordern, Ergebnis prüfen. Anfrage z. B. über datenanfragen.de/company/lidl.
- Scan&Go („Lidl & Go")-Produkt-Lookup: Die Self-Checkout-Funktion der App muss einen EAN→Artikel-Endpoint haben (konzeptionell die perfekte Brücke artikelnummer↔EAN). Öffentlich komplett undokumentiert; bräuchte eigenes MITM der App in einem Scan&Go-Markt. Aufwand hoch, Erfolg ungewiss.
Nutzbar (und teils schon umgesetzt)
- OpenFoodFacts bleibt die beste Quelle – nicht per EAN, sondern per Suche:
api/v2/search?stores_tags=lidl&brands_tags=milbona…liefert 1454 Milbona-Produkte mit EAN + Nährwerten (verifiziert); Lidl gesamt ist fünfstellig. Ein Vorfilter aufstores_tags=lidl+ Eigenmarken-Heuristik (Kategorie→Marke: Milch→Milbona, Wurst→Dulano, TK→Freshona …) kann unsere Trefferquote deutlich erhöhen.- Das Feld
abbreviated_product_name(enthält teils exakt den Kassenbon-Kurznamen) ist leider nur sporadisch gepflegt (Stichproben: bei Dulano/K-Classic-Treffern leer) und nicht als Suchfeld indiziert – nur als Bonus-Signal nutzbar, nicht als Primärschlüssel.
3. Was bereits gelöst ist (unser Hybrid-System, Stand heute)
- Stabiler Schlüssel statt EAN: jede Bon-Position wird über die interne
Artikelnummer als Grocy-Barcode
LIDL:{artId}getrackt – Import, Preishistorie und Idempotenz funktionieren ohne EAN. - Auto-Anreicherung: OFF-Namenssuche mit Lidl-Eigenmarken-Boost; bei Konfidenz ≥ 0.75 werden Klarname, echte EAN, Kategorie und kcal/Makros übernommen → ~40 % der 968 Produkte exakt angereichert.
- Fuzzy-Makros:
sync.py enrich --fuzzyübernimmt bei Konfidenz ≥ 0.6 nur die Nährwerte vom besten Namenstreffer (gleichnamige Produkte anderer Marken sind nährwertlich nahezu identisch); kein Umbenennen, keine falsche EAN. - Nachschärfen per Scan: echte EAN einmal mit der Grocy-App ans Produkt
scannen →
sync.py enrichüberschreibt mit den exakten OFF-Daten. Die Kandidatenliste liefertsync.py status. - Duplikate: Lidl vergibt pro Produkt mehrere Artikelnummern →
sync.py dedupeführt sie zusammen (52 Stück bereits gemergt), der Import verhindert neue Duplikate über die gematchte EAN.
4. Empfohlene nächste Schritte
| Prio | Maßnahme | Erwartung |
|---|---|---|
| 1 | OFF-Matching verschärfen: stores_tags=lidl-Vorfilter + Kategorie→Eigenmarken-Heuristik in best_match() |
+10–20 pp automatische Abdeckung, exaktere EANs |
| 2 | Nachscannen im Alltag (Top-Produkte zuerst: sync.py status sortiert nach Konfidenz) |
100 % exakt für alles, was du tatsächlich kaufst |
| 3 | DSGVO-Kopie anfordern und auf GTIN prüfen | gering, aber gratis |
| 4 | (optional, exotisch) Scan&Go-MITM in einem Lidl-&-Go-Markt | hoch riskant/aufwändig, einzige echte artId↔EAN-Brücke |
5. Update 16.06.2026 — IPA-Static-Analyse geprüft, EAN-Bridge geparkt
Terra (Foundation) hat die entschlüsselte Lidl-Plus-IPA v17.3.6 statisch zerlegt
(Hermes-Bytecode-Disasm + Mach-O-Strings aus Haupt-Binary + 26 Frameworks) plus einen
Live-MITM-Versuch. Roh-Korpus: /home/dennis/lidl-re/ (README = Methodik, analysis/strings_*,
captures/). Distillat: /home/dennis/foundation/vpn/lidl-api.md. Ergebnis für unser
Bon-EAN-Problem: bestätigt den Kernbefund oben, keine neue Brücke. Im Detail
(eigene Live-Tests + Korpus-Grep, 16.06.):
tickets/v2/DE/ticketsweiterhin 200 (Token sauber, 471 Bons) — der Refresh-Token-Flow lebt. Bon-Item trägt nurcodeInput(= 7-stellige In-Store-ArtId), keine EAN (imItemPurchase-Struct bestätigt).- EAN-Bridge via
product-catalog.lidlplus.com/api/appist ein Sackgasse-Kandidat — Namensraum-Bruch. product-catalog ist verschlüsselt nachproductId/commercialId(+articleId/erpNumber, alles Online-Shop/PIM-Welt). Der Bon-codeInputerscheint im ganzen Korpus nur in Ticket-/Scan-/Pfand-Strukturen, nie im product-catalog-Kontext; keinecodeInput → productId-Auflösung auffindbar. Mit der Bon-artId lässt sich product-catalog also nicht direkt abfragen. product-detailwurde nie live beobachtet — rein statisch + iXGuard-gepinnt. Im Live-Capture waren alle auth'd App-Calls (appgateway/selfscanning/tickets/product-catalog) gepinnt → unentschlüsselt; einzig entschlüsselt war ein unauth Gateway-Call (GET appgateway.lidlplus.com/configurationapp/v3/countryconfigurations/DE → 200). Eigene Replikation gegen unseren Token:product-catalog.lidlplus.com/api/app/product-detail/{artId}→ leeres 404 (alle Pfadformen),appgateway.lidlplus.com/...→ 502. Kein 401 = Routing/Pfad falsch, nicht Auth — aber der echte Pfad ist im Static-Korpus nicht sauber belegt.- EAN-Feldname im Produktkontext wahrscheinlich
barcode(keingtin/ean-Token dominant). - Wo EAN↔Artikel real entsteht:
CartsAddProductResponsePayload= die Self-Scan-Basket- Antwort (Barcode scannen → Server verknüpft EAN mit In-Store-Artikel). Bestätigt §2/§4 oben: die einzige echte Brücke ist Scan&Go, nur in aktiver In-Store-Session, gepinnt → nur per Runtime-Frida-Pinning-Bypass am Jailbreak-Gerät live verifizierbar (Anleitung:/home/dennis/foundation/vpn/lidl-mitm-anleitung.md).
Entscheidung (Dennis, 16.06.): EAN-Bridge geparkt, bis es eine Live-Aufnahme gibt.
Produktiver Weg bleibt das OFF-Matching (§3). Nicht erneut blind von der VPS gegen
product-catalog probieren — ohne live gesehenen Pfad + passende productId ist das aussichtslos.
(Potenziell wertvoller als die EAN-Bridge wäre Use-Case A: Live-Einkaufslisten-Abhaken via
selfscanning/basketsummary — ebenfalls gepinnt, braucht dieselbe Live-Capture-Session.)
Quellen
/home/dennis/foundation/vpn/lidl-api.md(IPA-RE-Distillat) ·/home/dennis/lidl-re/(Roh-Korpus) ·/home/dennis/foundation/vpn/lidl-mitm-anleitung.md(Live-Capture-Weg)- https://github.com/Andre0512/lidl-plus/pull/22 (v3-Wechsel, EAN-Verlust, Zitat)
- https://github.com/Andre0512/lidl-plus/issues (#20 HTTP 500, #23 403, #24 Login, #26 Coupons 404)
- https://github.com/zsobix/lidlplus-api (aktivster Fork, v3 roh)
- https://github.com/bluewalk/lidlplus-dotnet-client (archiviert) · https://github.com/KoenZomers/LidlApi (archiviert) · https://github.com/MrKrisKrisu/Lidl-eReceipt-Parser (OCR, archiviert)
- https://documenter.getpostman.com/view/624585/SW7W6qFq (alte Postman-Doku „BW – Lidl Plus"; appgateway-Routen heute 502)
- https://world.openfoodfacts.org/api/v2/search?stores_tags=lidl&brands_tags=milbona (1454 Treffer, verifiziert)
- https://www.lidl.de/p/milbona-haltbare-milch/p11710850 (JSON-LD ohne GTIN, verifiziert)
- https://www.datenanfragen.de/company/lidl/ (DSGVO-Anfrage)
- Eigene Live-Tests 05.06.2026 (Abschnitt 1; Token-authentifiziert)