Custom Add to Cart Integration

Last updated: July 30, 2026

This guide explains how to use your own Add to Cart button instead of Customily's built-in one. This is useful when you need full control over the checkout flow or want to integrate the add-to-cart action into your platform's native UI.

How It Works

When using Customily's built-in Add to Cart button, the iframe automatically performs three operations and sends the result to the parent page via postMessage.

If you want to use your own button, you'll need to hide Customily's button and call these operations yourself using the Customily engraver window object.

The three operations are:

  1. Generate the production file request — reserves a URL for the production-ready file.

  2. Generate a preview thumbnail (optional) — uploads a preview image and returns a CDN URL.

  3. Create a cart record (optional) — saves the personalization data on Customily's server so you can view the cart details from Customily's Orders dashboard.

Keep in mind

Only generating the production file request is required. Creating a preview thumbnail and cart record is optional, but recommended for a better shopper experience and easier order fulfillment.


Implementation

Generate the Production File Request

Call generatePFRPostOrder() on the engraver to create the production file request:

const exportedFiles = await window.engraver.generatePFRPostOrder('');
// Store the url(s) — you'll need them to call item/generate after checkout
const productionFileUrls = exportedFiles.map(f => f.url);

Returns: an array of production file URLs (one per template side):

[
    { "url": "https://cdn.customily.com/ExportFile/..." },
    { "url": "https://cdn.customily.com/ExportFile/..." }  // if the template has multiple sides
]

Note

The url is a placeholder — the actual file won't be available until you call the item/generate endpoint after checkout.

Generate the Preview Thumbnail (Optional)

Call generatePreviewImage() to upload a preview and get a CDN URL:

const preview = await window.engraver.generatePreviewImage({
    shop: 'yourstandalonestore.com'
});

Returns:

{
    "filename": "c611faa2-...",
    "previewUrl": "https://cdn.customily.com/shopify/assetFiles/previews/yourstandalonestore.com/c611faa2-....jpeg",
    "thumbnailUrl": "https://cdn.customily.com/..."
}
  • previewUrl — a 1000 Ă— 1000 high-quality image, ideal for sending to shoppers via email so they can see how their personalization looks.

  • thumbnailUrl — a smaller image, better suited for displaying the item in the shopping cart.

Create the Cart Record (Optional)

Creating a cart record stores the personalization data on Customily's server so you can view it later from the Orders dashboard (đź“„ Viewing Orders in Customily)

Post the personalization data to Customily's cart endpoint:

const response = await fetch('https://sh.customily.com/api/standalone/cart?shop=yourstandalonestore.com', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
        productId: window.engraver.currentProduct.id,
        quantity: 1,
        orderId: '10001',  // your platform's order ID (optional)
        sessionId: window.engraver.getSessionId(),
        previewUrl: preview.previewUrl,
        exportedFiles: exportedFiles,
        options: [
            { name: "Name", value: "John", type: "Text Input" },
            { name: "Date", value: "June 15, 2025", type: "Text Input" },
            { name: "Font", value: "Script", type: "Dropdown" },
            { name: "Photo", value: window.engraver.getElementsUrls('image', 1)[0], type: "Image Upload" }
        ]
    })
});

const cartItem = await response.json();
// cartItem.id is the personalizationGUID
  • Populate the options array with the shopper's selections. Each entry should contain a name, value, and type.

  • Providing an orderId is optional. If supplied, you can later retrieve every personalization item associated with that order.

Complete Example

The following example combines all three operations into a complete custom Add to Cart implementation.

async function customilyAddToCart(shop, quantity, options, orderId) {
    // 1. Generate production file request
    const exportedFiles = await window.engraver.generatePFRPostOrder('');

    // 2. Generate preview thumbnail
    const preview = await window.engraver.generatePreviewImage({ shop });

    // 3. Wait for any pending file uploads to complete.
    // When a shopper uploads an image or vector, Customily immediately starts uploading
    // the file in the background. For large files, it's possible the shopper clicks
    // "Add to Cart" before the upload finishes. Calling waitFilesUpload() ensures all
    // pending uploads are complete before proceeding, so no files are missing from the order.
    await window.engraver.waitFilesUpload();

    // 4. Create cart record
    const response = await fetch(`https://sh.customily.com/api/standalone/cart?shop=${shop}`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
            productId: window.engraver.currentProduct.id,
            quantity: quantity,
            orderId: orderId,
            sessionId: window.engraver.getSessionId(),
            previewUrl: preview.previewUrl,
            exportedFiles: exportedFiles,
            options: options
        })
    });

    const cartItem = await response.json();

    return {
        personalizationGUID: cartItem.id,
        previewUrl: preview.previewUrl,
        exportedFiles: exportedFiles
    };
}

// Usage
document.getElementById('my-add-to-cart-btn').addEventListener('click', async () => {
    // Collect the shopper's selections from your form
    const options = [
        { name: "Name", value: document.getElementById('name-input').value, type: "Text Input" },
        { name: "Date", value: document.getElementById('date-input').value, type: "Text Input" },
        { name: "Font", value: document.getElementById('font-select').value, type: "Dropdown" },
        { name: "Photo", value: window.engraver.getElementsUrls('image', 1)[0], type: "Image Upload" }
    ];

    const result = await customilyAddToCart('yourstandalonestore.com', 1, options, '10001');
    console.log('Added to cart:', result.personalizationGUID);
    console.log('Preview:', result.previewUrl);

    // Add to your platform's cart here...
});

Accessing Personalization Data After Checkout

After the order is placed, you'll need access to the shopper's personalization details and production file URLs during fulfillment.

If you stored the complete personalization payload when the item was added to the cart, you'll already have everything you need.

If you only stored the personalizationGUID or orderId, see Retrieving Personalization Details & Production Files to learn how to retrieve the personalization data later.

Relevant JavaScript Methods

The following window.engraver methods and properties are relevant to the add-to-cart flow:

Method

Returns

Description

generatePFRPostOrder('')

Promise<[{ url }]>

Generates the production file request (one entry per template side)

generatePreviewImage(options)

Promise<{ previewUrl, thumbnailUrl, filename }>

Uploads preview image, returns CDN URLs

waitFilesUpload()

Promise<void>

Waits for pending image/vector uploads to complete

getElementsUrls(type, id)

string[]

Gets Customily-hosted URLs for shopper uploaded images ('image') or vectors ('vector') by template element ID

currentProduct.id

string

The current template ID