Shopify Integration Guide

This guide shows you how to integrate HempData API with a Shopify store to display compliance badges on product pages and automatically respond to regulation changes.

What You Can Do

  1. Compliance badge on product pages — Show visitors whether your product is legal in their state
  2. Age gate enforcement — Automatically prompt for age verification when required
  3. Shipping restrictions — Block checkout for prohibited states
  4. Regulation change alerts — Get notified when a state changes its rules and update your store accordingly

Part 1: Add the Compliance Widget to Product Pages

Step 1: Edit Your Theme

In your Shopify admin, go to Online Store > Themes > Edit code.

Open the product.liquid or main-product.liquid template (depends on your theme).

Step 2: Add the Widget Container

Find the "Add to Cart" button section and add the widget just above it:

{% comment %} HempData Compliance Widget {% endcomment %}
<div id="hempdata-widget" style="margin-bottom: 16px;"></div>

<script
  src="https://cdn.hempdataapi.com/widget/v1/hempdata-widget.js"
  data-api-key="pk_live_your_public_key"
  data-substance="{{ product.metafields.hempdata.substance | default: 'cbd' }}"
  data-product-type="{{ product.metafields.hempdata.product_type | default: 'edibles' }}"
  data-auto-detect-state="true"
></script>

Step 3: Set Product Metafields

For each product, set metafields to identify the substance and product type. In Shopify admin, go to Settings > Custom data > Products and add:

NamespaceKeyType
hempdatasubstanceSingle line text
hempdataproduct_typeSingle line text

Then set values on each product:

  • hempdata.substance = delta-9-thc
  • hempdata.product_type = edibles

Step 4: Disable Add to Cart for Prohibited States

Add this script after the widget:

<script>
  document.getElementById('hempdata-widget').addEventListener('hempdata:loaded', function(e) {
    if (e.detail.legal_status === 'prohibited') {
      // Disable the add to cart button
      var cartBtn = document.querySelector('[name="add"]') || document.querySelector('.product-form__submit');
      if (cartBtn) {
        cartBtn.disabled = true;
        cartBtn.textContent = 'Not Available in Your State';
        cartBtn.style.opacity = '0.5';
        cartBtn.style.cursor = 'not-allowed';
      }
    }
  });
</script>

Step 5: Style to Match Your Theme

#hempdata-widget {
  --hd-badge-font-family: var(--font-body-family, sans-serif);
  --hd-badge-border-radius: 4px;
  --hd-badge-max-width: 100%;
  --hd-green-bg: #16a34a;
  --hd-yellow-bg: #ca8a04;
  --hd-red-bg: #dc2626;
}

Part 2: Block Shipping to Prohibited States

Use Shopify's carrier-calculated shipping or a shipping profile with HempData to block orders to states where your products are prohibited.

Using a Shopify Function (Shopify Plus)

If you are on Shopify Plus, create a Delivery Customization function:

// extensions/delivery-customization/src/index.js
import { HempDataClient } from '@hempdataapi/sdk';

const client = new HempDataClient({ apiKey: process.env.HEMPDATA_API_KEY });

export default async function deliveryCustomization(input) {
  const state = input.cart.deliveryGroups[0]?.deliveryAddress?.provinceCode;
  if (!state) return { operations: [] };

  // Check each line item
  const operations = [];
  for (const group of input.cart.deliveryGroups) {
    for (const item of group.cartLines) {
      const substance = item.merchandise.product.metafield?.value;
      if (!substance) continue;

      const result = await client.regulations.list({
        state,
        substance,
        product_type: item.merchandise.product.productType,
      });

      if (result.data[0]?.legal_status === 'prohibited') {
        // Hide all delivery options for this group
        for (const option of group.deliveryOptions) {
          operations.push({
            hide: { deliveryOptionHandle: option.handle },
          });
        }
      }
    }
  }

  return { operations };
}

Without Shopify Plus

For standard Shopify plans, maintain a list of blocked states and use Shopify's built-in shipping zones. Use the HempData API to keep this list updated:

// scripts/update-shipping-restrictions.js
// Run daily via cron or on webhook events

const { HempDataClient } = require('@hempdataapi/sdk');

const client = new HempDataClient({ apiKey: process.env.HEMPDATA_API_KEY });

async function getProhibitedStates(substance, productType) {
  const states = await client.states.list();
  const prohibited = [];

  for (const state of states.data) {
    const regs = await client.regulations.list({
      state: state.code,
      substance,
      product_type: productType,
    });

    if (regs.data.some(r => r.legal_status === 'prohibited')) {
      prohibited.push(state.code);
    }
  }

  return prohibited;
}

// Get prohibited states for Delta-9 edibles
getProhibitedStates('delta-9-thc', 'edibles').then(states => {
  console.log('Blocked states:', states);
  // Update your Shopify shipping zones via Admin API
});

Part 3: Webhook Alerts for Regulation Changes

Set up webhooks (Enterprise tier) to automatically update your store when regulations change.

Register the Webhook

curl -X POST "https://api.hempdataapi.com/v1/webhooks" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "endpoint_url": "https://your-shopify-app.herokuapp.com/webhooks/hempdata",
    "filters": {
      "substances": ["delta-9-thc", "delta-8-thc", "cbd"],
      "event_types": ["legal_status_changed"]
    },
    "description": "Shopify store shipping restriction updates"
  }'

Handle the Webhook

const express = require('express');
const crypto = require('crypto');
const Shopify = require('@shopify/shopify-api');

const app = express();

app.post('/webhooks/hempdata', express.raw({ type: 'application/json' }), async (req, res) => {
  // Verify signature
  const signature = req.headers['x-hempdata-signature'];
  const expected = crypto.createHmac('sha256', process.env.HEMPDATA_WEBHOOK_SECRET)
    .update(req.body, 'utf8').digest('hex');
  if (!crypto.timingSafeEqual(Buffer.from(signature, 'hex'), Buffer.from(expected, 'hex'))) {
    return res.status(401).send('Invalid signature');
  }

  res.status(200).send('OK');

  const event = JSON.parse(req.body);

  if (event.event_type === 'legal_status_changed') {
    const state = event.jurisdiction.state;
    const newStatus = event.after.legal_status;

    console.log(`${state} changed to ${newStatus} for ${event.substance} ${event.product_type}`);

    // Notify your team
    await sendSlackAlert(event);

    // If a state just prohibited a product, update shipping zones
    if (newStatus === 'prohibited') {
      await addStateToBlockedShipping(state);
    }

    // If a state just legalized a product, consider opening it up
    if (newStatus === 'legal' || newStatus === 'legal_with_restrictions') {
      await reviewStateForShipping(state);
    }
  }
});

Architecture Overview

Shopify Product Page
  |
  +-- HempData Widget (client-side)
  |     - Checks compliance for visitor's state
  |     - Shows badge + age gate
  |     - Disables cart if prohibited
  |
  +-- Shipping Restriction (server-side)
  |     - Blocks delivery to prohibited states
  |     - Updated via webhooks or daily sync
  |
  +-- Webhook Handler (server-side)
        - Receives regulation change alerts
        - Updates shipping zones
        - Notifies team via Slack

Testing

  1. Test the widget — Use data-state="TX" to force a specific state and verify all three badge colors appear correctly for your products.
  2. Test the age gate — Use a THC product with data-state="CO" to trigger the age verification modal.
  3. Test shipping blocks — Create a test order with a Texas shipping address for a prohibited product.
  4. Test webhooks — Check the HempData dashboard for delivery logs after registering your endpoint.