On this page

A product page can explain a reward without deciding whether a buyer has earned it. That distinction belongs in the component specification before anyone chooses fonts or writes Liquid. The block presents an approved public offer; the backend later evaluates the actual purchase under the applicable campaign rules.

Consider a hypothetical outdoor store selling two versions of a water filter. The compact model has a $10 purchase reward, while the larger model is outside the offer. A block that keeps displaying “$10 reward” after the shopper changes variants creates a false promise even if the eventual award calculation is correct. The implementation therefore needs a precise contract between the selected product, the approved offer and the rendered message.

Choose an eligible theme location and block contract

Shopify provides theme app extensions for adding configurable app content to supported themes. An app block belongs to the theme experience; it does not establish a checkout extension or a reward issuance capability. Shopify theme app extensions

Start by naming the template and section where the merchant needs the information. “Product page” is too broad when a store has different templates for subscriptions, bundles and ordinary products. Record the selected template, whether its section accepts the proposed block, and the position relative to the purchase control. If a required location is unsupported, record that gap before estimating development work.

For the filter example, the initial placement is the main product information section, below the selected variant price and above the purchase control. The merchant can move the block within supported limits. They cannot edit the approved reward amount as arbitrary presentation text, because that would allow the page to diverge from the campaign record.

A useful block contract separates three kinds of configuration:

Configuration Example Who controls its meaning?
Placement Main product section Store theme editor
Presentation Compact or expanded explanation Approved content settings
Offer reference OFFER-FILTER-07 Campaign configuration owner
Terms destination Approved public offer page Content approval process
Data freshness Publication version and validity period Offer publishing service

These names are illustrative application fields, not a RebateCardX schema. Their purpose is to make disagreement visible. A designer can change spacing without gaining permission to change eligibility. A campaign owner can retire an offer without depending on a developer to remove hardcoded text from every template.

Write the block’s negative requirements too. It must not collect card details, approve a recipient, reduce the checkout total or call an issuance operation. Those actions have different authority and data needs. Keeping them outside the component makes a display failure easier to contain.

Bind approved public offer data to the template

The block should consume a deliberately small public representation of the offer. In the example, that representation contains the campaign reference, applicable variant references, approved display text, currency, public terms link and publication version. It does not contain a customer record or a prediction that a particular visitor will qualify.

Use the server’s approved campaign record to produce that representation. Do not let a query string such as reward=50 become the displayed promise. A browser-supplied value can select a candidate reference, but the published offer must still come from the controlled source. This is especially important when marketing teams distribute links through several channels.

The rendering decision can be expressed as original pseudocode:

selected = current_product_and_variant()
public_offer = approved_offer_for(selected, configured_reference)

if public_offer is unavailable:
    show_approved_unavailable_state()
else if public_offer is outside_publication_window:
    hide_reward_amount_and_show_neutral_guidance()
else if selected is not within public_offer.display_scope:
    show_no_offer_for_this_selection()
else:
    render_approved_text(public_offer.version)
    render_approved_terms_link(public_offer.terms_destination)

This is a design sketch, not runnable vendor code. The unavailable state and the no-offer state are intentionally different. The first means the component cannot establish the current offer. The second means a valid public record says the selected item is not covered. A network failure should never masquerade as an eligibility decision.

Escape displayed text and constrain link destinations to approved public pages. Avoid injecting arbitrary HTML returned by an unreviewed integration. If approved content needs rich formatting, define the allowed structure rather than accepting an unlimited block of markup. That choice reduces the range of changes a compromised or mistaken content source could make.

Decide how caching interacts with campaign withdrawal. A long-lived cached page may continue to display an expired promise after the campaign changes. One possible design uses versioned public records plus a short, defined freshness window; another renders the approved state on the server. The right choice depends on the store’s architecture, but the owner must state how quickly a withdrawn offer stops appearing.

There is also a useful distinction between incomplete configuration and temporary source failure. A block without a campaign reference should show a merchant-facing setup indication in the editor and an approved neutral state on the public page. A correctly configured block whose source is temporarily unavailable should preserve enough internal diagnostics to identify that different problem.

Test variant changes and missing-data behavior

Test the decision contract rather than checking only that a banner appears. For the fictional filter store, the acceptance cases are concrete:

Situation Expected visible result Evidence to retain
Compact filter selected Approved $10 offer and terms Screenshot and offer version
Larger filter selected No compact-model reward promise Variant reference and screenshot
Selection changes twice quickly Final selection controls the message Recorded interaction
Offer source cannot be reached Neutral unavailable state Error category without private data
Campaign withdrawn Retired amount does not remain visible Publication change and resulting view
Block lacks configuration Public fallback; editor setup guidance Both viewing contexts

The rapid-change case catches a common asynchronous mistake. A response for the first variant can arrive after the response for the second. The component must bind a response to the selection that requested it and discard stale results. Otherwise the final page can display a perfectly valid offer for the wrong item.

Check the layout with long approved text and a narrow screen. The amount and its material condition should remain understandable together. A visually clipped condition can undermine an otherwise correct data integration. Also test a keyboard-driven selection change so the updated message does not require a pointer interaction to become available.

A second difficult case is a product that uses an alternate template. The main template may pass every test while a campaign landing page uses a different section with no block placement. Record every applicable template in the specification and distinguish “tested and supported” from “not used by this campaign.” The inventory should be specific enough that a future theme change can reuse it.

The completed deliverable is a block specification, not just a screenshot: placement, configuration ownership, public data contract, fallback meanings and observed acceptance results. Once those parts agree, the developer can implement against the actual supported integration without inventing what the browser is allowed to promise.

The handoff should include one filled configuration record from the test store. For example: template product.filter, approved offer OFFER-FILTER-07, compact variant only, version 3, neutral fallback approved by the content owner. Attach the result of the variant-switch test to that record. This gives the next developer something reproducible: they can load the same template, select the same item and compare the expected state. A statement that the block was “tested on mobile” does not establish which campaign or variant the test actually covered.

Request technical access to review supported Shopify storefront integration options.

Request technical access

Source references

Back to contents

General information only

This guide is general information, not financial, legal, tax or regulatory advice. Eligibility, card availability, permitted use and responsibilities depend on the applicable offer and card terms.