Price selectors for price tests
Price selectors tell Personizely where prices appear on your Shopify theme, so a price test can show each visitor their variation's price. They're CSS selectors for the product container (the root) and for the price, compare-at price and savings elements inside it. You set them once per store under Settings → Campaigns → Product selectors, and every price campaign uses them.
Available on: Shopify. A price campaign can't start until selectors are configured.
How prices are found
- The snippet looks for price elements matching your Price, Price compare, Savings value and Savings percent selectors, on every page and as new elements appear (quick views, infinite scroll, recommendations loaded later).
- Each price is tied to a product through its closest Root element that carries a product ID. Prices whose product isn't in a running campaign are left alone.
- The variant is detected from the root: the selected variant in its product form ([name="id"]), or a data-variant-id attribute. Without a variant (typical on collection cards), the product-level rule is used.
- The price is rewritten in your store's money format, using the variation's price rules. Savings and savings percent are recalculated from the new price and compare-at price.
- Prices of campaign products stay hidden until they're rewritten, so visitors don't see the original price flash. Elements are re-rewritten if your theme re-renders them, for example when the variant changes.
Configure selectors
- Go to Settings → Campaigns.
- Click Detect from theme. If your published theme is one of the supported Shopify themes, its preset selectors are filled in.
- Otherwise, add your theme's selectors to each field. The Example preview highlights which part of a product card each field targets.
- Click Save, then Validate (supported themes) to check your theme files.
- Preview a price campaign. Prices that were rewritten get a red outline.
Field | What it targets | Example |
|---|---|---|
Root | The element that wraps one product (a product card, the product page's info block, a search result). Must carry the product ID (see below). | div.card-wrapper[data-product-id] |
Price | The current price | .price__regular .price-item--regular |
Price compare | The compare-at ("was") price | .price__sale .price-item--regular |
Savings value (optional) | A "You save $X" amount | .ply-transform-savings |
Savings percent (optional) | A "X% off" badge | .ply-transform-savings-percent |
Each field accepts several selectors. Price selectors are searched inside the root, so they can be short.
Presets
Detect from theme has presets for these Shopify themes: Dawn, Taste, Trade, Spotlight, Craft, Colorblock, Sense, Refresh, Origin, Studio, Ride, Publisher and Crave. For these, Validate checks the theme's product, product card, predictive search and price files and lists any selector that's missing, or found without the data-product-id attribute, with a link to edit the file.
Other themes, including heavily customized versions of these, need their own selectors. Support can set them up for you.
Product ID on the root
Each root element must expose the product's numeric Shopify ID. Personizely accepts:
Source | Example |
|---|---|
data-product-id attribute (digits are extracted, so prefixes are fine) | data-product-id="7712345678901" or data-product-id="quiz-result-7712345678901" |
product-id attribute | product-id="7712345678901" |
data-original-product-id attribute | data-original-product-id="7712345678901" |
A product-id-<id> class | class="card product-id-7712345678901" |
Most themes don't add the ID to product cards by default. Add it in your theme's card snippet, for example in Dawn's snippets/card-product.liquid:
<div class="card-wrapper product-card-wrapper" data-product-id="{{ card_product.id }}">Variant-specific elements
Some themes render a price element per variant and show only the selected one. Use the {variantId} placeholder in a selector to target the current variant's element, for example [data-variant-price="{variantId}"]. Elements inside a data-variant-id wrapper are only rewritten when that wrapper's ID is the selected variant.
Developer attributes
Attribute | Where | What it does |
|---|---|---|
data-price="44.99" | Price or compare-at element | Personizely reads the original price from it instead of parsing the text. Use it when your theme formats prices unusually (ranges, "From", split cents). |
data-ply-transform-skip="true" | Price element or root | That element (or the whole product) is never rewritten |
data-variant-id | Root, or an element inside it | Tells Personizely which variant is shown |
Personizely's own product widgets are always included, without selectors. Seal Subscriptions price elements are supported: when a subscription plan is selected, only its subscription price is rewritten.
Behavior details and limitations
- Selectors are store-wide. All price campaigns share them. Changes apply to running campaigns as soon as you save.
- Theme changes can break detection. If you switch or update your theme, check that prices are still rewritten (preview a campaign and look for red outlines). A selector that stops matching leaves the original price visible, while the cart and checkout still charge the variation price.
- Text parsing. Without data-price, the first number in the element is read as the price. Elements that combine several prices ("$20 – $40") need data-price or a more specific selector.
- Nested roots. A price is matched to its closest root only, so a product card inside a product page section isn't confused with the main product.
- Hiding zero values. A compare-at price equal to the new price, and zero savings, are hidden automatically.
- App-rendered prices. Prices rendered by other apps (upsells, bundles, quizzes, cart drawers) need their own selectors and a product ID on their container. Check them with the QA checklist.
Troubleshooting
- The price doesn't change on collection pages → the card root has no product ID. Add data-product-id to the card in your theme, and the card's selector to Root.
- The price changes on the product page but not after switching variants → the variant isn't detectable. Make sure the product form has an [name="id"] input, or add data-variant-id to the root.
- The price shows the wrong number → the element contains several numbers. Add data-price with the original price.
- The original price flashes, then changes → prices are hidden before rewriting only inside roots that carry data-product-id. If the root identifies the product another way (a product-id attribute or class), add data-product-id. If the snippet loads asynchronously, see Performance and flicker.