Wine E-Label Compliance
Create a fully compliant EU wine e-label with ingredients, nutrition, allergens, and origin data.
This guide walks you through creating a wine e-label that meets EU Regulation 2021/2117 requirements. By the end, your wine product will have a scannable QR code linking to a Digital Product Passport with all mandatory information.
EU Regulation 2021/2117 requires e-labels for wines produced and labelled after December 8, 2023. If you ship into multiple member states, your e-label must be available in the relevant languages.
At a glance
- Outcome: a compliant e-label passport page + machine-readable dataset, reachable from a GS1 Digital Link QR code.
- Time to first result: ~10 minutes in sandbox, then production.
- What you’ll submit: ingredients, nutrition, allergens, origin, net content, alcohol by volume.
What's required
Ingredients
All additives and processing aids, with clear allergen disclosure
Nutrition
Declared per 100 mL (energy, macros, salt, alcohol where applicable)
Allergens
Sulphites, egg, fish, milk, and other Annex II allergens as applicable
Origin
Country, region, and designation (DOC/IGP) where applicable
Label outputs
QR code + passport page + structured compliance dataset
Full workflow
Register your product
Create a product entry with your wine's GTIN barcode:
export EULABEL_API_KEY="sk_test_..."
curl -X POST https://api.eulabel.eu/v1/products \
-H "Authorization: Bearer $EULABEL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Quinta dos Carvalhais Alfrocheiro 2019",
"category": "wine",
"brand": "Quinta dos Carvalhais",
"gtin": "5601012012200"
}'const EULABEL_API_KEY = process.env.EULABEL_API_KEY;
const product = await fetch('https://api.eulabel.eu/v1/products', {
method: 'POST',
headers: {
'Authorization': `Bearer ${EULABEL_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'Quinta dos Carvalhais Alfrocheiro 2019',
category: 'wine',
brand: 'Quinta dos Carvalhais',
gtin: '5601012012200',
}),
}).then(r => r.json());Attach the e-label data
Submit the full passport payload with ingredients, nutrition, allergens, and origin:
curl -X POST https://api.eulabel.eu/v1/passports \
-H "Authorization: Bearer $EULABEL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"productId": "a1b2c3d4-...",
"data": {
"productType": "wine",
"colour": "red",
"vintage": 2019,
"alcoholByVolume": 14.0,
"netContent": "750 mL",
"ingredients": [
"Grapes (Alfrocheiro)",
"Sulphur Dioxide"
],
"nutrition": {
"energyKj": 351,
"energyKcal": 84,
"fatG": 0,
"saturatedFatG": 0,
"carbohydratesG": 0.6,
"sugarsG": 0.3,
"proteinG": 0.1,
"saltG": 0,
"alcoholG": 13.5
},
"allergens": {
"containsSulphites": true,
"containsEgg": false,
"containsFish": false,
"containsMilk": false,
"containsCelery": false,
"containsLupin": false
},
"origin": {
"country": "PT",
"region": "Dão",
"designation": "Dão DOC"
},
"producers": [
{
"name": "Sogrape Vinhos S.A.",
"role": "producer",
"country": "PT"
}
]
}
}'const passport = await fetch('https://api.eulabel.eu/v1/passports', {
method: 'POST',
headers: {
'Authorization': `Bearer ${EULABEL_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
productId: 'a1b2c3d4-...',
data: {
productType: 'wine',
colour: 'red',
vintage: 2019,
alcoholByVolume: 14.0,
netContent: '750 mL',
ingredients: ['Grapes (Alfrocheiro)', 'Sulphur Dioxide'],
nutrition: {
energyKj: 351, energyKcal: 84,
fatG: 0, saturatedFatG: 0,
carbohydratesG: 0.6, sugarsG: 0.3,
proteinG: 0.1, saltG: 0, alcoholG: 13.5,
},
allergens: {
containsSulphites: true, containsEgg: false,
containsFish: false, containsMilk: false,
containsCelery: false, containsLupin: false,
},
origin: { country: 'PT', region: 'Dão', designation: 'Dão DOC' },
producers: [{ name: 'Sogrape Vinhos S.A.', role: 'producer', country: 'PT' }],
},
}),
}).then(r => r.json());Download the QR code
curl https://api.eulabel.eu/v1/products/a1b2c3d4-.../qr \
-H "Authorization: Bearer $EULABEL_API_KEY" \
-o wine-label-qr.svgThe QR code encodes a GS1 Digital Link URI (https://eulabel.eu/01/05601012012200). Print it on your wine label alongside the mandatory "e" symbol.
Verify the passport
Scan the QR code or visit the URL directly. The passport page displays:
- Ingredients list with allergen highlights
- Nutrition table per 100 mL
- Origin and producer information
- Regulatory compliance badges
Nutrition declaration format
All nutrition values are declared per 100 mL for beverages:
If you already store nutrition per serving, convert to per 100 mL before submitting. EUlabel validates required fields and returns actionable errors.
| Field | Type | Unit | Required |
|---|---|---|---|
energyKj | number | kJ | Yes |
energyKcal | number | kcal | Yes |
fatG | number | g | Yes |
saturatedFatG | number | g | Yes |
carbohydratesG | number | g | Yes |
sugarsG | number | g | Yes |
proteinG | number | g | Yes |
saltG | number | g | Yes |
alcoholG | number | g (per 100 mL) | Wine only |
Allergen codes
| Field | Allergen | EU Regulation |
|---|---|---|
containsSulphites | Sulphur dioxide / sulphites | Annex II, #12 |
containsEgg | Egg and egg products | Annex II, #3 |
containsFish | Fish (isinglass fining) | Annex II, #4 |
containsMilk | Milk / casein (fining) | Annex II, #7 |