Documentation Index Fetch the complete documentation index at: https://docs.launchmystore.io/llms.txt
Use this file to discover all available pages before exploring further.
Post-Purchase Extensions
Post-purchase extensions display content on the order confirmation page immediately after a customer completes their purchase. Use them for upsells, surveys, app installations, loyalty program enrollment, and more.
When Post-Purchase Runs
Post-purchase extensions appear between payment completion and the order confirmation page. Customers can skip them if they choose.
Extension Manifest
Register your post-purchase extension in app.json:
{
"handle" : "my-upsell-app" ,
"name" : "Post-Purchase Upsells" ,
"version" : "1.0.0" ,
"extensions" : {
"post_purchase" : [
{
"handle" : "order-upsell" ,
"name" : "Order Upsell" ,
"component_url" : "https://my-app.com/post-purchase/upsell.js"
},
{
"handle" : "survey" ,
"name" : "Customer Survey" ,
"component_url" : "https://my-app.com/post-purchase/survey.js"
}
]
}
}
Creating a Post-Purchase Extension
Post-purchase extensions are React components that receive order data:
import {
usePostPurchase ,
useOrder ,
Button ,
Layout ,
BlockStack ,
Heading ,
Text ,
Image
} from '@launchmystore/post-purchase-ui-extensions-react' ;
export default function OrderUpsell () {
const postPurchase = usePostPurchase ();
const order = useOrder ();
const [ isAdding , setIsAdding ] = useState ( false );
// Get recommended products based on order
const recommendations = useRecommendations ( order . lineItems );
const handleAddToOrder = async ( product ) => {
setIsAdding ( true );
try {
await postPurchase . addToOrder ({
variantId: product . variantId ,
quantity: 1
});
postPurchase . showToast ({
message: ` ${ product . title } added to your order!` ,
type: 'success'
});
} catch ( error ) {
postPurchase . showToast ({
message: 'Failed to add item' ,
type: 'error'
});
} finally {
setIsAdding ( false );
}
};
const handleDecline = () => {
postPurchase . done ();
};
if ( ! recommendations . length ) {
postPurchase . done ();
return null ;
}
return (
< Layout >
< BlockStack spacing = "loose" >
< Heading level = { 1 } > Wait! Special offer just for you </ Heading >
< Text > Add these items to your order with one click: </ Text >
{ recommendations . map (( product ) => (
< div key = { product . id } className = "upsell-product" >
< Image
src = { product . image }
alt = { product . title }
width = { 80 }
height = { 80 }
/>
< div className = "upsell-details" >
< Text weight = "bold" > { product . title } </ Text >
< Text >
< s > $ { product . compareAtPrice } </ s > $ { product . price }
</ Text >
< Text size = "small" color = "subdued" >
{ product . savings } % off - Limited time!
</ Text >
</ div >
< Button
onClick = { () => handleAddToOrder ( product ) }
loading = { isAdding }
>
Add to Order
</ Button >
</ div >
)) }
< Button onClick = { handleDecline } plain >
No thanks, continue to confirmation
</ Button >
</ BlockStack >
</ Layout >
);
}
Post-Purchase Context
Extensions receive detailed order information:
interface PostPurchaseContext {
order : {
id : string ;
orderNumber : string ;
totalPrice : number ;
subtotalPrice : number ;
shippingPrice : number ;
taxPrice : number ;
currency : string ;
lineItems : LineItem [];
shippingAddress : Address ;
billingAddress : Address ;
customer : Customer ;
discountCodes : string [];
};
shop : {
id : string ;
name : string ;
domain : string ;
};
}
interface LineItem {
id : string ;
title : string ;
variantTitle : string ;
quantity : number ;
price : number ;
productId : string ;
variantId : string ;
image : string ;
sku : string ;
}
Post-Purchase API
usePostPurchase Hook
const postPurchase = usePostPurchase ();
// Add item to the order (one-click upsell)
await postPurchase . addToOrder ({
variantId: 'variant_123' ,
quantity: 1 ,
customAttributes: { source: 'post_purchase_upsell' }
});
// Show toast notification
postPurchase . showToast ({
message: 'Added to order!' ,
type: 'success' // 'success' | 'error' | 'info'
});
// Complete post-purchase and continue to confirmation
postPurchase . done ();
// Track analytics event
postPurchase . trackEvent ( 'upsell_viewed' , {
productId: 'prod_123' ,
position: 1
});
useOrder Hook
const order = useOrder ();
console . log ( order . orderNumber ); // "#1234"
console . log ( order . totalPrice ); // 9999 (cents)
console . log ( order . lineItems ); // Array of items
console . log ( order . customer . email ); // "customer@example.com"
useShop Hook
const shop = useShop ();
console . log ( shop . name ); // "My Store"
console . log ( shop . domain ); // "mystore.launchmystore.io"
UI Components
The @launchmystore/post-purchase-ui-extensions-react package includes styled components:
Layout Components
import {
Layout ,
BlockStack ,
InlineStack ,
Divider
} from '@launchmystore/post-purchase-ui-extensions-react' ;
< Layout maxWidth = { 600 } padding = "base" >
< BlockStack spacing = "loose" >
< Heading > Special Offer </ Heading >
< InlineStack spacing = "base" alignment = "center" >
< Image src = { product . image } />
< Text > { product . title } </ Text >
</ InlineStack >
< Divider />
< Button > Add to Order </ Button >
</ BlockStack >
</ Layout >
Typography
import { Heading , Text } from '@launchmystore/post-purchase-ui-extensions-react' ;
< Heading level = { 1 } > Main Heading </ Heading >
< Heading level = { 2 } > Subheading </ Heading >
< Text > Regular text </ Text >
< Text weight = "bold" > Bold text </ Text >
< Text size = "small" > Small text </ Text >
< Text color = "subdued" > Muted text </ Text >
< Text color = "success" > Success text </ Text >
import { Button } from '@launchmystore/post-purchase-ui-extensions-react' ;
< Button onClick = { handleAdd } > Add to Order </ Button >
< Button onClick = { handleAdd } loading > Adding... </ Button >
< Button onClick = { handleDecline } plain > No thanks </ Button >
< Button onClick = { handleRemove } destructive > Remove </ Button >
< Button disabled > Sold Out </ Button >
Images
import { Image } from '@launchmystore/post-purchase-ui-extensions-react' ;
< Image
src = { product . image }
alt = { product . title }
width = { 200 }
height = { 200 }
borderRadius = "base"
/>
Common Use Cases
One-Click Upsells Offer complementary products that can be added instantly
Surveys Ask customers how they heard about you or gather feedback
Loyalty Enrollment Invite customers to join your rewards program
App Promotion Encourage customers to download your mobile app
Example: Customer Survey
import { useState } from 'react' ;
import {
usePostPurchase ,
useOrder ,
Layout ,
BlockStack ,
Heading ,
Text ,
Button ,
RadioGroup ,
TextField
} from '@launchmystore/post-purchase-ui-extensions-react' ;
export default function CustomerSurvey () {
const postPurchase = usePostPurchase ();
const order = useOrder ();
const [ source , setSource ] = useState ( '' );
const [ feedback , setFeedback ] = useState ( '' );
const [ submitting , setSubmitting ] = useState ( false );
const sourceOptions = [
{ value: 'google' , label: 'Google Search' },
{ value: 'social' , label: 'Social Media' },
{ value: 'friend' , label: 'Friend/Family Referral' },
{ value: 'ad' , label: 'Online Advertisement' },
{ value: 'other' , label: 'Other' }
];
const handleSubmit = async () => {
setSubmitting ( true );
try {
// Send survey data to your app
await fetch ( 'https://my-app.com/api/survey' , {
method: 'POST' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ({
orderId: order . id ,
customerId: order . customer . id ,
source ,
feedback
})
});
postPurchase . showToast ({
message: 'Thanks for your feedback!' ,
type: 'success'
});
postPurchase . trackEvent ( 'survey_completed' , { source });
postPurchase . done ();
} catch ( error ) {
postPurchase . showToast ({
message: 'Failed to submit survey' ,
type: 'error'
});
setSubmitting ( false );
}
};
const handleSkip = () => {
postPurchase . trackEvent ( 'survey_skipped' );
postPurchase . done ();
};
return (
< Layout maxWidth = { 500 } padding = "loose" >
< BlockStack spacing = "loose" >
< Heading level = { 1 } > Quick Question </ Heading >
< Text > Help us improve by answering a quick question: </ Text >
< BlockStack spacing = "tight" >
< Text weight = "bold" > How did you hear about us? </ Text >
< RadioGroup
options = { sourceOptions }
value = { source }
onChange = { setSource }
/>
</ BlockStack >
< TextField
label = "Any additional feedback? (Optional)"
value = { feedback }
onChange = { setFeedback }
multiline
maxLength = { 500 }
/>
< Button
onClick = { handleSubmit }
loading = { submitting }
disabled = { ! source }
>
Submit
</ Button >
< Button onClick = { handleSkip } plain >
Skip
</ Button >
</ BlockStack >
</ Layout >
);
}
Example: Loyalty Enrollment
import { useState } from 'react' ;
import {
usePostPurchase ,
useOrder ,
Layout ,
BlockStack ,
InlineStack ,
Heading ,
Text ,
Button ,
Image
} from '@launchmystore/post-purchase-ui-extensions-react' ;
export default function LoyaltyEnrollment () {
const postPurchase = usePostPurchase ();
const order = useOrder ();
const [ enrolling , setEnrolling ] = useState ( false );
// Calculate points earned from this order
const pointsEarned = Math . floor ( order . totalPrice / 100 ); // 1 point per dollar
const handleEnroll = async () => {
setEnrolling ( true );
try {
await fetch ( 'https://my-app.com/api/loyalty/enroll' , {
method: 'POST' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ({
customerId: order . customer . id ,
email: order . customer . email ,
initialPoints: pointsEarned
})
});
postPurchase . showToast ({
message: `Welcome! ${ pointsEarned } points added to your account.` ,
type: 'success'
});
postPurchase . trackEvent ( 'loyalty_enrolled' );
postPurchase . done ();
} catch ( error ) {
postPurchase . showToast ({
message: 'Enrollment failed. Please try again.' ,
type: 'error'
});
setEnrolling ( false );
}
};
return (
< Layout maxWidth = { 500 } padding = "loose" >
< BlockStack spacing = "loose" alignment = "center" >
< Image
src = "https://my-app.com/loyalty-badge.png"
alt = "Rewards"
width = { 80 }
height = { 80 }
/>
< Heading level = { 1 } > Join Our Rewards Program </ Heading >
< Text alignment = "center" >
You just earned < strong > { pointsEarned } points </ strong > from this order!
Join now to start saving on future purchases.
</ Text >
< BlockStack spacing = "tight" >
< InlineStack spacing = "base" alignment = "center" >
< span > ✓ </ span >
< Text > Earn 1 point for every $1 spent </ Text >
</ InlineStack >
< InlineStack spacing = "base" alignment = "center" >
< span > ✓ </ span >
< Text > 100 points = $5 off your next order </ Text >
</ InlineStack >
< InlineStack spacing = "base" alignment = "center" >
< span > ✓ </ span >
< Text > Exclusive member-only discounts </ Text >
</ InlineStack >
</ BlockStack >
< Button onClick = { handleEnroll } loading = { enrolling } >
Join & Claim { pointsEarned } Points
</ Button >
< Button onClick = { () => postPurchase . done () } plain >
Maybe later
</ Button >
</ BlockStack >
</ Layout >
);
}
Best Practices
Customers want to see their confirmation. Make your post-purchase extension quick and valuable.
Offer genuine discounts, useful information, or quick actions. Don’t just show ads.
Provide a clear “No thanks” or “Skip” option. Never trap customers in the post-purchase flow.
If an API call fails, show a friendly message and allow the customer to continue.
Use trackEvent to understand how customers interact with your extension.
Many customers checkout on mobile. Ensure your extension is responsive.
Timing and Display Rules
You can control when your extension appears:
{
"handle" : "order-upsell" ,
"name" : "Order Upsell" ,
"component_url" : "https://my-app.com/post-purchase/upsell.js" ,
"display_rules" : {
"min_order_value" : 2500 ,
"max_order_value" : 50000 ,
"product_types" : [ "clothing" , "accessories" ],
"exclude_discount_orders" : false ,
"customer_tags" : [ "vip" , "repeat" ]
}
}
Rule Description min_order_valueMinimum order value in cents max_order_valueMaximum order value in cents product_typesOnly show for orders containing these product types exclude_discount_ordersHide for orders with discount codes customer_tagsOnly show for customers with these tags
Testing
Test your post-purchase extension using the development mode:
# Start local development server
npm run dev
# In your app settings, set component URL to:
# https://localhost:3000/post-purchase/upsell.js
Use the LaunchMyStore developer tools to simulate different order scenarios.