Shopify field mapping
Shopify body_html to description
product.body_html
description
The Shopify description is rich text stored as HTML, and the feed description attribute wants plain text. The mapping has to strip the markup, decode the entities it leaves behind, collapse the whitespace that replaces the block elements, and only then truncate to the channel limit.
The Shopify side
- API field
- product.body_html
- Called
- Description
- Found at
- Product → Description (the rich text editor)
- Feeds
- description
Before and after
Real values on the left as Shopify stores them, on the right as a channel needs them.
| In Shopify | In the feed | Note |
|---|---|---|
Brushed cotton. Made in Portugal. |
Brushed cotton. Made in Portugal. | Block boundary becomes a space, so the two sentences do not run together. |
|
100% cotton. Machine washable. | List items separated rather than concatenated. Some generators use a semicolon or a bullet character instead. |
| Tom & Jerry's blend | Tom & Jerry's blend | Entities decoded. Left alone they reach the shopper as raw entity text. |
| Soft and warm | Soft and warm | Non-breaking spaces from pasted content normalised to a single space. |
Sale! |
Sale! | Script content removed entirely rather than stripped to its text. |
The transformation, step by step
-
Convert block boundaries to whitespace before stripping tags
Removing tags naively joins the end of one paragraph to the start of the next, so "Machine washable.Made in Portugal." appears in the feed. Replace closing block tags and line breaks with a space or newline first, then strip what remains.
-
Strip the remaining markup
Remove every tag, including the inline ones. Also remove anything that was never prose in the first place: embedded scripts, style blocks, tracking pixels and the iframe a review app injected.
-
Decode HTML entities
Stripping tags leaves entities behind, so the text still contains &, and '. Decode them to real characters, because an entity in a feed field is submitted literally and appears that way to shoppers.
-
Collapse whitespace
Pasted content brings non-breaking spaces, double spaces and long runs of newlines. Collapse runs of whitespace to single spaces and trim the ends, so the value is one clean block of prose rather than a shape that hints at the HTML it used to be.
-
Truncate on a word boundary, last
Channels cap the description length. Truncate after cleaning rather than before, or the limit is spent on markup, and cut at a word or sentence boundary rather than mid-word.
What goes wrong
HTML submitted as-is is rejected or mangled
The description attribute is a text field. Markup in it is either rejected outright or displayed literally, and a description that begins with a div is the most visible possible sign that a feed was exported rather than mapped.
Apps inject markup you did not write
Review widgets, size-chart apps and page builders add their own HTML into the description field. That content is not prose about the product, so a naive strip carries fragments of interface text into the feed. Removing known app blocks is part of the mapping rather than an optimisation.
Truncation before cleaning wastes the limit
Cutting to the channel limit while the value is still HTML spends a large part of the allowance on tags, so the visible description is much shorter than it should be, and often ends inside a tag.
An empty description is common and disqualifying
Plenty of Shopify products have no description at all, particularly imported ones. Description is required on every channel, so those items are rejected. A fallback built from the title, product type and brand is better than an empty field, though it is a stopgap rather than a fix.
How feedlab maps it
feedlab converts block boundaries to whitespace, strips markup and script content, decodes entities, collapses whitespace and then truncates on a word boundary to each channel's limit, so the same source description produces a correct value at every length. Products with an empty description are listed in the preview rather than silently shipped as blanks.
Frequently asked questions
Can I send HTML in the feed description?
No. The attribute is plain text, so markup is either rejected or shown to shoppers literally. The HTML has to be stripped and its entities decoded before the value reaches the feed.
Why do my feed descriptions have words joined together?
Because the tags were stripped without replacing block boundaries first. The end of one paragraph is joined to the start of the next, which is the signature of a naive strip.
What do I do about products with no description?
Description is required everywhere, so those items are rejected. A generated fallback from the title, type and brand keeps them serving, but the real fix is writing the description.
Should the description be truncated to the channel limit?
Yes, but after cleaning and on a word boundary. Truncating while the value is still HTML spends the allowance on markup and frequently cuts mid-tag.
Attributes involved
- description The description attribute is the prose a channel uses to understand and display what a product is. On Shopify it maps from body_html, which is rich text, so it needs its HTML stripped and its entities decoded before it can be submitted.
- title The title attribute is the product name a channel shows in a listing and matches against search queries, which makes it the single highest-leverage field in a product feed. On Shopify it usually needs building from the product title plus the variant's options, because the raw product title alone does not describe an individual variant.
Related concepts
Primary sources
Channel specifications change. These are the official documents this page is based on.