> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orderprotection.com/llms.txt
> Use this file to discover all available pages before exploring further.

# A/B Testing

> Set up, configure, and analyze A/B tests in the Order Protection app for Shopify.

## Setting Up Your Test Settings in Shopify

Before you can start your A/B tests within the Order Protection app, you need to configure a few settings.

<Steps>
  <Step title="Enable a New Custom Pixel">
    From Settings, click on <code>Customer Events</code>.

    <img src="https://mintcdn.com/orderprotectioncom/GDuchlp6KbhScehe/public/assets/img/shopify/ab-test-customer-events.png?fit=max&auto=format&n=GDuchlp6KbhScehe&q=85&s=cfa4580e360fc67c2dd1b34a3846fad0" alt="" width="2866" height="1668" data-path="public/assets/img/shopify/ab-test-customer-events.png" />

    Once in the Customer Events settings, click <code>Add custom pixel</code>. Name it "Order Protection A/B Testing" or something similar to know the testing is originating in the OP app.

    <img src="https://mintcdn.com/orderprotectioncom/GDuchlp6KbhScehe/public/assets/img/shopify/ab-test-add-custom-pixels.png?fit=max&auto=format&n=GDuchlp6KbhScehe&q=85&s=a121a0d537c59cee8a50dcb6dc09e3cc" alt="" width="2866" height="1686" data-path="public/assets/img/shopify/ab-test-add-custom-pixels.png" />
  </Step>

  <Step title="Add the Code Script">
    Once the pixel is added, add the custom script below.

    ```javascript expandable theme={null}
    analytics.subscribe('checkout_completed', async event => {
      const STORE_URL = 'kysonteststore4.myshopify.com';
      const API_BASE = 'https://api.production.orderprotection.com/v1';

      function transformSettings(settings) {
        return {
          variants: settings.variants,
          settings: {
            default_op: settings.automaticallyAddToCart,
            dynamic_price: true,
            dynamic_price_range: settings.rules.map(rule => {
              const term = rule.terms.customer || rule.terms.brand;
              return {
                value: rule.min * 100,
                max: rule.max * 100,
                insuranceCost: term.type === 'percentage' ? term.amount : term.amount * 100,
                isPercentage: term.type === 'percentage',
                paidBy: rule.terms.customer ? 'customer' : 'brand',
              };
            }),
            splitTestSettings: settings.splitTestSettings || null,
          },
        };
      }

      function extractSplitTestFromWidgetConfig(widgetConfig) {
        const configArray = Array.isArray(widgetConfig) ? widgetConfig : [widgetConfig];
        const configWithSplitTest = configArray.find(c => c?.splitTestSettings?.token);
        return configWithSplitTest?.splitTestSettings || null;
      }

      async function fetchWidgetConfig(widgetType) {
        const response = await fetch(`${API_BASE}/widget/config?id=${STORE_URL}&type=${widgetType}`);
        if (!response.ok) return null;
        const widgetConfig = await response.json();
        return extractSplitTestFromWidgetConfig(widgetConfig);
      }

      async function checkWidgetViewed(testId, token) {
        const response = await fetch(`${API_BASE}/tests/${testId}/${token}`);
        return response.ok;
      }

      async function getWidgetStyleSplitTest(testId) {
        const widgetTypes = ['CHECKOUT', 'CART'];
        const results = await Promise.allSettled(widgetTypes.map(fetchWidgetConfig));
        const splitTestSettings = results.find(r => r.status === 'fulfilled' && r.value)?.value || null;

        if (!splitTestSettings?.token) return null;

        const wasViewed = await checkWidgetViewed(testId, splitTestSettings.token);
        if (!wasViewed) return null;

        return splitTestSettings;
      }

      async function getNonWidgetStyleSplitTest(testId) {
        const storeResponse = await fetch(`${API_BASE}/quote/insurance?store_url=${STORE_URL}`);
        if (!storeResponse.ok) return null;

        const rawStoreSettings = await storeResponse.json();
        const store_settings = transformSettings(rawStoreSettings);
        const splitTestFromStore = store_settings?.settings?.splitTestSettings;

        if (!splitTestFromStore?.token) return null;

        const viewedWidgetResponse = await fetch(`${API_BASE}/tests/${testId}/${splitTestFromStore.token}`);
        if (!viewedWidgetResponse.ok) return null;

        return splitTestFromStore;
      }

      function sendTestEvent(splitTestSettings, orderId, purchasedOp) {
        fetch(`${API_BASE}/tests/event`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            type: 'checkout:completed',
            testId: splitTestSettings.id,
            sessionId: splitTestSettings.token,
            metadata: {
              isOriginal: splitTestSettings.isOriginal,
              settingsType: splitTestSettings.type,
              orderId,
              purchasedOp,
            },
          }),
        }).catch(err => console.error('Failed to send test event:', err));
      }

      async function initSplitTest() {
        try {
          const testResponse = await fetch(`${API_BASE}/tests?store=${STORE_URL}`);
          if (!testResponse.ok) return;

          const hasSplitTest = await testResponse.json();
          if (!hasSplitTest?.active || !hasSplitTest?.test) return;

          const isWidgetStyleTest = hasSplitTest.test.type === 'WIDGET_STYLE';
          const testId = hasSplitTest.test.id;

          const splitTestSettings = isWidgetStyleTest ? await getWidgetStyleSplitTest(testId) : await getNonWidgetStyleSplitTest(testId);

          if (!splitTestSettings?.token) return;

          const purchasedOp = event.data.checkout.lineItems.some(
            item => item.variant.product.vendor === 'Order Protection',
          );
          const orderId = event.data.checkout.order.id;

          sendTestEvent(splitTestSettings, orderId, purchasedOp);
        } catch (error) {
          console.error('Error in initSplitTest:', error);
        }
      }

      initSplitTest();
    });
    ```

    It should look something like this.

    <img src="https://mintcdn.com/orderprotectioncom/qPn_wkuPR5MS2_fF/public/assets/img/shopify/ab-test-add-code-script.png?fit=max&auto=format&n=qPn_wkuPR5MS2_fF&q=85&s=4aab005d3eed9d07d9f2f526deac5bc6" alt="" width="2622" height="1678" data-path="public/assets/img/shopify/ab-test-add-code-script.png" />

    Before you save the file, you need to swap out the following in quotations <code>const STORE\_URL = 'kysonteststore4.myshopify.com';</code>
    with your Shopify store URL. The store URL can be found at the top of the left navigation in settings as well as at the top of the current custom pixel page you are populating.
    This URL **must** be your myshopify URL for it to work properly. The Shopify URL will be something similar to: <code>\{store\_name}.myshopify.com</code>.
  </Step>

  <Step title="Configure Customer Privacy Settings">
    Scroll to the <code>Customer privacy</code> section of the custom pixel and configure the following settings so the pixel always runs and can collect the data needed for A/B testing:

    * **Permission**: Select <code>Not required</code>. The pixel will always run.
    * **Data sale**: Select <code>Data collected does not qualify as data sale</code>.

          <img src="https://mintcdn.com/orderprotectioncom/9g_vfDkEo6VGfceB/public/assets/img/shopify/ab-test-customer-privacy.png?fit=max&auto=format&n=9g_vfDkEo6VGfceB&q=85&s=9a616e2dc9ca03854c0e2903ea921555" alt="Customer privacy settings for the A/B testing pixel" width="1444" height="954" data-path="public/assets/img/shopify/ab-test-customer-privacy.png" />
  </Step>

  <Step title="Save and Connect the Pixel">
    After saving the custom pixel, make sure to **Connect** it from the custom pixel page. A saved pixel will not fire until it is connected, and your A/B test will not receive any event data until this step is completed. 🙌
  </Step>

  <Step title="Starting an A/B Test in the Order Protection App">
    Now that you have configured your custom pixel, you're ready to start A/B testing. Log back in to app.orderprotection.com, navigate to to the <code>A/B Tests</code> tab
    in the left navigation and click on <code>Start New Test</code> to get started. Session data will start rolling into the test analytics within a few minutes. Expect 1-2 weeks for results to
    reach statistical significance depending on your store traffic volume.
  </Step>
</Steps>

***

## What You Can Test

When creating a new A/B test, you'll choose from three test types. Each type isolates a different variable so you can measure its impact on conversions and revenue.

<img src="https://mintcdn.com/orderprotectioncom/LxVsZXNdOSwuzeBW/public/assets/img/shopify/ab-test-1-setting-up-test.png?fit=max&auto=format&n=LxVsZXNdOSwuzeBW&q=85&s=8f0792fb3bb244c5571a9987ff17e52d" alt="Creating a new A/B test" width="2448" height="1534" data-path="public/assets/img/shopify/ab-test-1-setting-up-test.png" />

<CardGroup cols={3}>
  <Card title="Widget" icon="toggle-on">
    Test whether the Order Protection widget defaults to **on** or **off** for
    customers at checkout. This is the most common test type for measuring
    opt-in vs. opt-out behavior.
  </Card>

  <Card title="Price" icon="dollar-sign">
    Test different pricing structures to find the optimal balance between
    customer conversion and revenue. Compare your current pricing against a
    variant with adjusted rates.
  </Card>

  <Card title="Widget Style" icon="palette">
    Test different widget designs and layouts to see which style drives the
    highest engagement and attach rate.
  </Card>
</CardGroup>

***

## Configuring Your Test

After selecting your test type, you'll configure the test details. Each test type has its own configuration options.

### Pricing Tests

When you select **Price** as the test type, you'll see your current pricing displayed as the **Original** variant. This is pulled directly from your store's existing price settings and cannot be edited within the test — it serves as your control group.

Create a **Variant** with adjusted pricing to test against the original. You can modify both the flat rate and percentage-based pricing tiers for different order value ranges.

<img src="https://mintcdn.com/orderprotectioncom/LxVsZXNdOSwuzeBW/public/assets/img/shopify/ab-test-2-types-of-tests-pricing.png?fit=max&auto=format&n=LxVsZXNdOSwuzeBW&q=85&s=5785400d7ff7a45c0a06920cdf58a1c9" alt="Configuring a pricing A/B test" width="2454" height="1542" data-path="public/assets/img/shopify/ab-test-2-types-of-tests-pricing.png" />

<Warning>
  Once you start a test, you will not be able to edit the variants to maintain
  the integrity of the test. You can always end the test and start a new one if
  you need to adjust your pricing.
</Warning>

### Widget Style Tests

Widget style tests let you compare two different widget designs to determine which performs better. Before setting up this test type, you'll need at least two widget configurations created in the **Customizations** section.

<Tip>
  To learn how to create and customize widgets, see the [Widget
  Customization](/education-basecamp/widgets) guide.
</Tip>

Navigate to **Customizations > Widgets** to view your available widget configurations. You'll need both a published widget (your control) and at least one additional widget to use as a variant.

<img src="https://mintcdn.com/orderprotectioncom/LxVsZXNdOSwuzeBW/public/assets/img/shopify/ab-test-4-widget-style-design-widget.png?fit=max&auto=format&n=LxVsZXNdOSwuzeBW&q=85&s=5e4f83501e78903fbd2b34ad1a9b1110" alt="Available widgets in Customizations" width="2458" height="1546" data-path="public/assets/img/shopify/ab-test-4-widget-style-design-widget.png" />

When you select **Widget Style** as the test type, a widget picker will appear showing your available widget configurations. Each widget has an **Add To A/B Test** button — select the widgets you want to compare.

<img src="https://mintcdn.com/orderprotectioncom/LxVsZXNdOSwuzeBW/public/assets/img/shopify/ab-test-5-widget-style-add-to-test.png?fit=max&auto=format&n=LxVsZXNdOSwuzeBW&q=85&s=f0529e619c985d73681a4bb4add68326" alt="Selecting widgets for your A/B test" width="2454" height="1524" data-path="public/assets/img/shopify/ab-test-5-widget-style-add-to-test.png" />

Once selected, you'll see a preview of each variant showing the control widget and the variant widget side by side.

<img src="https://mintcdn.com/orderprotectioncom/LxVsZXNdOSwuzeBW/public/assets/img/shopify/ab-test-3-types-of-tests-widget-styling.png?fit=max&auto=format&n=LxVsZXNdOSwuzeBW&q=85&s=d3d2f1e38bd63adea0739385d0716861" alt="Widget style test with control and variant" width="2454" height="1534" data-path="public/assets/img/shopify/ab-test-3-types-of-tests-widget-styling.png" />

***

## Checking Your Results

Once your test is running, you can monitor results in real time from the **A/B Tests** tab. Click on any active or completed test to view the results dashboard.

<img src="https://mintcdn.com/orderprotectioncom/LxVsZXNdOSwuzeBW/public/assets/img/shopify/ab-test-6-checking-results.png?fit=max&auto=format&n=LxVsZXNdOSwuzeBW&q=85&s=13cf398e80bdee784fd28f112a7bb862" alt="A/B test results dashboard" width="2014" height="2018" data-path="public/assets/img/shopify/ab-test-6-checking-results.png" />

<Note>
  All metrics are calculated starting from when the A/B test was launched — not
  from when your store was created or when Order Protection was installed. This
  ensures a clean comparison between your test variants.
</Note>

### Understanding Your Metrics

The results dashboard shows a summary row at the top with key winner indicators, a time-series chart for tracking trends, and a detailed comparison table. Here's what each metric means:

| Metric                    | What It Measures                                                                                                       |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| **Views**                 | The number of times the Order Protection widget was displayed to customers in each variant.                            |
| **Conversions**           | The number of completed checkouts per variant, regardless of whether Order Protection was purchased.                   |
| **CVR (Conversion Rate)** | The percentage of widget views that resulted in a completed checkout. Calculated as `Conversions / Views`.             |
| **Attach Rate**           | The percentage of orders that included Order Protection, per variant. Calculated as `Protected Orders / Total Orders`. |
| **Profit**                | Estimated profit generated from Order Protection fees based on your revenue share agreement.                           |

<AccordionGroup>
  <Accordion title="Views">
    Views represent the total number of times the Order Protection widget was rendered and visible to a customer during their shopping session. Each unique session where the widget loads counts as one view.

    The results table breaks views down per variant, so you can see whether traffic was split evenly. A significant imbalance in views between variants may indicate that the test needs more time to normalize.
  </Accordion>

  <Accordion title="Conversions">
    Conversions track the number of completed purchases (checkouts) within each test variant. This metric captures all orders — both those that included Order Protection and those that did not.

    The **CVR (Conversion Rate)** is calculated as:

    `CVR = Conversions / Views x 100`

    The **CVR Compare to Original** column shows the percentage-point difference between each variant and the original, making it easy to spot whether a variant is helping or hurting overall checkout completion.
  </Accordion>

  <Accordion title="Attach Rate">
    Attach rate is the most important metric for most A/B tests. It measures the percentage of total orders in a variant that included Order Protection.

    `Attach Rate = Protected Orders / Total Orders x 100`

    For example, if 3,409 out of 5,171 orders in the Original variant included Order Protection, the attach rate is 65.93%. A higher attach rate means more customers are opting in to protection, directly increasing revenue.

    The **Attach Rate Winner** in the summary row highlights which variant achieved the highest attach rate.
  </Accordion>

  <Accordion title="Profit Calculation">
    Profit is calculated based on your **revenue share** agreement with Order Protection. This represents your store's estimated earnings from Order Protection fees collected during the test period.

    The calculation considers:

    * **Total Order Protection fees collected** per variant (based on the pricing tier and order values)
    * **Your revenue share percentage** — the portion of each fee that goes to your store
    * **Claim costs** are not factored into this metric; it reflects gross revenue share only

    The **Profit Winner** in the summary row indicates which variant generated the most revenue for your store. When evaluating profit, consider it alongside attach rate — a variant with slightly lower attach rate but higher pricing may still generate more total profit.
  </Accordion>
</AccordionGroup>

### Variant Details

At the bottom of the results page, you'll find **Variant Details** showing the exact configuration for each variant. This includes:

* Whether Order Protection was **on by default**
* Whether the **No Order Protection** option was provided
* Any widget style differences between variants
* For **Price** tests, the full pricing tiers and rates for each variant (flat rates, percentage-based rates, and order value ranges)

Use this section to recall exactly what was being tested, especially when reviewing results from older tests.
