# Custom Events Source: https://docs.ollie.shop/ollie-shop/analytics/custom-events Send custom analytics events from your Ollie Shop components to Google Tag Manager While Ollie Shop automatically tracks standard e-commerce events, you may want to track additional user interactions specific to your business. Custom events allow you to measure engagement with promotional banners, loyalty programs, form interactions, and any other checkout elements you've built. ## Real-World Example: VIP Enrollment Imagine you've added a VIP program enrollment option to your checkout. When customers opt-in, you want to track this decision in your analytics to measure program adoption and correlate it with purchase behavior. Here's how a custom component can send a `vip_enrollment` event when a customer joins: ```typescript VipEnrollmentButton.tsx theme={"system"} 'use client' import React from 'react'; import styles from './vipEnrollmentButton.module.css'; export default function VipEnrollmentButton() { const handleEnrollment = () => { window.dataLayer = window.dataLayer || []; window.dataLayer.push({ event: 'vip_enrollment', enrollment_source: 'checkout' }); }; return ( ); } ``` When a customer clicks the button, the `vip_enrollment` event is pushed to the `dataLayer`, where GTM captures it and forwards it to GA4 or any other analytics platform you've configured. You can [enrich this event with session data](/ollie-shop/analytics/gtm-enrichment) using GTM Custom HTML tags—for example, adding customer segment or cart value context. ## How It Works Custom events are sent to Google Tag Manager via the `dataLayer` object—a JavaScript array that GTM uses as a communication layer between your website and tags. ```typescript theme={"system"} window.dataLayer = window.dataLayer || []; window.dataLayer.push({ event: 'your_event_name', // ... additional parameters }); ``` Learn more about the dataLayer in the [GTM dataLayer documentation](https://developers.google.com/tag-platform/tag-manager/datalayer). ## Prerequisites * Ollie Shop [SDK](/ollie-shop/api/index) installed * [Google Tag Manager](/ollie-shop/configuration/integrations) configured in your store * A [custom component](/ollie-shop/customization/custom-component) to add the event tracking ## Implementation Details Add this type declaration at the top of your custom component to get type safety and IDE autocompletion for the `dataLayer`: ```typescript theme={"system"} declare global { interface Window { dataLayer?: Record[]; } } ``` ```typescript VipEnrollmentButton.tsx theme={"system"} 'use client' import React from 'react'; import styles from './styles.module.css'; declare global { interface Window { dataLayer?: Record[]; } } export default function VipEnrollmentButton() { const handleEnrollment = () => { window.dataLayer = window.dataLayer || []; window.dataLayer.push({ event: 'vip_enrollment', enrollment_source: 'checkout' }); }; return ( ); } ``` ## Event Naming Best Practices Follow these conventions to keep your analytics data clean and actionable: | Convention | Example | Description | | ------------------- | -------------------------- | ----------------------------------- | | Use snake\_case | `vip_enrollment` | Consistent with GA4 standard events | | Be descriptive | `shipping_method_selected` | Makes reports easier to understand | | Include context | `checkout_promo_applied` | Helps segment by checkout stage | | Avoid generic names | `button_click` | Too vague for meaningful analysis | Event names in GA4 are case-sensitive and limited to 40 characters. Avoid spaces and special characters. See [GA4 event naming rules](https://support.google.com/analytics/answer/13316687). ## Configuring GTM to Capture Custom Events After pushing events to the `dataLayer`, configure GTM to capture and forward them: 1. Create a **Custom Event Trigger** in GTM matching your event name (e.g., `vip_enrollment`) 2. Create a **GA4 Event Tag** that fires on this trigger 3. Map any custom parameters to GA4 event parameters 4. Test using GTM's Preview mode before publishing Use [GTM's Preview mode](https://support.google.com/tagmanager/answer/6107056) to verify events are being captured correctly before publishing your container. ## Further Reading * [GA4 Custom Events Guide](https://developers.google.com/analytics/devguides/collection/ga4/events) * [GTM dataLayer Documentation](https://developers.google.com/tag-platform/tag-manager/datalayer) * [GA4 Event Naming Rules](https://support.google.com/analytics/answer/13316687) # Device Fingerprint Source: https://docs.ollie.shop/ollie-shop/analytics/device-fingerprint Native anti-fraud device fingerprint compatibility for fraud prevention services Fraud prevention is critical for e-commerce. Device fingerprinting is a technique used by anti-fraud services to identify and analyze the device used for a transaction, helping to assess the risk of fraud. Ollie Shop maintains native compatibility with device fingerprint scripts from your e-commerce platform. ## What is Device Fingerprint? A device fingerprint is a unique identifier generated by collecting non-sensitive data about a user's device and browser. This data helps anti-fraud platforms like **Clearsale**, **Cybersource**, and others to: * Identify the device used in each transaction * Analyze the security level of the device * Detect patterns from previous transactions made with the same device * Flag suspicious behavior that may indicate fraud Device fingerprinting collects non-sensitive technical data such as browser type, screen resolution, installed fonts, and time zone. It does not collect personal information. ## How It Works with Ollie Shop When using Ollie Shop, your e-commerce platform's device fingerprint scripts continue to work seamlessly. Ollie Shop maintains the expected global variables and interfaces that these scripts rely on. ## Platform Compatibility For VTEX stores, Ollie Shop creates and maintains the standard `window.vtex.deviceFingerprint` field. This field can be populated exactly as it would be in a native VTEX checkout. ```javascript theme={"system"} // The deviceFingerprint field is available at: window.vtex.deviceFingerprint ``` Your existing VTEX anti-fraud configuration will work automatically. No additional setup is required in Ollie Shop.
Coming Soon
Shopify device fingerprint compatibility is currently in development. Contact our team for updates on availability.
## Integration with Anti-Fraud Services Device fingerprint data is automatically included in the payment processing flow. When a transaction is submitted: 1. The anti-fraud script collects device data and generates a fingerprint 2. The fingerprint is stored in the platform's expected location (e.g., `window.vtex.deviceFingerprint`) 3. Ollie Shop includes this fingerprint when processing the payment 4. Your anti-fraud provider receives the fingerprint for risk analysis ## Loading Anti-Fraud Scripts If your anti-fraud provider requires manual script loading, you have two options: Create a [custom component](/ollie-shop/customization/custom-component) (e.g., a pixel component) that loads the anti-fraud script when the checkout renders: ```typescript AntifraudPixel.tsx theme={"system"} 'use client' import { useEffect } from 'react'; export default function AntifraudPixel() { useEffect(() => { const script = document.createElement('script'); script.src = 'https://your-antifraud-provider.com/fingerprint.js'; script.async = true; document.body.appendChild(script); return () => { document.body.removeChild(script); }; }, []); return null; } ``` Load the script via a [GTM Custom HTML tag](/ollie-shop/analytics/gtm-enrichment) that fires on checkout page load: ```html theme={"system"} ``` Configure the trigger to fire on **Page View** or a custom checkout event. ## Troubleshooting If device fingerprinting isn't working as expected: 1. **Verify script loading** — Check that your anti-fraud provider's script is loading in the checkout 2. **Check the global variable** — Confirm the fingerprint value is being set (e.g., `console.log(window.vtex.deviceFingerprint)`) 3. **Review provider configuration** — Ensure your anti-fraud provider is correctly configured in your e-commerce platform 4. **Contact support** — If issues persist, reach out to both your anti-fraud provider and Ollie Shop support ## Further Reading * [VTEX Anti-fraud Documentation](https://help.vtex.com/docs/tutorials/what-is-anti-fraud) # Enriching Events with GTM Source: https://docs.ollie.shop/ollie-shop/analytics/gtm-enrichment Access checkout session context to enrich analytics events using Google Tag Manager Custom HTML tags Sometimes the standard event data isn't enough. You may want to enrich your analytics events with additional context from the checkout session—such as whether the user is a VIP member, their loyalty tier, or platform-specific data. Ollie Shop exposes session context through global objects that you can access directly from GTM. ## Real-World Example: Enriching VIP Enrollment In the [Custom Events](/ollie-shop/analytics/custom-events) guide, we created a `vip_enrollment` event that fires when a customer joins your VIP program. Now let's enrich that event with additional context from the checkout session. Using a GTM Custom HTML tag, you can add the customer's VIP status from your platform's session data: ```html theme={"system"} ``` ```html theme={"system"} ``` The `vipEnrollment` field is available in the VTEX session when the customer has opted into your VIP program during checkout. ## Available Session Objects Ollie Shop exposes two global objects with checkout session data. For a complete reference with full examples, see the [Session](/ollie-shop/concepts/session) documentation. | Object | Description | | --------------------------------- | ------------------------------------------ | | `window.__CHECKOUT_SESSION__` | Ollie Shop's normalized session data | | `window.__RAW_CHECKOUT_SESSION__` | Raw platform session (VTEX, Shopify, etc.) | ## Common Use Cases ### User Segmentation Enrich events with user attributes for better segmentation in analytics: ```html theme={"system"} ``` ### Platform-Specific Data Access raw platform data when you need fields not available in the normalized session: ```html theme={"system"} ``` ## Setting Up in GTM In GTM, go to **Tags > New > Tag Configuration > Custom HTML**. Paste your enrichment script. Configure the tag to fire on the appropriate trigger—for the VIP enrollment example, use a Custom Event trigger matching `vip_enrollment`. Use [GTM Preview mode](https://support.google.com/tagmanager/answer/6107056) to verify your enriched events are pushing correctly to the `dataLayer`. Once verified, publish your GTM container to apply changes to your live checkout. ## Best Practices * **Always use fallbacks** — Use `|| {}` and `|| false` to prevent errors if session objects aren't loaded yet * **Keep scripts lightweight** — GTM Custom HTML runs synchronously; complex logic can impact checkout performance * **Use descriptive event names** — Suffix enriched events (e.g., `*_enriched`) to distinguish them from the original events * **Test thoroughly** — Session data availability may vary depending on checkout stage ## Further Reading * [Session Objects Reference](/ollie-shop/concepts/session) — Full session structure and examples * [useCheckoutSession Hook](/ollie-shop/api/useCheckoutSession) — Access session data in components * [GTM Custom HTML Tags](https://support.google.com/tagmanager/answer/6107167) * [GTM Preview Mode](https://support.google.com/tagmanager/answer/6107056) # Native Checkout Events Source: https://docs.ollie.shop/ollie-shop/analytics/index Track checkout events with native Google Analytics 4 e-commerce integration via Google Tag Manager Understanding how customers interact with your checkout is essential for optimizing conversion rates. Ollie Shop natively implements [Google Analytics 4 e-commerce events](https://developers.google.com/analytics/devguides/collection/ga4/ecommerce), giving you complete visibility into your checkout funnel without writing any additional code. ## How It Works When you configure your Google Tag Manager container in your store's [Integrations](/ollie-shop/configuration/integrations), Ollie Shop automatically sends standardized e-commerce events to the `dataLayer`. These events follow Google's recommended schema, ensuring seamless integration with GA4 and other analytics platforms. Only a GTM container ID is required. Ollie Shop handles all event formatting and dispatching automatically. ## Native Events The following e-commerce events are automatically tracked throughout the checkout journey: | Event | Description | When It Fires | | ------------------- | ------------------------------------- | ------------------------------- | | `view_cart` | User views their shopping cart | Cart page is displayed | | `begin_checkout` | User initiates the checkout process | Checkout flow starts | | `add_to_cart` | Item is added to the cart | Product added during checkout | | `remove_from_cart` | Item is removed from the cart | Product removed during checkout | | `add_shipping_info` | User submits shipping information | Shipping step completed | | `add_payment_info` | User submits payment information | Payment step completed | | `purchase` | Transaction is successfully completed | Order confirmation | All events include the standard GA4 e-commerce parameters such as `currency`, `value`, and `items` array with product details. See [Google's GA4 event reference](https://developers.google.com/analytics/devguides/collection/ga4/reference/events) for the complete parameter specifications. ## Prerequisites Before events are tracked, ensure you have: 1. A [Google Tag Manager](https://tagmanager.google.com/) container configured 2. The GTM container ID added to your store's [Integrations](/ollie-shop/configuration/integrations) 3. GA4 tags configured in GTM to receive the e-commerce events ## What's Next Send custom analytics events from your components Add session context to events using GTM Custom HTML Anti-fraud device fingerprint compatibility Configure your GTM container ID ## Further Reading * [Google Analytics 4 E-commerce Implementation](https://developers.google.com/analytics/devguides/collection/ga4/ecommerce) * [GA4 Event Reference](https://developers.google.com/analytics/devguides/collection/ga4/reference/events) * [Google Tag Manager Documentation](https://developers.google.com/tag-platform/tag-manager) # CheckoutSession Type Source: https://docs.ollie.shop/ollie-shop/api/CheckoutSession The `CheckoutSession` is the core interface representing a checkout session in the Ollie Shop ecosystem. It contains all the necessary data to render and process a typical checkout flow, including cart items, customer information, shipping details, payment methods, and totals. **Let your agent build it.** The Ollie Shop skill ships with projects created by `npx create-ollie-shop` and knows this interface, including which fields can be absent and need a defensive read. ```text title="Prompt" theme={"system"} Read the selected delivery address from the session and show it in a component. ``` Don't have the skill yet? [Install it](/ollie-shop/skills). ## **Structure Overview** ```typescript theme={"system"} interface CheckoutSession> { id: string; cartItems: CartItem[]; customer?: CustomerData; shipping?: ShippingInfo; payment?: PaymentInfo; campaign?: Campaign; locale: LocaleInfo; taxes?: TaxLine[]; totals: Totals; user: User; readOnly: boolean; extensions?: Extensions; } ``` ## **Properties** ### `id` **Type:** `string`\ **Description:** A unique identifier for the checkout session. This is a platform-specific ID. ### `cartItems` **Type:** `CartItem[]`\ **Description:** An array of items in the user's cart. Each item contains pricing information, availability, and other product information. Each cart item includes: * `id`: Unique identifier for the cart item (e.g., SKU code) * `sellerId`: (Optional) Identifier for the marketplace seller providing the item * `name`: Display name of the item * `price`: Current (sale) price in minor units (e.g., cents) * `originalPrice`: Original (non-sale) price in minor units * `quantity`: Number of this item in the cart * `available`: Whether the item is in stock * `index`: Position index in the cart * `image`: URL for the item's image * `url`: (Optional) URL to the product details * `variantDetails`: (Optional) Object containing variant information (e.g., color, size) ### `customer` **Type:** `CustomerData` (optional)\ **Description:** Information about the customer for order fulfillment, which may include: * `id`: Platform's unique identifier for the customer * `email`: Customer's email address * `firstName`: Customer's first name * `lastName`: Customer's last name * `document`: Customer's document or tax ID (e.g., CPF in Brazil) * `phone`: Customer's phone number * `addresses`: List of customer's addresses ### `Address` **Type:** Base address interface \ **Description:** The core address structure used across the checkout system: * `id`: Optional unique identifier for saved addresses * `type`: Optional address type ("home", "billing", "work", "pick\_up", "other") * `street`: Optional street name * `number`: Optional street number * `complement`: Optional address complement/apartment number * `reference`: Optional delivery reference * `neighborhood`: Optional neighborhood or district * `city`: Optional city name * `country`: Required country code (e.g., "USA", "BRA") * `stateOrProvince`: Optional state or province * `postalCode`: Required postal code ### `CustomerAddress` **Type:** `CustomerAddress extends Address` \ **Description:** Addresses associated with a customer account, with additional fields: * `selected`: Whether this address is currently selected * `receiverName`: Optional name of person receiving deliveries ### `shipping` **Type:** `ShippingInfo` (optional)\ **Description:** Comprehensive shipping information including: * `addresses`: List of shipping addresses available for selection * `packages`: List of shipping packages the user has selected * `availableQuotes`: List of shipping options available for user selection * `availableCountries`: List of country codes available for shipping ### `ShippingAddress` **Type:** `ShippingAddress extends Address` \ **Description:** Used specifically for shipping destinations, with additional field: * `receiverName`: Optional name of person receiving the package #### **Shipping Packages** Each `ShippingPackage` \ contains: * `id`: Unique identifier for the shipping package * `items`: List of cart item indexes included in this package * `carrier`: Name of the shipping carrier (e.g., "FedEx", "UPS") * `method`: Carrier's shipping method (e.g., "Standard", "Express") * `estimatedDeliveryTime`: Object containing: * `value`: Numerical value of the estimated delivery time * `unit`: Unit of time (e.g., "day", "hour", "week") as Intl.RelativeTimeFormatUnit * `price`: Cost of shipping this package in minor units * `addressId`: ID of the shipping address for this package * `type`: Type of shipping: "delivery" or "pick\_up" * `storeName`: Optional name of store for pickup packages * `timeSlot`: Optional time slot selection with: * `id`: Unique identifier for the time slot * `originalPrice`: Original price for this time slot * `price`: Current price for this time slot * `startDate`: Start date and time in ISO 8601 format * `endDate`: End date and time in ISO 8601 format #### **Shipping Quotes** Each `ShippingQuote` (as either `DeliveryQuote` or `PickUpQuote`) contains: * `id`: Unique identifier for the shipping quote * `carrier`: Name of the shipping carrier * `name`: Display name of the shipping method * `estimatedDeliveryTime`: Object containing: * `value`: Numerical value of the estimated delivery time * `unit`: Unit of time (e.g., "day", "hour", "week") as Intl.RelativeTimeFormatUnit * `availableItems`: List of cart item indexes this quote applies to * `price`: Cost of this shipping option in minor units * `timeSlots`: Array of available delivery/pickup time slots, each containing: * `id`: Unique identifier for the time slot * `originalPrice`: Original price for this time slot * `price`: Current price for this time slot * `startDate`: Start date and time in ISO 8601 format * `endDate`: End date and time in ISO 8601 format * `type`: Either "delivery" or "pick\_up" * For pickup quotes: additional `pickUpInfo` containing: * `name`: Name of the pickup location/store * `address`: Full address object containing all standard address fields ### `payment` **Type:** `PaymentInfo` (optional)\ **Description:** Payment details including: * `availableMethods`: All payment methods available (credit card, PayPal, etc.) * `selectedPayments`: Payment method(s) selected by the user * `total`: Total amount to be paid #### **Payment Methods** Each `PaymentMethod` contains: * `id`: Unique identifier for the payment method * `type`: Payment method type (e.g., "credit\_card", "debit\_card", "paypal") * `name`: Display name of the payment method (e.g., "Visa", "PayPal") * `installments`: Optional array of available payment installment options, each containing: * `number`: Number of installments (e.g., 1, 3, 6) * `amount`: Amount of each installment in minor units * `total`: Total amount across all installments in minor units * `interestRate`: Optional interest rate percentage for this installment plan #### **Selected Payments** Each `SelectedPayment` contains: * `methodId`: ID of the chosen payment method (matching [PaymentMethod.id](http://PaymentMethod.id)) * `referenceValue`: Base amount for this payment, typically the sub-total * `total`: Total amount being paid with this payment method in minor units * `installments`: Optional number of installments chosen for this payment ### `campaign` **Type:** `Campaign` (optional)\ **Description:** Marketing or merchandising campaign information: * `coupons`: Array of coupon codes applied by the user * `promotions`: Array of promotions, each containing: * `id`: Unique identifier for the promotion * `name`: Optional display name or description * `discountValue`: Optional total discount amount in minor units ### `locale` **Type:** `LocaleInfo`\ **Description:** Regional settings for the checkout: * `currency`: ISO 4217 currency code (e.g., "USD", "BRL") * `language`: Language code (e.g., "en", "pt-BR") * `country`: Country code in ISO 3166-1 alpha-3 format (e.g., "USA", "BRA") ### `taxes` **Type:** `TaxLine[]` (optional)\ **Description:** Detailed breakdown of tax lines, each containing: * `name`: Name or code of the tax (e.g., "VAT", "State Tax") * `value`: Amount of this tax in minor units ### `totals` **Type:** `Totals`\ **Description:** Comprehensive breakdown of order costs: * `items`: Total cost of items in the cart * `shipping`: (Optional) Total shipping cost * `tax`: (Optional) Total tax amount * `discounts`: (Optional) Total discount amount * `interest`: (Optional) Total interest amount (e.g., from installments) * `total`: Grand total for the checkout ### `user` **Type:** `User`\ **Description:** Information about who is operating the checkout session: * `id`: Identifier for the user (customer ID or operator ID) * `role`: Role of the user: * `"user"`: The end customer themselves * `"operator"`: A third party acting on behalf of the customer * `isGuest`: Whether the user is not logged in ### `readOnly` **Type:** `boolean`\ **Description:** Indicates if the checkout session is locked from further modification. This could occur when a user was identified but not logged in. ### `extensions` **Type:** `Extensions` (generic parameter, optional)\ **Description:** An extension point where clients can add custom fields for platform-specific or business-specific needs. ## **Usage Examples** ### **Checking if a session is valid for checkout** ```typescript theme={"system"} function CanProceedToCheckout() { const { session } = useCheckoutSession(); // Check if we have the minimum required data if (!session.shipping?.addresses?.length) { return

Please add a shipping address

; } if (!session.payment?.selectedPayments?.length) { return

Please select a payment method

; } return ; } ``` ### **Displaying cart totals** ```typescript theme={"system"} function CartSummary() { const { session } = useCheckoutSession(); const { totals, locale } = session; return (
Items: {formatCurrency(totals.items, locale.currency)}
{totals.shipping !== undefined && (
Shipping: {formatCurrency(totals.shipping, locale.currency)}
)} {totals.discounts !== undefined && (
Discounts: -{formatCurrency(totals.discounts, locale.currency)}
)}
Total: {formatCurrency(totals.total, locale.currency)}
); } ``` ### **Handling multi-package shipping** ```typescript theme={"system"} function ShippingPackages() { const { session } = useCheckoutSession(); const packages = session.shipping?.packages || []; return (

Your Shipments

{packages.map(pkg => (
Carrier: {pkg.carrier}
Method: {pkg.method}
Price: {formatCurrency(pkg.price, session.locale.currency)}
{pkg.estimatedDeliveryTime && (
Estimated delivery: {pkg.estimatedDeliveryTime.value} {pkg.estimatedDeliveryTime.unit}
)}
))}
); } ``` ## **Related Types** The `CheckoutSession` interface works with several other types: * `CartItem` - Information about items in the cart * `CustomerData` - Customer details * `ShippingInfo` - Shipping details and options * `PaymentInfo` - Payment methods and selections * `Campaign` - Promotions and coupons * `LocaleInfo` - Regional settings * `Totals` - Cost breakdown * `User` - Information about session operator # Checkout Order Types Source: https://docs.ollie.shop/ollie-shop/api/checkout-order-types Type definitions for the order data returned by [useCheckoutOrder](/ollie-shop/api/use-checkout-order). **Let your agent build it.** The Ollie Shop skill ships with projects created by `npx create-ollie-shop`, so you can name the field you want instead of tracing it through these types. ```text title="Prompt" theme={"system"} Show the payment method and installments from the completed order. ``` Don't have the skill yet? [Install it](/ollie-shop/skills). *** ## CheckoutOrder The main order object returned after checkout completion. | Property | Type | Description | | ------------------- | --------------------- | ------------------------------- | | `id` | `string` | Unique identifier for the order | | `sessionId` | `string \| undefined` | Associated checkout session ID | | `fulfillmentOrders` | `FulfillmentOrder[]` | Array of fulfillment orders | *** ## FulfillmentOrder Represents a single fulfillment order containing items, customer data, shipping, payment, and totals. | Property | Type | Description | | ------------ | -------------------------------------- | ------------------------------------------- | | `id` | `string` | Unique identifier for the fulfillment order | | `status` | `OrderStatus` | Current status of the order | | `orderItems` | `OrderItem[]` | Items included in this fulfillment | | `customer` | `OrderCustomer` | Customer information | | `shipping` | `OrderShipping` | Shipping addresses and packages | | `payment` | `OrderPayment` | Payment details | | `campaign` | `Campaign` | Applied coupons and promotions | | `taxes` | `TaxLine[]` | Tax breakdown | | `totals` | `Totals` | Order totals | | `locale` | `LocaleInfo` | Currency and language information | | `createdAt` | `string` | Timestamp when the order was created | | `extensions` | `Record \| undefined` | Custom platform-specific fields | *** ## OrderItem A single item in the order. | Property | Type | Description | | ---------------- | ------------------------------------- | ---------------------------------------- | | `id` | `string` | Unique identifier (e.g., SKU code) | | `sellerId` | `string \| undefined` | Marketplace seller ID | | `name` | `string` | Display name | | `variant` | `string \| undefined` | Variant name (e.g., "Size Large", "Red") | | `brand` | `string \| undefined` | Brand name | | `category` | `string \| undefined` | Product category | | `price` | `number` | Current price in minor units (cents) | | `originalPrice` | `number` | Original price in minor units | | `quantity` | `number` | Quantity ordered | | `index` | `number` | Item index | | `image` | `string` | Image URL | | `uniqueId` | `string` | Unique item ID | | `url` | `string \| undefined` | Product details URL | | `variantDetails` | `Record \| undefined` | Variant details (color, size, etc.) | *** ## OrderCustomer Customer information associated with the order. | Property | Type | Description | | ----------- | --------------------- | ------------------------------ | | `id` | `string \| undefined` | Customer ID | | `email` | `string` | Customer email (required) | | `firstName` | `string` | First name (required) | | `lastName` | `string` | Last name (required) | | `phone` | `string` | Phone number (required) | | `document` | `string \| undefined` | Tax ID or document (e.g., CPF) | *** ## OrderShipping Shipping information for the order. | Property | Type | Description | | ----------- | ------------------- | -------------------------- | | `addresses` | `ShippingAddress[]` | List of shipping addresses | | `packages` | `ShippingPackage[]` | Shipping packages | ### ShippingAddress | Property | Type | Description | | ----------------- | -------------------------- | --------------------------------- | | `id` | `string \| undefined` | Address ID | | `type` | `AddressType \| undefined` | Type of address | | `street` | `string \| undefined` | Street address | | `number` | `string \| undefined` | Street number | | `complement` | `string \| undefined` | Additional address info | | `reference` | `string \| undefined` | Reference landmark | | `neighborhood` | `string \| undefined` | Neighborhood or district | | `city` | `string \| undefined` | City | | `country` | `string` | Country code (e.g., "USA", "BRA") | | `stateOrProvince` | `string \| undefined` | State or province | | `postalCode` | `string` | Postal/zip code | | `receiverName` | `string \| undefined` | Recipient name | ### ShippingPackage | Property | Type | Description | | ----------------------- | ------------------------------------ | --------------------------------- | | `id` | `string` | Package ID | | `items` | `number[]` | Cart item indexes in this package | | `carrier` | `string` | Carrier name (e.g., "FedEx") | | `method` | `string` | Shipping method (e.g., "Express") | | `vendor` | `string \| undefined` | Package vendor | | `estimatedDeliveryTime` | `EstimatedDeliveryTime \| undefined` | Delivery estimate | | `price` | `number` | Shipping price in minor units | | `addressId` | `string` | Associated address ID | | `type` | `"delivery" \| "pick_up"` | Delivery or pickup | | `storeName` | `string \| undefined` | Store name for pickups | ### EstimatedDeliveryTime | Property | Type | Description | | -------- | ----------------------------- | ------------------------------- | | `value` | `number` | Numerical value | | `unit` | `Intl.RelativeTimeFormatUnit` | Time unit (e.g., "day", "hour") | *** ## OrderPayment Payment information for the order. | Property | Type | Description | | ---------- | ------------------------ | --------------------- | | `payments` | `SelectedPaymentOrder[]` | List of payments used | ### SelectedPaymentOrder | Property | Type | Description | | ------------------ | --------------------- | --------------------------------- | | `id` | `string` | Payment ID | | `methodId` | `string` | Payment method ID | | `name` | `string` | Payment method display name | | `type` | `string` | Payment type (e.g., "creditCard") | | `referenceValue` | `number` | Base amount for this payment | | `total` | `number` | Total amount paid | | `installments` | `number \| undefined` | Number of installments | | `savedCardId` | `string \| null` | Saved card ID if applicable | | `lastDigits` | `string \| null` | Last digits of card | | `paymentSessionId` | `string \| undefined` | Payment session ID | *** ## Campaign Marketing campaign data with coupons and promotions. | Property | Type | Description | | ------------ | ------------- | -------------------- | | `coupons` | `string[]` | Applied coupon codes | | `promotions` | `Promotion[]` | Applied promotions | ### Promotion | Property | Type | Description | | --------------- | --------------------- | ------------------------------ | | `id` | `string` | Promotion ID | | `name` | `string \| undefined` | Display name | | `discountValue` | `number \| undefined` | Discount amount in minor units | *** ## TaxLine A single tax applied to the order. | Property | Type | Description | | -------- | -------- | ----------------------------------- | | `name` | `string` | Tax name (e.g., "VAT", "State Tax") | | `value` | `number` | Tax amount in minor units | *** ## Totals Order totals breakdown. All values in minor units (cents). | Property | Type | Description | | ----------- | --------------------- | -------------------------- | | `items` | `number` | Total cost of items | | `shipping` | `number` | Total shipping cost | | `tax` | `number \| undefined` | Total tax | | `discounts` | `number \| undefined` | Total discounts | | `giftCard` | `number \| undefined` | Gift card amount applied | | `interest` | `number \| undefined` | Interest from installments | | `change` | `number \| undefined` | Change amount | | `total` | `number` | Grand total | *** ## LocaleInfo Locale and currency information. | Property | Type | Description | | ---------- | -------- | ------------------------------------ | | `currency` | `string` | ISO 4217 currency code (e.g., "USD") | | `language` | `string` | Language code (e.g., "en", "pt-BR") | | `country` | `string` | Country code in ISO 3166-1 alpha-3 | *** ## OrderStatus Possible order status values: | Value | Description | | ------------ | ---------------------------------- | | `"waiting"` | Order is waiting to be processed | | `"approved"` | Order has been approved | | `"pending"` | Order is pending confirmation | | `"canceled"` | Order has been canceled | | `"ready"` | Order is ready for pickup/delivery | | `"other"` | Other status | *** ## AddressType Possible address type values: | Value | Description | | ----------- | --------------- | | `"home"` | Home address | | `"billing"` | Billing address | | `"work"` | Work address | | `"pick_up"` | Pickup location | | `"search"` | Search address | | `"other"` | Other type | # SDK Reference Source: https://docs.ollie.shop/ollie-shop/api/index Essential React hooks for accessing checkout data and building dynamic components that respond to customer actions The SDK provides React hooks that give you real-time access to cart data, payment methods, shipping options, and store configuration. **Ask your agent.** The Ollie Shop skill ships with projects created by `npx create-ollie-shop` and covers every hook on this page, so you can describe the goal instead of picking the hook yourself. ```text title="Prompt" theme={"system"} Which hook should I use to read the selected shipping method? ``` Don't have the skill yet? [Install it](/ollie-shop/skills). ## Hooks **Problem:** Need access to cart contents and customer information ```typescript useCheckoutSession Hook theme={"system"} import { useCheckoutSession, useCheckoutAction } from '@ollie-shop/sdk'; export default function CartSummary() { const { session } = useCheckoutSession(); const { execute: executeRemoveItems } = useCheckoutAction("REMOVE_ITEMS"); const { currency, language } = session.locale; // Format price utility function const formatPrice = (price: number) => { return new Intl.NumberFormat(language, { style: "currency", currency: currency, }).format(price / 100); }; return (

Hello {session.customer?.firstName}!

Items: {session.cartItems.length}

Total: {formatPrice(session.totals.items || 0)}

{session.cartItems.map((item) => (
{item.name} ({formatPrice(item.price)})
))}
); } ``` **What you get:** * Session data (cart items, customer profile, totals) * Locale information (currency, language) * Access to raw session data from e-commerce provider * Real-time updates when session changes
**Problem:** Need access to store theme and settings ```typescript useStoreInfo Hook theme={"system"} import { useStoreInfo } from '@ollie-shop/sdk'; export default function ThemedComponent() { const { platformStoreId, logo, theme, props } = useStoreInfo(); // `theme` is a flat record of CSS-variable-style tokens // (Record), not a nested object. return (

{platformStoreId}

{logo && Store logo} {props?.flags?.showCouponCodeInputOpened && (

Coupon input is opened by default

)}
); } ``` **What you get:** * Store metadata (`storeId`, `platformStoreId`, `logo`, `versionId`, `template`) * Theme tokens (`theme` as a flat `Record`) * Feature flags and configuration via `props` and `settings` * The injected custom `components` for this store
**Problem:** Need access to session data, provider data and to validate required fields ```typescript useStoreInfo Hook theme={"system"} import { useCheckoutSession } from '@ollie-shop/sdk'; export const function PageShipping { const { sessionValidity } = useCheckoutSession(); // Extract address validation errors if they exist const missingAddressFields = sessionValidity && "errors" in sessionValidity ? sessionValidity.errors?.shipping?.addresses : undefined; // Component rendering... return (
{}}>
) } ``` **What you get:** * Raw data from the e-commerce provider * Ollie Session data * Validate required fields
# useCheckoutOrder Source: https://docs.ollie.shop/ollie-shop/api/use-checkout-order Use this hook when you need to access order data after checkout completion. It's useful for building custom order confirmation components. **Let your agent build it.** The Ollie Shop skill ships with projects created by `npx create-ollie-shop` and knows this hook only resolves on the order confirmation route. ```text title="Prompt" theme={"system"} Build a custom order confirmation component. ``` Don't have the skill yet? [Install it](/ollie-shop/skills). ## **Import** ```typescript theme={"system"} import { useCheckoutOrder } from '@ollie-shop/sdk'; ``` ## **Return Value** | Property | Type | Description | | -------- | --------------- | --------------------------------------------------------------------- | | `order` | `CheckoutOrder` | Normalized order data containing id, sessionId, and fulfillmentOrders | For detailed type definitions including `FulfillmentOrder`, `OrderItem`, `OrderCustomer`, and more, see the [Checkout Order Types](/ollie-shop/api/checkout-order-types) reference. ## **Usage** ```typescript theme={"system"} const { order } = useCheckoutOrder(); console.log(order.id); // Order ID console.log(order.fulfillmentOrders); // Fulfillment details ``` ## **Example** Display an order summary on a custom order page. ```typescript theme={"system"} import { useCheckoutOrder } from '@ollie-shop/sdk'; import styles from './styles.module.css'; function ThankYouPage() { const { order } = useCheckoutOrder(); const fulfillment = order.fulfillmentOrders[0]; const { customer, totals, orderItems } = fulfillment; function formatCurrency(value: number, currency: string) { return new Intl.NumberFormat('en-US', { style: 'currency', currency, }).format(value / 100); } return (

Thank you, {customer.firstName}!

Your order #{order.id} has been placed.

Order Summary

    {orderItems.map((item) => (
  • {item.name} x {item.quantity}
  • ))}

Total: {formatCurrency(totals.total, fulfillment.locale.currency)}

); } ```
```css theme={"system"} .container { max-width: 600px; margin: 0 auto; padding: 24px; } .title { font-size: 24px; font-weight: 600; margin-bottom: 8px; } .orderId { color: #666; margin-bottom: 24px; } .subtitle { font-size: 18px; font-weight: 600; margin-bottom: 12px; } .itemList { list-style: none; padding: 0; margin: 0 0 24px 0; } .item { padding: 8px 0; border-bottom: 1px solid #eee; } .total { font-size: 18px; font-weight: 600; } ```
## **Notes** * This hook is only available on the order confirmation page (after successful checkout) * See [Checkout Order Types](/ollie-shop/api/checkout-order-types) for complete type definitions # useLogin Source: https://docs.ollie.shop/ollie-shop/api/use-login Use this hook when you need to control the login modal programmatically. It's useful for protected actions that require authentication, like adding items to a wishlist or accessing account-specific features. **Let your agent build it.** The Ollie Shop skill ships with projects created by `npx create-ollie-shop` and knows the template already renders the modal, so your component only decides when it opens. ```text title="Prompt" theme={"system"} Require login before my custom action runs. ``` Don't have the skill yet? [Install it](/ollie-shop/skills). ## **Import** ```typescript theme={"system"} import { useLogin } from '@ollie-shop/sdk'; ``` ## **Return Value** | Property | Type | Description | | ------------ | -------------------------------------- | ------------------------------------------------- | | `openLogin` | `(options?: OpenLoginOptions) => void` | Opens the login modal with optional configuration | | `closeLogin` | `() => void` | Closes the login modal | ### OpenLoginOptions | Property | Type | Default | Description | | ------------ | --------- | ------- | -------------------------------------------------------------------------- | | `isRequired` | `boolean` | `false` | When `true`, prevents the modal from being closed by clicking the backdrop | | `title` | `string` | `null` | Custom title to display in the login modal header | ## **Usage** ```typescript theme={"system"} const { openLogin, closeLogin } = useLogin(); // Open with default settings openLogin(); // Open with custom title openLogin({ title: "Sign in to continue" }); // Open as required (can't dismiss by clicking backdrop) openLogin({ isRequired: true, title: "Login required" }); // Close programmatically closeLogin(); ``` ## **Example** A favorites button that prompts the user to log in before adding an item to their wishlist. ```typescript theme={"system"} import { useLogin, useCheckoutSession } from '@ollie-shop/sdk'; import styles from './styles.module.css'; function FavoriteButton({ productId }: { productId: string }) { const { openLogin } = useLogin(); const { session: { user } } = useCheckoutSession(); const handleFavorite = () => { if (user.isGuest) { openLogin({ isRequired: true, title: "Sign in to save favorites" }); return; } // User is logged in, add to favorites addToFavorites(productId); }; return ( ); } ``` ```css theme={"system"} .button { display: inline-flex; align-items: center; gap: 8px; padding: 12px 24px; background-color: #556AEB; color: white; border: none; border-radius: 8px; font-size: 14px; font-weight: 500; cursor: pointer; transition: background-color 0.2s; } .button:hover { background-color: #4458d1; } ``` ## **Related** * [Ollie Login Configuration](/ollie-shop/configuration/ollie-login) — Enable or disable the native login modal in the Admin * [Login Required](/ollie-shop/configuration/login-required) — Configure guest access settings for cart and checkout * [useCheckoutSession](/ollie-shop/api/useCheckoutSession) — Access customer information and session state # usePendingActions Source: https://docs.ollie.shop/ollie-shop/api/use-pending-actions Use this hook when you need to track ongoing checkout actions and show loading states in your UI. It's useful for disabling buttons, showing spinners, or preventing user interactions while the checkout is processing. **Let your agent build it.** The Ollie Shop skill ships with projects created by `npx create-ollie-shop` and knows which action types to watch for a given piece of UI. ```text title="Prompt" theme={"system"} Disable my button while the cart is updating. ``` Don't have the skill yet? [Install it](/ollie-shop/skills). ## **Import** ```typescript theme={"system"} import { usePendingActions } from '@ollie-shop/sdk'; ``` ## **Return Value** | Property | Type | Description | | ---------------------------- | ------------------------------------------------- | ------------------------------------------------------------ | | `hasPendingActions` | `boolean` | Whether there are any checkout actions currently in progress | | `pendingActions` | `ActionType[]` | Array of action types currently being processed | | `addActionNameForLoading` | `(action: ActionType, isEarly?: boolean) => void` | Adds an action to the pending list | | `removeActionNameForLoading` | `(action: ActionType) => void` | Removes an action from the pending list | ### ActionType Values The `pendingActions` array can contain any of these action types: | ActionType | Description | | ----------------------------- | ----------------------------- | | `ADD_ITEMS` | Adding items to cart | | `REMOVE_ITEMS` | Removing items from cart | | `UPDATE_ITEMS_QUANTITY` | Updating item quantities | | `UPDATE_COUPONS` | Applying or removing coupons | | `UPDATE_SHIPPING_PACKAGES` | Selecting shipping options | | `UPDATE_SHIPPING_ADDRESSES` | Updating shipping address | | `UPDATE_PAYMENT_METHODS` | Selecting payment methods | | `UPDATE_GIFT_CARDS` | Applying gift cards | | `UPDATE_CUSTOMER_DETAILS` | Updating customer information | | `UPDATE_CUSTOMER_PREFERENCES` | Updating customer preferences | ## **Usage** ```typescript theme={"system"} const { hasPendingActions, pendingActions } = usePendingActions(); // Simple check for any pending action if (hasPendingActions) { // Show loading state } // Check for specific actions const isUpdatingCart = pendingActions.includes('UPDATE_ITEMS_QUANTITY'); ``` ## **Example** A totalizer component that shows a loading skeleton while cart-related actions are processing. ```typescript theme={"system"} import { usePendingActions, useCheckoutSession } from '@ollie-shop/sdk'; import styles from './styles.module.css'; const TOTALIZER_ACTIONS = [ 'UPDATE_ITEMS_QUANTITY', 'REMOVE_ITEMS', 'UPDATE_SHIPPING_PACKAGES', 'UPDATE_PAYMENT_METHODS', ]; function isUpdatingTotalizers(pendingActions: string[]): boolean { return pendingActions.some((action) => TOTALIZER_ACTIONS.includes(action) ); } function formatCurrency(value: number, currency: string, locale: string): string { return new Intl.NumberFormat(locale, { style: 'currency', currency, }).format(value / 100); } function CheckoutTotalizer() { const { session } = useCheckoutSession(); const { pendingActions } = usePendingActions(); const { totals, locale } = session; const isUpdating = isUpdatingTotalizers(pendingActions); const formatPrice = (price: number) => formatCurrency(price, locale.currency, locale.language); return (
Items {isUpdating ? ( ) : ( {formatPrice(totals.items)} )}
Shipping {isUpdating ? ( ) : ( {formatPrice(totals.shipping ?? 0)} )}
Total {isUpdating ? ( ) : ( {formatPrice(totals.total)} )}
); } ```
```css theme={"system"} .container { display: flex; flex-direction: column; gap: 8px; } .row { display: flex; justify-content: space-between; align-items: center; } .total { font-weight: 700; } .skeleton { display: inline-block; width: 64px; height: 16px; background-color: #e5e5e5; border-radius: 4px; animation: pulse 1.5s ease-in-out infinite; } .skeletonLarge { display: inline-block; width: 80px; height: 16px; background-color: #e5e5e5; border-radius: 4px; animation: pulse 1.5s ease-in-out infinite; } @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } } ```
## **Notes** * The `addActionNameForLoading` and `removeActionNameForLoading` functions are automatically called by [useCheckoutAction](/ollie-shop/api/useCheckoutAction) when actions start and complete * Use `hasPendingActions` for simple loading states, or filter `pendingActions` for more granular control * Related: [useCheckoutSession](/ollie-shop/api/useCheckoutSession) # useStoreInfo Source: https://docs.ollie.shop/ollie-shop/api/use-store-info Use this hook when you need to access store metadata like the logo URL, platform information, or custom configuration. It's useful for building custom headers, or branded components. **Let your agent build it.** The Ollie Shop skill ships with projects created by `npx create-ollie-shop` and knows to read the platform account from here rather than taking it as a component prop. ```text title="Prompt" theme={"system"} Build a custom header using the store logo. ``` Don't have the skill yet? [Install it](/ollie-shop/skills). ## **Import** ```typescript theme={"system"} import { useStoreInfo } from '@ollie-shop/sdk'; ``` ## **Return Value** | Property | Type | Description | | ----------------- | -------------------------------------- | --------------------------------------------------------------- | | `storeId` | `string \| undefined` | Unique identifier for the store in Ollie Shop's database | | `logo` | `string \| undefined` | URL to the store's logo image | | `versionId` | `string \| undefined` | Version identifier for the current store configuration | | `platform` | `string` | Name of the e-commerce platform (e.g., `"vtex"`, `"shopify"`) | | `platformStoreId` | `string` | Store ID from the underlying platform (e.g., VTEX account name) | | `theme` | `Record \| undefined` | Theme object with style tokens like colors and fonts | | `props` | `Record \| undefined` | Custom configuration properties defined in the Admin | ### theme The `theme` object contains CSS custom properties (tokens) that define your store's visual identity. These values are configured in the [Theme settings](/ollie-shop/configuration/theme) in the Admin. ```typescript theme={"system"} const { theme } = useStoreInfo(); // Example theme object: // { // "--color-primary": "#556AEB", // "--color-secondary": "#BFC9FF", // "--font-family": "Inter, sans-serif" // } ``` ### props The `props` object contains custom configuration values that you define in the Admin under your [Version](/ollie-shop/concepts/version) settings. You can create any custom properties you need for your store. Custom props are defined in the Admin under **Version > Props**. You can add any JSON configuration that your custom components need. ```typescript theme={"system"} const { props } = useStoreInfo(); // Access custom props you defined in the Admin const myCustomConfig = props?.myCustomSetting; ``` ## **Usage** ```typescript theme={"system"} const { logo, platform, platformStoreId, storeId, versionId, theme, props } = useStoreInfo(); ``` ## **Example** Display the store logo in a custom header component with platform-specific styling. ```typescript theme={"system"} import { useStoreInfo } from '@ollie-shop/sdk'; import styles from './styles.module.css'; function CustomHeader() { const { logo, platform, theme } = useStoreInfo(); if (!logo) { return null; } return (
Store logo Powered by {platform}
); } ```
```css theme={"system"} .header { display: flex; align-items: center; justify-content: space-between; padding: 16px 24px; } .logo { height: 40px; width: auto; } .platform { font-size: 12px; color: #666; } ```
# useCheckoutAction Source: https://docs.ollie.shop/ollie-shop/api/useCheckoutAction The `useCheckoutAction` hook enables interactions with checkout actions in a type-safe manner, automatically updating the checkout session upon successful execution. **Let your agent build it.** The Ollie Shop skill ships with projects created by `npx create-ollie-shop`, so your assistant already knows every action type below and the input each one expects. ```text title="Prompt" theme={"system"} Add an add-to-cart button to my checkout component. ``` Don't have the skill yet? [Install it](/ollie-shop/skills). ## **Action Types** The hook supports various action types including: * `ADD_ITEMS` - Add items to the cart * `REMOVE_ITEMS` - Remove items from the cart * `UPDATE_COUPONS` - Update coupon codes * `UPDATE_CUSTOMER_DETAILS` - Update customer information * `UPDATE_ITEMS_QUANTITY` - Update quantities of items in the cart * `UPDATE_SHIPPING_PACKAGES` - Update shipping packages * `UPDATE_SHIPPING_ADDRESSES` - Update shipping addresses * `UPDATE_PAYMENT_METHODS` - Update payment methods * `UPDATE_GIFT_CARDS` - Apply or update gift cards * `UPDATE_CUSTOMER_PREFERENCES` - Update customer preferences (e.g. save data, locale) * `SIMULATE_SESSION` - Simulate a checkout session without mutating the real one * `CREATE_ORDER` - Create a new order * `REQUEST` - Make custom API requests to the backend ### **Parameters** * `actionType: ActionType` - The type of checkout action to perform (e.g., `ADD_ITEMS`, `REMOVE_ITEMS`, etc.) * `callback?: object` - Optional configuration callbacks * `onSuccess?: (data?: CheckoutSession, input?: Input) => void` - Called when the action succeeds. Receives the updated session (or the order for `CREATE_ORDER`; `unknown` for `REQUEST`) and the input that was executed * `onError?: ({ serverError, validationErrors }) => void` - Called when action fails ### **Return Value** Returns an object with: * `execute: (input: Input) => void` - Function to dispatch the action with the appropriate payload * `executeAsync: (input: Input) => Promise` - Async version of execute that returns a Promise with the action result * `isPending: boolean` - Boolean indicating if the action is currently processing * `error?: object` - Error information if the action failed * `serverError?: ServerError` - Error returned by the server * `validationErrors?: ValidatorErrors` - Input Validation errors ## **Input Parameters by Action Type** Each action type expects specific input parameters. Below are the details for each: Navigate the tabs to see details of each action ### **ADD\_ITEMS** ```typescript theme={"system"} type CartItemInput = { id: string; // Id of the item on cartItems array inside the session quantity: number; // Quantity to add sellerId?: string; // Optional seller ID }; // Usage execute([{ id: "product123", quantity: 2 }]); ``` ### ### **REMOVE\_ITEMS** ```typescript theme={"system"} type RemoveItemsInput = number[]; // Array of item indexes to remove // Usage execute([0, 2]); // Removes first and third items ``` ### ### **UPDATE\_COUPONS** ```typescript theme={"system"} type CouponsInput = string[]; // Array of coupon codes // Usage execute(["SUMMER10", "FREESHIP"]); ``` ### ### **UPDATE\_CUSTOMER\_DETAILS** ```typescript theme={"system"} type CustomerDetailsInput = { email?: string; firstName?: string; lastName?: string; phone?: string; // Other customer fields }; // Usage execute({ email: "customer@example.com", firstName: "John", lastName: "Doe" }); ``` ### ### **UPDATE\_ITEMS\_QUANTITY** ```typescript theme={"system"} type UpdateQuantityInput = { index: number; // Item index in the cart quantity: number; // New quantity }[]; // Usage execute([ { index: 0, quantity: 3 }, { index: 1, quantity: 1 } ]); ``` ### **UPDATE\_SHIPPING\_PACKAGES** ```typescript theme={"system"} type ShippingPackageInput = { id: string; // Package ID items: number[]; // Array of item indexes addressId?: string; // Optional shipping address ID selectedTimeSlotId?: string; // Optional time slot ID for delivery }; // Usage execute([ { id: "standard-delivery", items: [0, 1, 2], addressId: "home-address" } ]); ``` ### ### **UPDATE\_SHIPPING\_ADDRESSES** ```typescript theme={"system"} type ShippingAddressInput = { postalCode: string; // Required country: string; // Required street?: string; number?: string; city?: string; state?: string; complement?: string; neighborhood?: string; receiverName?: string; }; // Usage execute([ { postalCode: "12345", country: "US", street: "Main St", number: "123", city: "New York", state: "NY" } ]); ``` ### ### **UPDATE\_PAYMENT\_METHODS** ```typescript theme={"system"} type PaymentMethodInput = { methodId: string; // Payment method ID referenceValue: number; // Payment amount installments?: number; // Optional installments count }; // Usage execute([ { methodId: "credit-card", referenceValue: 99.99, installments: 3 } ]); ``` ### **CREATE\_ORDER** ```typescript theme={"system"} type CreateOrderInput = { isGuest?: boolean; // Whether to create a guest order captchaToken?: string; // Optional captcha token for validation }; // Usage execute({ isGuest: true }); ``` ### **REQUEST** Makes custom API requests to the backend. Unlike other actions, this action does not automatically update the checkout session. ```typescript theme={"system"} type RequestActionInput = { url: string; // The API endpoint URL method?: string; // HTTP method (GET, POST, etc.). Defaults to GET headers?: Record; // Optional custom headers body?: string; // Optional request body (for POST/PUT requests) revalidate?: boolean; // If true, revalidates the checkout session after request }; // Usage - GET request execute({ url: "https://example.com/api/custom-endpoint" }); // Usage - POST request with body execute({ url: "https://example.com/api/custom-endpoint", method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ key: "value" }), revalidate: true }); ``` Use the `revalidate` option to refresh the session after making changes. ## **Example** ### **Import** ```typescript theme={"system"} import { useCheckoutAction } from '@ollie-shop/sdk'; ``` ### **Usage** ```typescript theme={"system"} const { execute, executeAsync, isPending, error } = useCheckoutAction( actionType, { onSuccess: (data) => { // Handle success }, onError: ({ serverError, validationErrors }) => { // Handle errors } } ); // Execute the action (fire and forget) execute({ // Input specific to the action type }); // Or use executeAsync to await the result const result = await executeAsync({ // Input specific to the action type }); ``` ### Action ```typescript theme={"system"} import { useCheckoutAction } from '@ollie-shop/sdk'; function AddToCartButton({ productId, quantity }) { const { execute, isPending } = useCheckoutAction('ADD_ITEMS', { onSuccess: () => { console.log('Item added successfully'); }, onError: ({ serverError }) => { console.error('Failed to add item', serverError?.message); } }); return ( ); } ``` ### Using executeAsync ```typescript theme={"system"} import { useCheckoutAction } from '@ollie-shop/sdk'; function AddToCartButton({ productId, quantity }) { const { executeAsync, isPending } = useCheckoutAction('ADD_ITEMS'); const handleAddToCart = async () => { const result = await executeAsync([{ id: productId, quantity }]); if (result?.data) { console.log('Item added successfully', result.data); } }; return ( ); } ``` # useCheckoutSession Source: https://docs.ollie.shop/ollie-shop/api/useCheckoutSession The `useCheckoutSession` hook provides access to the current checkout session data and functionality to update it. It gives you access to both the parsed, platform-agnostic checkout session data and the raw session data from the e-commerce platform. **Let your agent build it.** The Ollie Shop skill ships with projects created by `npx create-ollie-shop`, so your assistant already knows the session shape and which fields are safe to read. ```text title="Prompt" theme={"system"} Build a custom totalizer from the session totals. ``` Don't have the skill yet? [Install it](/ollie-shop/skills). ## **Import** ```typescript theme={"system"} import { useCheckoutSession } from '@ollie-shop/sdk'; ``` ## **Usage** ```typescript theme={"system"} const { session, rawSession, updateSession, sessionValidity } = useCheckoutSession(); // Access session data console.log(session.cartItems); // Update session data updateSession(newSession, newRawSession); // Check if the session is valid if (sessionValidity?.valid) { // Session is valid } else { // Handle validation errors console.error(sessionValidity?.errors); } ``` ## **Return Value** Returns an object with: * `session: CheckoutSession` - The parsed, platform-agnostic checkout session conforming to your custom schema * `rawSession: unknown` - The original session data from the e-commerce platform (VTEX, Shopify, etc.) in raw/unparsed form * `updateSession: (session: CheckoutSession, rawSession: unknown) => void` - Function to update both the parsed and raw session data * `sessionValidity?: ValidationSuccess | ValidationFailure` - Results from the last validation check of the session data ## **Session Validation** The `sessionValidity` object contains the results of validating the checkout session against a ZodSchema. This schema-based validation ensures that all required data is present and formatted correctly. ```typescript theme={"system"} if (sessionValidity?.valid) { // Session is valid - all required fields are present and correctly formatted } else { // Session is invalid - access validation errors const errors = sessionValidity?.errors; } ``` ### **Understanding sessionValidity** * `sessionValidity` uses a ZodSchema to validate the structure and content of your checkout session * It helps identify missing or invalid information in customer details, shipping addresses, payment methods, etc. * This validation is crucial for determining whether a user can proceed to checkout or needs to provide more information ### **Validating Address Information** A common use case is checking if some information is complete before redirecting the user to the next step ```typescript theme={"system"} export const function PageShipping { const { sessionValidity } = useCheckoutSession(); // Extract address validation errors if they exist const missingAddressFields = sessionValidity && "errors" in sessionValidity ? sessionValidity.errors?.shipping?.addresses : undefined; // Component rendering... return (
{}}>
) } ``` This pattern lets you detect missing required fields and direct users to the appropriate step in your checkout flow to provide that information. ## **Example** ```typescript theme={"system"} import { useCheckoutSession } from '@ollie-shop/sdk'; function CartSummary() { const { session } = useCheckoutSession(); return (

Cart Summary

Total Items: {session.cartItems.length}

Subtotal: ${session.totals.items}

{(session.totals.discounts ?? 0) > 0 && (

Discounts: -${session.totals.discounts}

)}

Shipping: ${session.totals.shipping ?? 0}

Total: ${session.totals.total}

); } ``` ## **Notes** * Use type parameters with `useCheckoutSession()` when you have custom properties in your checkout session # useMessages Source: https://docs.ollie.shop/ollie-shop/api/useMessages The useMessages hook is part of the Ollie Shop React library and provides functionality to manage notification messages across the application. The `useMessages` hook provides a way to manage application messages (notifications, alerts, etc.) in a React application. It allows you to add, remove, and clear messages throughout your application. **Let your agent build it.** The Ollie Shop skill ships with projects created by `npx create-ollie-shop` and knows the message types and when surfacing one beats failing silently. ```text title="Prompt" theme={"system"} Show an error message when my validation fails. ``` Don't have the skill yet? [Install it](/ollie-shop/skills). ## **Import** ```typescript theme={"system"} import { useMessages } from '@ollie-shop/sdk'; ``` ## **Usage** ```typescript theme={"system"} const { messages, addMessage, removeMessage, clearAll } = useMessages(); // Add a new message addMessage({ type: 'success', content: 'Order completed successfully!' }); // Remove a specific message removeMessage(messageId); // Clear all messages clearAll(); ``` ## **Return Value** Returns an object with: * `messages: Message[]` - Array of all current message objects * `addMessage: (message: AddMessageInput) => void` - Function to add a new message. Accepts either a `content` (a direct message) or an `error` (a `ServerError`, automatically resolved into a localized message via translations) * `removeMessage: (messageId: string) => void` - Function to remove a message by its ID * `clearAll: () => void` - Function to remove all messages ## **Message Object** Each message in the `messages` array has the following structure: ```typescript theme={"system"} { id: string; // Automatically generated unique ID type: enum; // Type of message (e.g., 'success', 'error', 'info', 'warning') content: string; // The actual message content title?: string; // Optional title for the message } ``` Message is described by the following structure: | Property | Type | Description | | :-------- | :------- | :-------------------------------------------------------------- | | `id` | `string` | A unique identifier for the message (automatically generated) | | `type` | `enum` | The type of message `info` \| `success` \| `warning` \| `error` | | `content` | `string` | The main text content of the message | | `title` | `string` | Optional title for the message | ## **Example** The example below shows two different messages, a `success` and an `error` | Desktop | Mobile | | ---------------------- | ---------------------- | | messages | messages | To achieve the result in the example above : ```tsx theme={"system"} import React from 'react'; import { useMessages } from '@ollie-shop/sdk'; function NotificationSystem() { const { messages, addMessage, clearAll } = useMessages(); // Create a success message const handleSuccess = () => { addMessage({ type: 'success', title: 'Order Placed', content: 'Your order has been successfully placed.', }); }; // Create an error message const handleError = () => { addMessage({ type: 'error', content: 'Unable to process your request. Please try again.', }); }; return (
{messages.length > 0 && ( )}
); } ``` ## Examples per Action ### addMessage(message) Adds a new message to the message stack. #### Parameters * `message`: an `AddMessageInput`. Provide **either** `content` (a direct message) **or** `error` (a `ServerError` to auto-resolve a localized message). `type` is required; `title` is optional. ```tsx theme={"system"} // Direct message addMessage({ type: 'success', title: 'Order Placed', content: 'Your order has been successfully placed.' }); // Auto-resolved from a ServerError (e.g. an action's onError handler). // The localized text is resolved from the error's platformCode / code / // errorGroup via translations, falling back to a generic message. addMessage({ type: 'error', error: serverError, }); ``` ### removeMessage(messageId) Removes a specific message from the stack by its ID. #### Parameters * `messageId`: `id` of the message to remove ```tsx theme={"system"} ... removeMessage('message-uuid-123'); ... ``` Messages are **not** dismissed automatically. They stay in the stack until you remove them with `removeMessage(id)` or `clearAll()`. The rendering layer is responsible for any auto-dismiss behavior. ### clearAll() Removes all messages from the message stack. ```tsx theme={"system"} ... clearAll(); ... ``` ### # Changelog Source: https://docs.ollie.shop/ollie-shop/changelog/index Product updates and announcements ## New Features & Improvements * **Redesigned Studio workspace.** Studio now opens as a full-screen, standalone editing environment with a side-by-side live preview, component search grouped by slot, and a redesigned header and sidebar. * **Visual props editor.** Edit component props through a schema-driven form (or raw JSON) with live validation — no more guessing prop shapes. * **Theme editor.** A dedicated Theme tokens panel to edit brand colors, neutrals, system colors, and shape/size presets directly in Studio. * **Slot inspector.** Hover to highlight slots on the live preview, copy a slot id, or jump straight into editing the component in that slot. * **Batch deploy.** Build and deploy multiple components at once from Studio. * **Import components across stores and organizations.** Reuse a component from another store — including across organizations — and keep it in sync with its source. * **Duplicate a version.** Clone an entire version's content, components, and functions to branch off a new experience quickly. * **A/B testing.** Run experiments across versions with per-version A/B test configuration and flag overrides. * **Apple Pay via VTEX Wallet Hub.** Express Apple Pay checkout now works gateway-agnostically through VTEX Wallet Hub. * **Romanian locale.** Added full Romanian (ro) translations, with currency shown as "lei". * **Measurement-unit aware cart.** Items sold by weight or volume (e.g. per 100g) now display the correct unit and per-unit pricing, including grouped breakdowns for promotion splits. * **Shipping improvements.** New pickup layout, a complete-address modal for missing mandatory fields, and estimated delivery / arrival dates in the order summary. * **CLI: stream browser logs.** A `--browser-logs` flag streams your custom component's console output straight to your terminal. ## Bug Fixes * Fixed PayPal express rendering and added a loading skeleton on the cart. * Various installment display and shipping-package layout fixes. ## Technical Updates * Introduced a framework-free `` custom element for PCI-isolated card fields. * Standardized the AI agent skills library and published it via a public mirror. * Centralized feature-flag handling behind a single flag registry. ## New Features & Improvements * **New payment methods:** Aplazo, Kueski, and Mercado Pago. * **Debit card support.** Debit cards now appear as their own payment tile with a dedicated brand strip. * **Mexico support.** Postal-code-first address flow and Mexico-specific address fields (exterior/interior numbers, colonia). * **Smarter shipping.** Optional business-days delivery display, per-dock package splitting, and an optimized shipping-options flow. * **Studio props panel** and a configurable checkout start route. * **Sales template revamp** with new header and share slots. * **Resilient payments.** Automatic payment retry and timeout recovery, a fallback payment method after repeated failures, and clearer "payment not ready" and item-error modals. * Smoother, optimistic payment loading experience. ## Bug Fixes * Fixed saved-card default selection and filtering of expired cards. * Numerous payment-step and checkout consistency fixes. ## New Features & Improvements * **Business rules.** Configure store business rules from the Admin, with matching CLI commands and versioned rule sets. * **Custom payment methods.** Define and render your own payment methods in the checkout. * **Step navigation SDK hook.** Custom components can now drive step navigation (including the place-order button) programmatically. * **Store environment variables.** Manage per-store secrets and configuration, injected securely at runtime. * **Global layout bottom slot** for content that spans the whole checkout. * **Builds visibility.** New builds tab on component and function pages, plus exposed build logs. * **CLI:** new `function` command and production environment defaults. * Redesigned review/summary step and an on-select-payment hook for custom components. ## Bug Fixes * Handle item errors during order creation and show the Pix modal correctly while redirecting. * Fixed gift-card flows and transaction verification via order status. ## Technical Updates * Added bot-protection to the storefront. ## New Features & Improvements * **Boleto** payment method and **Yuno Click to Pay**. * **Address lookup by postal code**, with a graceful fallback when Google Maps is unavailable. * **Address selection on the cart page** and gift-card full-payment flow. * **CLI agent commands** and deploy-status reporting. * **Custom functions:** custom regex support and reusable trigger-variable operator presets. * Server-side session storage and session-cookie persistence for more reliable sessions. * New Studio sidebar layout and improved default template. ## Bug Fixes * Multiple address-form fixes, including street/place-name handling. ## Technical Updates * Faster component delivery via a dedicated CloudFront cache policy and lazy-mounted PayPal buttons. ## New Features & Improvements * **Ollie Studio styling** groundwork and a "use my location" button for faster address entry. * **Saved cards:** a "see more" control to reveal additional saved cards. * **Purchase tracking** for payments completed on the order page. * **Mobile summary dropdown** and improved shipping-step UI. * Improved PayPal implementation and login messaging. * CLI scaffolding now includes an AI prompt for creating an Ollie project. ## Bug Fixes * Address-autocomplete alignment, remove-item behavior, and mobile summary layout fixes. * Resolved PostHog race conditions and PayPal express caching issues. ## Technical Updates * Added security headers to payments and served minified component bundles. ## New Features & Improvements * **NuPay** payment method. * **Login form modal** in the default template, plus a forgot-password flow. * **Ollie Login enabled by default.** * Design tokens for the sidebar, container, and buttons. * New Admin view-and-filter component and page-view tracking. * New slots: address on cart, proceed-to-checkout, full-page header, and summary items. * **Custom functions:** pass request headers into trigger expressions. ## Bug Fixes * Fixed step-address behavior and step-navigation slot styling. * Resolved version-cookie edge cases. ## Technical Updates * Introduced JSON-schema-based validation across the platform. ## New Features & Improvements * **Device fingerprinting** for fraud prevention. * **Dynamic credit-card brand icons** and gift-card support in the commerce client. * New navigation and address-form slots, plus a multi-package slider on mobile. * Option to keep items unsplit (`noSplitItems`) and disable Google Translate on checkout. * More reliable payments via a container handshake before submit and PayPal gateway-callback handling. ## Bug Fixes * Fixed installment selection, success messages, and shipping-package updates. * Added a fallback parser for gateway-callback responses. ## Technical Updates * Migrated checkout middleware to the Node.js runtime. * Applied security patches for underlying framework vulnerabilities. ## New Features & Improvements * **Guest checkout with address before identification** and a change-address / login modal. * **Pix order page** with redirect after placing a Pix payment. * Suggested email on the contact form and an items counter on the product gallery. * New shipping-packages slot and additional delivery-method selector props. * Error boundaries around slot components to isolate custom-component failures. * VTEX helpers are now exported from the SDK. ## Bug Fixes * Fixed address field ordering and country/schema switching. * Multiple Apple Pay and Pix redirect fixes. ## Technical Updates * Introduced session cookies with cache control. ## New Features & Improvements * **PayPal Express** and express payment buttons in the payment section. * **Affirm** payment method and reCAPTCHA support. * **PostHog analytics** integration. * Billing address v2, address autocomplete, and gift-card-only orders. * Redesigned step navigation and mobile navigation, with theming tokens for navigation buttons. * Many new slots: totalizers, cart item package list, shipping options, empty-cart, and mobile totalizers. * Transaction-denied modal and dynamic badges. ## Bug Fixes * Address, Apple Pay, and installment fixes across the flow. * Region-specific address schema fixes (Ireland, Canada). ## Technical Updates * New shared UI library package and optimistic cart updates. ## New Features & Improvements * **Apple Pay and Google Pay** express checkout, with an express-checkout container. * **Gift cards** and **saved cards** support. * **Share Cart** and **EasyCart** for faster cart handoff. * **GTM analytics** integration and the SDK `useCheckoutOrder` hook. * Native checkout success page and a "My Orders" slot. * Team member management with email invites. * Mobile improvements and sticky navigation. ## Bug Fixes * Fixed saved-card detection, checkout errors, and invite flows. * Cookie and session-creation fixes. ## Technical Updates * Added a complete local testing environment for developers. ## New Features & Improvements * **Google Pay** and **Pagaleve** payment methods. * **Manual address input** and a phone country selector. * Update-profile flow and session revalidation. * Additional slots on the shipping step and cart, plus an unavailable-items list on the shipping step. * Translations for custom components and expanded multi-language support. ## Bug Fixes * Cart layout fixes and Pix error handling. * Fixed CVV tooltip position and broken font/style props. ## Technical Updates * Foundational observability and reliability improvements across the platform. ## New Features & Improvements * Added shipping slot functionality. * Improved props management. * Integrated PayPal payment option. * Added missing translations in components and templates (default and grocery). ## Bug Fixes * Fixed 500 error on checkout session. ## Technical Updates * Allowed multiple active components and functions per version. ## New Features & Improvements * Minor updates to `@create-ollie-shop`. * Added optimistic updates for cart operations (adding/removing items) to improve user experience. * Introduced new CLI commands: docs, help, whoami, and validate. ## Bug Fixes * Fixed payment submission errors. * Fixed input number issue for OTP. * Added fallback to Node.js v18. # Easy Cart Source: https://docs.ollie.shop/ollie-shop/cheat-sheet/Easy-Cart A floating dev tool for managing carts during development and QA ## Overview **Easy Cart** is a built-in developer tool that provides a floating menu in the checkout UI for quickly creating and manipulating carts. It's intended for development, QA, and internal testing — not for end users. *** ## How to enable Add `?easycart=on` to any checkout URL: ``` /new?easycart=on /cart?easycart=on /details?step=shipping&easycart=on ``` Once enabled, a cookie (`ollie_shop_ec`) is set for 1 year so you don't need the query parameter on subsequent visits. A floating **EC** button will appear in the bottom-right corner of the page. Easy Cart only appears on stores using the **default** template — the `grocery` and `sales` templates do not mount it. ### Accepted values The parameter name is matched **case-insensitively**, so `?easycart=on`, `?easyCart=on` and `?EASYCART=on` are equivalent. The value is also case-insensitive: | To do this | Use any of | | ---------- | ------------------------- | | Enable | `on`, `true`, `1`, `yes` | | Disable | `off`, `false`, `0`, `no` | Anything else (a typo like `?easycart=onn`) is ignored and leaves the current state alone, so it won't switch off a tool you had already enabled. A bare `?easycart` with no value does **not** enable it. ## How to disable Either add `?easycart=off` to the URL, or open the Easy Cart menu and click **Disable EasyCart**. Both clear the `ollie_shop_ec` cookie. *** ## Actions | Action | What it does | | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **New Cart** | Creates a fresh checkout session and adds a random product to it. | | **Add Random Item** | Fetches the store's product catalog and adds a random item to the current cart. The arrow at the end of the row opens [advanced settings](#random-item-advanced-settings) instead of adding anything. | | **Add by SKU IDs** | Opens a form to add specific items by SKU ID, with optional quantity and seller ID. Blank quantity defaults to 1, blank seller to `1`. | | **Load Session** | Restores a previous cart by entering its Session ID. | | **Empty Cart** | Removes all items from the current cart. | *** ## Random item advanced settings Clicking the **Add Random Item** row still adds one random item straight away. The **arrow at the end of that row** opens a small form instead, where every field is optional: | Field | Blank means | What it does | | --------------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **How many products** | 1 | Adds this many items. Distinct SKUs are used first; once the matches run out, the quantity of an already-picked SKU goes up instead of the same line being sent twice. | | **Seller ID** | any seller | Keeps only SKUs offered by that seller, and adds them under it. | | **Category** | whole catalog | A category ID path (`16`, `16/22`) becomes a VTEX `fq=C:/16/22/` filter; anything else is searched as free text (`ft=`). | Leaving all three blank behaves exactly like clicking the row. The search that feeds this widens with the quantity — asking for 20 items fetches 20 products rather than the default 5 — and stops at VTEX's limit of 50. If nothing matches the filters, an error message is shown and the cart is left alone. The seller filter runs on the search results, so a seller with no items in the searched category simply matches nothing. Narrow by one filter at a time when a combination comes back empty. *** ## Switching sales channel Easy Cart deliberately has no sales-channel action. On VTEX a cart inherits its sales channel **when it is created** and an existing cart cannot be moved to another one — there is no endpoint, attachment, or parameter for it. Verified against a live store: `?sc=` on cart creation scopes only that one response (re-read without `sc` and the cart reports the default channel, and a channel-specific SKU is rejected with `ORD027`); setting `public.sc` on the session updates `store.channel` but leaves the next cart on the default channel; and a `vtex_segment` cookie carrying `channel` has no effect either, while `POST /api/segments` returns `405`. What does work is the storefront route on the **store's own domain**, which creates a cart genuinely bound to the channel: ``` https://{account}.vtexcommercestable.com.br/checkout/cart/add?sku={sku}&qty=1&seller={seller}&sc={channel} ``` The SKU must exist in the target channel. Because it sets its cookies on the store domain, this works end to end when checkout runs on that domain too. # CLI Installation Source: https://docs.ollie.shop/ollie-shop/cli/installation Install and set up the Ollie Shop CLI for component and function development Quick CLI setup for Ollie Shop development. Install, authenticate, and start building in under 2 minutes. ## Install ```bash npm theme={"system"} npm install -g @ollie-shop/cli ``` ```bash yarn theme={"system"} yarn global add @ollie-shop/cli ``` ```bash pnpm theme={"system"} pnpm install -g @ollie-shop/cli ``` ```bash theme={"system"} ollieshop --version ``` Should show version number (e.g., `2.1.4`) ## Authenticate ```bash theme={"system"} ollieshop login ``` Opens browser for OAuth authentication Best for teams with existing GitHub workflows Quick single sign-on for business users Secure email-based authentication **Ready!** CLI is installed and authenticated. Start with the [Developer Quickstart](/ollie-shop/get-started/quickstart) to build your first component. Authentication tokens are stored securely in `~/.ollie-shop/credentials.json` ## Troubleshooting **Problem**: `npm install -g` fails with permission errors **Solution**: ```bash theme={"system"} sudo npm install -g @ollie-shop/cli ``` Or use a Node version manager like nvm **Problem**: `ollieshop` command not recognized **Solution**: Restart terminal or check PATH: ```bash theme={"system"} echo $PATH | grep npm ``` **Problem**: Browser doesn't open or authentication fails **Solution**: Retry the login: ```bash theme={"system"} ollieshop login ``` **Problem**: CLI requires newer Node.js version **Solution**: Update Node.js to 18+ or use nvm: ```bash theme={"system"} node --version # Should be 18.0.0+ ``` # whoami Source: https://docs.ollie.shop/ollie-shop/cli/whoami Show the authenticated user and the store/organization linked to the current project `ollieshop whoami` reports who you are currently logged in as. When the current directory has an `ollie.json`, it also resolves the **store** and **organization** that config points at — but only if your account has access to them. ```bash theme={"system"} ollieshop whoami ``` ## What it shows When an `ollie.json` is present and you have access to its store: ```json theme={"system"} { "data": { "email": "you@example.com", "orgId": "0e8f...", "org": "Acme Inc.", "storeId": "1a2b...", "store": "Acme Storefront" } } ``` When there is no `ollie.json` in the current directory, only the user is returned, with a hint to link a store: ```json theme={"system"} { "data": { "email": "you@example.com", "hint": "No ollie.json found. Run `ollieshop init` to link a store." } } ``` When `ollie.json` references a store you cannot access, the store fields are null and a note explains why: ```json theme={"system"} { "data": { "email": "you@example.com", "storeId": "1a2b...", "store": null, "note": "Store not found. Run `ollieshop login` or check the storeId in ollie.json." } } ``` Store and organization access is enforced server-side. `whoami` never reveals a store you are not a member of — it simply reports it as not found. ## Options | Flag | Description | | --------------------- | -------------------------------------------------- | | `-o, --output json` | Force JSON output (auto-selected when piped). | | `--fields a,b,c` | Limit the output to specific fields. | | `-s, --stage ` | Read `ollie.{stage}.json` instead of `ollie.json`. | ## Examples ```bash theme={"system"} # Pretty output in a terminal ollieshop whoami # JSON for scripting ollieshop whoami -o json # Only the email and org ollieshop whoami --fields email,org # Resolve against a stage-specific config ollieshop whoami --stage dev ``` Not logged in or your session expired? `whoami` exits with an error — run `ollieshop login` to refresh your credentials. # Build Your First Component Source: https://docs.ollie.shop/ollie-shop/components/your-first-component Step-by-step guide to creating a checkout component ## Overview This guide walks through building a **free shipping progress bar** component. You'll learn how to: * Create a component in your project * Access checkout data with the SDK * Run it locally * Register and deploy it to your store **Let your agent build it.** The Ollie Shop skill ships with projects created by `npx create-ollie-shop`, and it carries an opinionated recipe for this exact component. ```text title="Prompt" theme={"system"} Create a free shipping progress bar component. ``` It covers the rest of this guide too, one step at a time: * **Access checkout data with the SDK:** `Which session fields do I need for a free shipping bar?` * **Run it locally:** `Start the dev server and show me the component in Studio.` * **Register and deploy it:** `Register this component in my store and deploy it.` Working through the walkthrough below teaches you what the agent is doing, which is worth doing once. After that, the prompts are faster. Don't have the skill yet? [Install it](/ollie-shop/skills). ## Prerequisites * The Ollie Shop CLI installed (`npm install -g @ollie-shop/cli`) — see [Installation](/ollie-shop/cli/installation) * A scaffolded project (`npx create-ollie-shop`) — see the [Quickstart](/ollie-shop/get-started/quickstart) * Basic React knowledge * Access to a store A component is a folder under `components/` in your project. It is **not** a standalone package — `ollieshop component create` only registers metadata in the database; it does not scaffold a folder. The actual code lives in your project. ## Create the Component Inside your project, create `components/FreeShippingBar/` with an `index.tsx` and a `meta.json`: ``` your-project/ ├── components/ │ └── FreeShippingBar/ │ ├── index.tsx # Component code (entry point) │ ├── styles.module.css # Styles (optional) │ └── meta.json # Component metadata (id, slot, props) ├── package.json # Project dependencies └── ... ``` `meta.json` tells the tooling where the component goes. The `slot` is where it renders in the checkout (see [Slots](/ollie-shop/concepts/slots)). Leave `id` out for local development — an unlinked component gets a temporary `studio-*` id until you register it. ```json meta.json theme={"system"} { "name": "Free Shipping Bar", "slot": "your-slot" } ``` ## Build the Component Create `components/FreeShippingBar/index.tsx`: ```tsx index.tsx theme={"system"} import React from 'react'; import { useCheckoutSession } from '@ollie-shop/sdk'; import styles from './styles.module.css'; export default function FreeShippingBar() { const { session } = useCheckoutSession(); const { totals, locale } = session; const threshold = 10000; // $100 in cents const subtotal = totals.items; const remaining = threshold - subtotal; const progress = Math.min((subtotal / threshold) * 100, 100); const format = (cents: number) => new Intl.NumberFormat(locale.language, { style: 'currency', currency: locale.currency, }).format(cents / 100); if (remaining <= 0) { return (
✓ Free shipping unlocked
); } return (

Add {format(remaining)} for free shipping

); } ``` ## Add Styles Create `components/FreeShippingBar/styles.module.css`: ```css styles.module.css theme={"system"} .shippingBar { background: #f3f4f6; padding: 12px; text-align: center; font-size: 14px; } .success { background: #10b981; color: white; } .progressTrack { background: #e5e7eb; height: 6px; border-radius: 3px; margin-top: 8px; overflow: hidden; } .progressFill { background: #3b82f6; height: 100%; transition: width 0.3s ease; } ``` ## Test Locally Start the local dev server from your project root: ```bash theme={"system"} npm start # or, directly: ollieshop start ``` This discovers your components, opens Ollie Studio in the browser, and hot-reloads as you edit. ## Register & Deploy Create the component record in a store version to get its **component id**. You can do this in the admin dashboard, or via the CLI: ```bash theme={"system"} ollieshop component create \ --version-id \ --name "Free Shipping Bar" \ --slot your-slot ``` Deploy bundles the local `components/FreeShippingBar` folder and uploads it to the builder. Pass the component id from the previous step and the folder name: ```bash theme={"system"} ollieshop deploy \ --component-id \ --name FreeShippingBar \ --wait ``` `--wait` polls until the build finishes. ```bash theme={"system"} ollieshop component list --store-id ``` ## Using Checkout Data The SDK exposes hooks for reading checkout data. `useCheckoutSession` returns the parsed session: ```tsx theme={"system"} const { session } = useCheckoutSession(); session.cartItems // Array of cart items session.totals.items // Subtotal of items, in cents session.totals.shipping // Shipping cost, in cents (optional) session.totals.total // Grand total, in cents session.locale // { currency, language, country } session.customer // Customer data (optional) ``` See the [hooks reference](/ollie-shop/api/hooks) and the [`CheckoutSession` type](/ollie-shop/api/CheckoutSession) for the full shape. ## Adding Interactivity Cart changes go through [`useCheckoutAction`](/ollie-shop/api/useCheckoutAction), not `useCheckoutSession`: ```tsx theme={"system"} import { useCheckoutAction } from '@ollie-shop/sdk'; function RemoveFirstItemButton() { const { execute, isPending } = useCheckoutAction('REMOVE_ITEMS', { onError: ({ serverError }) => console.error('Failed to remove item', serverError?.message), }); return ( ); } ``` ## Best Practices ### Performance ```tsx theme={"system"} // Memoize expensive calculations derived from the session const totalSavings = useMemo( () => session.cartItems.reduce( (sum, item) => sum + (item.originalPrice - item.price) * item.quantity, 0, ), [session.cartItems], ); ``` ### Error Handling Surface failures to the user via [`useMessages`](/ollie-shop/api/useMessages): ```tsx theme={"system"} const { addMessage } = useMessages(); const { execute } = useCheckoutAction('ADD_ITEMS', { onError: ({ serverError }) => addMessage({ type: 'error', error: serverError }), }); ``` ### Accessibility ```tsx theme={"system"}
{remaining > 0 ? `${format(remaining)} until free shipping` : 'Free shipping unlocked'}
``` ## Next Steps A fully custom CartItem walkthrough Complete SDK documentation # Components Source: https://docs.ollie.shop/ollie-shop/concepts/component React apps written in TypeScript Ollie Shop works with Templates, which is nothing but a pre-defined set of slots. In each Slot goes a Component. This way you can change compoennts wihtout having to worry about re-buidling your checkout. Take a look at our [onboarding tutorial](/ollie-shop/get-started/quickstart) and learn how create and deploy a custom component ## Component Architecture Components follow a simple pattern: ```typescript index.tsx theme={"system"} import { useCheckoutSession, useStoreInfo } from "@ollie-shop/sdk"; export default function MyComponent() { import React from "react"; // Access live checkout data const { session } = useCheckoutSession(); const { theme } = useStoreInfo(); return (

Welcome {session.customer?.firstName}!

Cart total: ${(session.totals.total / 100).toFixed(2)}

); } ``` ## Creating Components Components are created through the admin dashboard: Component creation form showing name, active toggle, slot selection, and version selection 1. `Name` - Descriptive component name 2. `Slot` - Where the component will appear 3. `Version` - Which store version to deploy to 4. `Status` - Active/inactive # Functions Source: https://docs.ollie.shop/ollie-shop/concepts/function Add custom business logic to your checkout that is impossible with traditional e-commerce platforms. Modify any attribute from your cart. Integrate with any API. With Ollie Shop you don't have to take no for an answer. You are now able to build complex business rules without overloading your customer's experience. Add validation rules, dynamic pricing, inventory checks, and custom integrations. Transform checkout data with your exact business requirements. Deploy instantly without managing servers. Functions scale automatically from one order to millions. Pay only when they run. Ollie Shop act as a proxy to your ecommerce provider. As you can see on the diagram below Ollie Shop sits between the Client (or the UI) and the ecommerce platform. Ollie Components can be used as your UI, but we've created Ollie Functions completely separate on purpose, this way we make sure to run the functions server-side and we also allow external clients to use Ollie Functions (think of native apps that can take advantage of the functions already built for your web checkout). Diagram explaining how Ollie Functions work All Functions run server-side guaranteeing security and maximum performance. ## Function Triggers Functions are similar to AWS Lambda's, it's where we store and run your custom code. The most important aspect of a Function is to determine when it should be executed, meaning what will trigger the Function. Given the headless nature of Ollie Shop, there are many HTTP requests flowing between the client and the server. You can define any of these HTTP request as a trigger. ### Example - execute function when the user adds their email to the cart Let's say you want to run a customization that runs a background check everytime the user add's an email to the cart. The traditional way of thikning how to approach this problem is to build a new textbox component and in this component use AXIOS or a similar lib to fetch an external API, directly ffrom the component. Clear downsides is that you'll depend on the browser, and also the front-end developer will have to know how this external API works. With Ollie this is not required. You know that there is already a textbox where the user will enter their email, the Contact Step in your checkout process. You also know that this action will use the Ecommerce Provider API to add the email to the cart data. **Example:** the VTEX API that adds the client profile data - accountName.myvtex.com/api/checkout/pub/orderForm/:orderFormId/attachments/clientProfileData You can configure a function to "listen" to this API (HTTP request). Image with Function trigger configuration Ollie Shop Functions can be seem as interceptors of HTTP requests. When the HTTP is called, Ollie Shop will check if there are any Functions associated with it. In our example, there is one, and we configured it to run on the **response**, meaning that Ollie is actually intercepting the responde of the HTTP request, before it get's back to the client (component). Your function will not only use the API as a trigger, but it can also use the request/response payload of that API for it's own purposes. ```json response /api/checkout/pub/orderForm/:orderFormId/attachments/clientProfileData theme={"system"} { ... "clientProfileData": { "email": "thomas@low.beer", "firstName": "T***", "lastName": "L***", "document": "***63", "documentType": "cpf", "phone": "***30", ... }, ... } ``` By using the "Add Profile to Cart" as a trigger we are taking advantage of the fact that in a normal chekout flow you want the user to add their email to the cart. We are "piggybacking" on an action that was already meant to happen Ollie will now run your custom code that gets the user's email from the body of the response from the "add client to the cart" API - `clientProfileData.email` - and use this data in the custom code you deployed to the function. Below an example of how to use the payload inside a function ```typescript Example of how to use the available request/response payload in a function theme={"system"} export const handler = async ({ res }: { req: Request; res: Response }) => { const rawSession = await res.json(); try { // Enhance the cart response by adding background check validation // This demonstrates how to extend the original API response with custom data const newSession = { ...rawSession, clientProfileData: { ...rawSession.clientProfileData, backgroundCheck: "approved", } }; return new Response(JSON.stringify(newSession), res); } catch (error) { // Handle errors gracefully and return original response if processing fails console.error('Function execution failed:', error); return new Response(JSON.stringify(rawSession), res); } }; ``` Once your code runs, the data that it returns can be added to the response of the API that was used as a trigger, effectively "extending" the original API. In our example we added a new attribute to the body of the response - `clientProfileData.backgroundCheck` ```json response of the original HTTP enriched with the Function focus=10 theme={"system"} { ... "clientProfileData": { "email": "thomas@low.beer", "firstName": "T***", "lastName": "L***", "document": "***63", "documentType": "cpf", "phone": "***30", ... "backgroundCheck": "approved", ... }, ... } ``` ## Function Types **Invocation Type** * `Request` Runs **before** the HTTP setup as the trigger * `Response` Runs **after** the HTTP setup as the trigger The example above was for a **response** function, meaning that your custom code will run after the HTTP request that triggered it has happened, so that you have access to the *response* of that HTTP request (but before the response reaches the client). You should use a **request** type of function when you wish to make a validation before the HTTP request actually happens, for example, if you have a rule where a max/min quantity of items can be bought. So before the HTTP request (add to cart API) is actually executed, your custom function will check against an external database what is the limit for that SKU. If the limit exceeds the updated quantity your function can abort the HTTP request and the add to cart API is not even executed. **intercept an HTTP request and modify the payload** Use them for validation, data modification, and pre-processing logic. **intercept an HTTP request and modify the response** Use them for post-processing, integrations, and response enhancement. ## Error Handling Strategies Understanding error handling is crucial for building reliable checkout flows: * **Throw** - an error message will appear for the user * **Skip** - the user will continue it's journey and the error will be suppressed. Image with Function error configuration **Best Practice**: Use `throw` for anything that affects order validation or payment. Use `skip` for analytics, logging, and optional features. ## Priority If you need to trigger multiple functions using the same trigger, you can use the `priority` feature. This creates an order in which Ollie Shop will trigger your functions. When a functions is triggered it will use the data made available from the previous function. Priority starts with `0` (zero) and currently there are no limits on the number of functions you can trigger. # Global Session Objects Source: https://docs.ollie.shop/ollie-shop/concepts/session Access checkout session data through global objects available in the browser During checkout, Ollie Shop exposes session data through global objects in the browser. These objects contain all the information about the current checkout state—cart items, user data, shipping options, payment methods, and more. ## Available Session Objects | Object | Description | | --------------------------------- | -------------------------------------------------------------------------------- | | `window.__CHECKOUT_SESSION__` | Ollie Shop's normalized session with a consistent structure across all platforms | | `window.__RAW_CHECKOUT_SESSION__` | The raw session data from your e-commerce platform (VTEX, Shopify, etc.) | Use `__CHECKOUT_SESSION__` for a consistent data structure regardless of your e-commerce platform. Use `__RAW_CHECKOUT_SESSION__` when you need platform-specific fields not available in the normalized version. ## Ollie Shop Session Structure The `__CHECKOUT_SESSION__` object provides a clean, normalized structure: ```json theme={"system"} { "id": "4d300fb5d13246a1873ef69a650c9a78", "cartItems": [ { "id": "14", "name": "Soccer Shirt S", "variant": "S", "brand": "Ollie", "category": "Apparel", "quantity": 1, "price": 5000, "originalPrice": 5000, "available": true, "index": 0, "image": "https://example.com/image.png", "url": "/soccer-shirt/p" } ], "customerPreferences": { "saveData": false, "locale": "en-US" }, "shipping": { "addresses": [], "packages": [], "availableQuotes": [], "availableCountries": ["USA", "BRA", "NLD"] }, "payment": { "availableMethods": [ { "id": "1", "type": "credit_card", "name": "American Express", "installments": [ { "number": 1, "amount": 5000, "total": 5000, "interestRate": 0 } ] } ], "selectedPayments": [], "giftCards": [], "total": 0, "savedCards": [] }, "locale": { "currency": "USD", "country": "USA", "language": "en-US" }, "taxes": [], "totals": { "items": 5000, "total": 5000 }, "user": { "role": "user", "isGuest": true }, "readOnly": false } ``` ### Key Properties | Property | Type | Description | | ----------- | ------ | -------------------------------------------------- | | `id` | string | Unique session identifier | | `cartItems` | array | Products in the cart with normalized properties | | `user` | object | User information including `isGuest` status | | `locale` | object | Currency, country, and language settings | | `totals` | object | Order totals (items, shipping, discounts, total) | | `shipping` | object | Shipping addresses, packages, and available quotes | | `payment` | object | Available payment methods and selected payments | ## Raw Platform Session (VTEX Example) The `__RAW_CHECKOUT_SESSION__` object contains the unmodified data from your e-commerce platform. This example shows the VTEX orderForm structure: ```json theme={"system"} { "orderFormId": "4d300fb5d13246a1873ef69a650c9a78", "salesChannel": "1", "loggedIn": false, "isCheckedIn": false, "storeId": null, "allowManualPrice": false, "canEditData": true, "userProfileId": null, "userType": null, "value": 5000, "messages": [], "items": [ { "uniqueId": "A1CAC2C73CCE4C7C985F60DAF99C1599", "id": "14", "productId": "4", "refId": "OLL-SOCCER-S", "name": "Soccer Shirt S", "skuName": "S", "price": 5000, "listPrice": 5000, "sellingPrice": 5000, "quantity": 1, "seller": "1", "imageUrl": "https://example.com/image.png", "detailUrl": "/soccer-shirt/p", "availability": "available", "additionalInfo": { "brandName": "Ollie", "brandId": "2000001" }, "productCategories": { "2": "Apparel" } } ], "totalizers": [ { "id": "Items", "name": "Items Total", "value": 5000 } ], "shippingData": { "address": null, "logisticsInfo": [ { "itemIndex": 0, "selectedSla": null, "shipsTo": ["USA", "BRA", "NLD"] } ], "selectedAddresses": [] }, "clientProfileData": null, "paymentData": { "paymentSystems": [ { "id": 1, "name": "American Express", "groupName": "creditCardPaymentGroup" } ], "payments": [], "giftCards": [] }, "sellers": [ { "id": "1", "name": "VTEX - EUA", "logo": "" } ], "storePreferencesData": { "countryCode": "USA", "currencyCode": "USD", "currencySymbol": "$" } } ``` For a complete reference of all VTEX orderForm fields, see the [VTEX orderForm Fields documentation](https://developers.vtex.com/docs/guides/orderform-fields). The `__RAW_CHECKOUT_SESSION__` structure varies by platform. The properties shown above are specific to VTEX. Shopify and other platforms will have different structures. ## Accessing Session Data ### In Custom Components Use the [`useCheckoutSession`](/ollie-shop/api/useCheckoutSession) hook to access session data reactively in your components: ```typescript theme={"system"} import { useCheckoutSession } from "@ollie-shop/sdk"; export default function MyComponent() { const { session } = useCheckoutSession(); return

Total: {session.totals.total}

; } ``` ### In GTM Custom HTML Tags Access the global objects directly in [GTM Custom HTML tags](/ollie-shop/analytics/gtm-enrichment): ```html theme={"system"} ``` ## Related * [useCheckoutSession Hook](/ollie-shop/api/useCheckoutSession) — React hook for accessing session data * [Enriching Events with GTM](/ollie-shop/analytics/gtm-enrichment) — Use session data in GTM tags # Slots Source: https://docs.ollie.shop/ollie-shop/concepts/slots Strategic placement points where components transform your checkout experience Slots are predefined blocks that structure a [Template](https://docs.ollie.shop/ollie-shop/concepts/templates) in Ollie Shop. Each slot is filled with a native component by default, but you can easily replace it with your own — no need to rebuild your entire checkout.