-
Notifications
You must be signed in to change notification settings - Fork 905
Description
Context - This is a proposal from Google based on our experience consuming schema.org Offer markup and working with similar data from online merchants. If it were accepted, it would make it easier for us and others to understand the different prices related to an offer.
Introduction
Many products advertised and sold on the web have different categories of prices, for example:
- invoice price,
- list price,
- sale price,
- manufacturer-suggested retail price (MSRP)
- minimum advertised price (MAP)
- price by standardized weight or volume
Currently, schema.org does not provide a structured way of differentiating the categories of prices associated with an offer. The closest option is the /priceType property, but this field is intended to identify different price components, for example cleaning fee, service fee, downpayment, monthly installment payment, recycling fee, airport surcharge, etc. Several price components are combined together to make up a single price category.
See also issues #829 and more recently #2689 for a discussion on Compound pricing.
Proposal
We believe allowing an explicit and structured way of expressing the category of a /priceSpecification would benefit the ecosystem.
This design builds on the approach explored in #2689 which introduced an enumeration (e.g. /PriceTypeEnumeration) for the existing /priceType property. Alongside this we propose another enumeration (e.g., _/PriceCategoryEnumeration) _for different categories of prices, and a property /priceCategory to reference these. Example 2 below shows both of these dimensions being used in a single scenario.
New property /priceCategory would then be added to types /UnitPriceSpecification and /CompoundPriceSpecification to allow specification of a price category for singular prices as well as compound prices.
Example 1
The following example illustrates how to specify three different price categories (MSRP, list price, and sale price) for an offer using the proposed new enumeration
{
"@context": "https://schema.org/",
"@type": "Product",
"sku": "coffeemaker-12345",
"image": "https://www.example.com/coffeemaker.jpg",
"name": "Coffee maker",
"description": "Fast coffee maker, large",
"gtin14": "12345678905678",
"brand": {
"@type": "Thing",
"name": "SomeCoffeeBrand"
},
"offers": {
"@type": "Offer",
"url": "https://www.example.com/coffeemaker",
"itemCondition": "https://schema.org/NewCondition",
"availability": "https://schema.org/InStock",
"priceSpecification": [
{
"@type": "UnitPriceSpecification",
"priceCategory": "https://schema.org/MSRP",
"price": 150.00,
"priceCurrency": "EUR"
},
{
"@type": "UnitPriceSpecification",
"priceCategory": "https://schema.org/ListPrice",
"price": 119.95,
"priceCurrency": "EUR"
},
{
"@type": "UnitPriceSpecification",
"priceCategory": "https://schema.org/SalePrice",
"price": 99.95,
"priceCurrency": "EUR",
"validFrom": "2020-10-01",
"validThrough": "2020-10-14"
}
]
}
}
}
Note that the sale price specification in this example has an explicit date range to indicate when the sale price is valid. Also note the absence of properties /price and /priceCurrency at the offer level.
Example 2
The following example, building on the example given in issue #2689, illustrates a combination of price categories and price types.
{
"@context": "https://schema.org/",
"@type": "Product",
"sku": "GZDU23L/B",
"image": "https://www.example.com/phone_5_32_slvr.jpg",
"name": "Phone 5" 32GB Silver",
"description": "New phone 5" screen in silver with 32GB + contract",
"gtin14": "00821793049157",
"mpn": "G-2PW4100-021-B",
"brand": {
"@type": "Thing",
"name": "PhoneBrand"
},
"color": "Silver",
"offers": {
"@type": "Offer",
"url": "http://www.example.com/GZDU23LB",
"itemCondition": "https://schema.org/NewCondition",
"availability": "https://schema.org/InStock",
"priceSpecification": [
{
"@type": "CompoundPriceSpecification",
"priceComponent": [
{
"@type": "UnitPriceSpecification",
"priceType": "https://schema.org/Downpayment",
"price": 215,
"priceCurrency": "GBP"
},
{
"@type": "UnitPriceSpecification",
"priceType": "https://schema.org/Installment",
"price": 38.65,
"priceCurrency": "GBP",
"billingIncrement": 1,
"unitCode": "MON",
"eligibleQuantity": {
"@type": "QuantitativeValue",
"value": 12,
"unitCode": "MON"
}
},
{
"@type": "UnitPriceSpecification",
"priceType": "https://schema.org/Subscription",
"price": 15,
"priceCurrency": "GBP",
"billingIncrement": 1,
"unitCode": "MON",
"eligibleQuantity": {
"@type": "QuantitativeValue",
"minValue": 24,
"unitCode": "MON"
}
}
]
},
{
"@type": "CompoundPriceSpecification",
"priceCategory": "https://schema.org/SalePrice",
"validFrom": "2020-10-01",
"validThrough": "2020-10-14",
"priceComponent": [
{
"@type": "UnitPriceSpecification",
"priceType": "https://schema.org/Downpayment",
"price": 0,
"priceCurrency": "GBP"
},
{
"@type": "UnitPriceSpecification",
"priceType": "https://schema.org/Installment",
"price": 29.99,
"priceCurrency": "GBP",
"billingIncrement": 1,
"unitCode": "MON",
"eligibleQuantity": {
"@type": "QuantitativeValue",
"value": 12,
"unitCode": "MON"
}
},
{
"@type": "UnitPriceSpecification",
"priceType": "https://schema.org/Subscription",
"price": 15,
"priceCurrency": "GBP",
"billingIncrement": 1,
"unitCode": "MON",
"eligibleQuantity": {
"@type": "QuantitativeValue",
"minValue": 24,
"unitCode": "MON"
}
}
]
}
]
}
}
This example builds on the example in #2689 by adding a second compound sale price. The difference in this example between the default price (which comes without the /priceCategory property) and the sale price are the downpayment and installment price components. The subscription price component is unchanged.
Note that this example has modified the example in #2689 by moving the down payment under /CompoundPriceSpecification.
Consideration
Different price categories can be used under different circumstances, for example a product sold on the web could have a different sales price than a product advertised on the web. We could consider adding yet another pricing dimension to model how the price should be used, but this seems overkill and can instead be modeled by adding more enumeration values to the proposed /PriceCategoryEnumeration type.