Running a promotional sale is straightforward on your storefront, but getting the price data right in your product feed is where many merchants run into disapprovals. Two attributes control how Google reads your sale pricing: sale_price and sale_price_effective_date. Getting both right — including the date format — is what separates a clean feed from a disapproved one.
What the sale_price Attribute Must Contain
The sale_price attribute carries the discounted price you charge during a sale period. According to Google documentation, the attribute type is Number plus currency (ISO 4217), meaning you must always pair the numeric value with a currency code. In a TSV or CSV file that looks like 15.00 USD; in XML it is <g:sale_price>15.00 USD</g:sale_price>.
Several hard requirements apply that can cause product disapproval if missed:
- Always keep submitting
pricealongsidesale_price. The full, non-sale price must remain in thepriceattribute. As Google documentation states, "the product sale price should be less than the price for the product, and this price difference should show in your product data." - Landing page consistency is mandatory. You must "clearly display both non-sale and sale prices on your landing pages, and only the sale price at checkout."
- No more than two decimal digits. A value like
1.0234is automatically rounded to1.02. Submit clean values from the start to avoid unexpected rounding. - Do not use
sale_pricefor loyalty prices in countries where the loyalty program is supported. Use theloyalty_programattribute instead.
Note that a sale price annotation — the badge that highlights the discount in Google Shopping — may not always appear even when all requirements are met. Google reserves the right to surface whichever annotation it considers best performing.
How sale_price_effective_date Controls Timing
Without a date range, your sale price becomes active immediately upon feed processing and stays active until you remove it. To control exactly when the sale starts and ends, submit the sale_price_effective_date attribute.
The format requirement is specific. Google documentation defines the type as: Date range (ISO 8601), with a start date and end date separated by a slash, in the format YYYY-MM-DDThh:mm[±hhmm] or YYYY-MM-DDThh:mmZ. The field is limited to 0–51 characters and is not a repeated field.
A correct TSV value looks like this:
2024-11-29T06:00-0500/2024-11-29T23:59-0500
And in XML:
<g:sale_price_effective_date>2024-11-29T06:00-0500/2024-11-29T23:59-0500</g:sale_price_effective_date>
Two specific timing defaults matter if you omit parts of the value:
- No time included: The sale starts at 12:00 AM midnight on the start date and ends at 11:59 PM on the end date.
- No timezone included: Google defaults to UTC.
If your sale is timezone-sensitive — a flash sale running 9 AM to 9 PM Eastern, for example — always include the offset (-0500 for Eastern Standard Time) or your sale window will be misaligned for shoppers in your target market.
Common Checks Before Feed Submission
Before pushing a sale price update to your feed, run through each of the following:
1. Price relationship check
Confirm sale_price is numerically lower than price. If they are equal or sale_price is higher, the feed will be non-compliant.
2. Landing page match Open the product URL and verify the sale price shown matches the value in the feed exactly. A mismatch between feed and landing page is a common disapproval reason.
3. Date string validation Check that the date string uses a forward slash separator, includes both a start and end datetime, and that the end date is later than the start date. A reversed date range (end before start) will make the attribute unusable.
4. Timezone offset If your sale targets a specific region, include an explicit timezone offset rather than relying on the UTC default.
5. Decimal precision
Verify no prices carry more than two decimal digits. Submit 29.90 not 29.8999.
6. Variant-level granularity
If only some variants are on sale, submit sale_price only on those specific rows. Do not apply a sale price to variants that remain at full price.
Hypothetical Example: A Weekend Flash Sale on Selected Variants
This is a hypothetical example for illustration purposes only.
Suppose a merchant sells a water bottle in three colors — Alpine White, Slate Grey, and Coral Red — at a regular price of 34.99 USD. For a weekend promotion, only the Alpine White variant goes on sale at 24.99 USD, running from Saturday 8:00 AM to Sunday 11:59 PM Eastern Standard Time (UTC−5).
The feed rows for this scenario would look as follows:
| Attribute | Alpine White (on sale) | Slate Grey (full price) |
|---|---|---|
id | BTL-500-WHT | BTL-500-GRY |
price | 34.99 USD | 34.99 USD |
sale_price | 24.99 USD | (not submitted) |
sale_price_effective_date | 2024-11-30T08:00-0500/2024-12-01T23:59-0500 | (not submitted) |
The Slate Grey row receives no sale_price field at all. If the merchant mistakenly submitted sale_price: 34.99 USD on the Slate Grey row — matching price — that would fail the requirement that the sale price must be less than the base price.
For the Alpine White row, the date string stays within the 51-character limit, uses the correct ISO 8601 slash-separated format, and carries an explicit timezone offset so Google does not fall back to UTC.
Keeping Sale Price Data Clean Over Time
Expired sale prices that remain in your feed are a silent problem. Once the sale_price_effective_date end time passes, Google ignores the sale price and uses the price value instead — but leaving stale sale price attributes in your feed creates unnecessary noise and can cause confusion during audits.
A practical maintenance routine:
- Remove or blank the
sale_priceandsale_price_effective_datefields as soon as a promotion ends. - If your platform exports both fields automatically from a "compare at price" or "was price" field, confirm that field is cleared at the end of each sale, not just the storefront display.
- After any feed update involving prices, review the Merchant Center diagnostics tab for price mismatch or disapproval warnings before the feed refresh cycle completes.
Managing sale price attributes accurately across a large catalog — especially when different variants carry different promotion windows — is one of the areas where a structured feed management workflow pays off. Magicfeedpro is built to help catalog operators maintain that kind of attribute-level control across product feeds at scale.
Related articles

item_group_id for Variants: Requirements, Value Rules, and Feed Impact
When item_group_id is required for color and size variants, what value rules apply, and what happens when it is missing or mismatched.

identifier_exists With a GTIN: What to Set for brand
When a product has a valid GTIN but no brand value, here is what Merchant Center requires for identifier_exists and brand.

Shipping Weight and Dimensions in Google Shopping Feeds
When to submit shipping_weight and shipping dimensions in your product feed, and how to format each attribute correctly.

