Embeddable Compliance Widget
The HempData compliance widget lets you embed a real-time legal status badge on any website. It shows visitors whether a hemp product is legal in their state using color-coded indicators. Available on Professional and Enterprise tiers.
POST /v1/widget/check
Server-side compliance check endpoint. Use this if you want to build your own UI instead of using the embed script.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
substance | string | Yes | Substance identifier (e.g., delta-9-thc, cbd) |
product_type | string | Yes | Product type (e.g., edibles, topicals) |
state | string | Yes | Two-letter state code |
Request Example
curl -X POST "https://api.hempdataapi.com/v1/widget/check" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"substance": "delta-9-thc",
"product_type": "edibles",
"state": "CO"
}'
Response Example
{
"success": true,
"data": {
"state": "CO",
"state_name": "Colorado",
"substance": "delta-9-thc",
"product_type": "edibles",
"legal_status": "legal_with_restrictions",
"badge_color": "yellow",
"headline": "Legal with Restrictions",
"summary": "Delta-9 THC edibles are legal in Colorado for adults 21+ with licensed retail sale.",
"restrictions": [
"Must be 21 or older to purchase",
"Maximum 10mg THC per serving",
"Maximum 100mg THC per package",
"Must be purchased from a licensed retailer"
],
"age_gate_required": true,
"minimum_age": 21,
"confidence": 0.94,
"last_verified": "2026-03-18T06:00:00Z",
"regulation_id": "reg_a1b2c3d4-5678-9012-abcd-ef3456789012"
},
"meta": {
"request_id": "req_widget_001"
},
"errors": []
}
Badge Colors
| Color | CSS Class | Meaning |
|---|---|---|
green | hd-badge--green | Legal — Product is fully legal in this state |
yellow | hd-badge--yellow | Restricted — Legal with conditions (age, licensing, limits) |
red | hd-badge--red | Prohibited — Product is not legal in this state |
Script Tag Embed
Add the widget to any page with a single <script> tag and a container element.
Basic Usage
<!-- Widget container -->
<div id="hempdata-widget"></div>
<!-- Widget script -->
<script
src="https://cdn.hempdataapi.com/widget/v1/hempdata-widget.js"
data-api-key="YOUR_PUBLIC_API_KEY"
data-substance="delta-9-thc"
data-product-type="edibles"
data-state="CO"
></script>
With Auto-Detect State
Let the widget automatically detect the visitor's state via IP geolocation:
<div id="hempdata-widget"></div>
<script
src="https://cdn.hempdataapi.com/widget/v1/hempdata-widget.js"
data-api-key="YOUR_PUBLIC_API_KEY"
data-substance="delta-9-thc"
data-product-type="edibles"
data-auto-detect-state="true"
></script>
Script Tag Attributes
| Attribute | Required | Description |
|---|---|---|
data-api-key | Yes | Your public API key (different from your server API key; safe to expose in client-side code) |
data-substance | Yes | Substance to check (e.g., delta-9-thc, cbd) |
data-product-type | Yes | Product type to check (e.g., edibles, topicals) |
data-state | No | Two-letter state code. If omitted, use data-auto-detect-state. |
data-auto-detect-state | No | Set to "true" to detect state via IP geolocation. Ignored if data-state is set. |
Age Gate Modal
When a compliance check returns age_gate_required: true, the widget displays a modal asking the visitor to confirm their age before showing the product page.
Default Behavior
- Widget loads and performs the compliance check.
- If
age_gate_requiredistrue, an overlay modal appears asking: "Are you [minimum_age] or older?" - If the visitor clicks Yes, the modal closes and the badge is displayed.
- If the visitor clicks No, they are shown a message that the product is not available to them.
- The age confirmation is stored in
localStoragefor 24 hours to avoid repeated prompts.
Customizing the Age Gate
<script
src="https://cdn.hempdataapi.com/widget/v1/hempdata-widget.js"
data-api-key="YOUR_PUBLIC_API_KEY"
data-substance="delta-9-thc"
data-product-type="edibles"
data-auto-detect-state="true"
data-age-gate-title="Age Verification Required"
data-age-gate-message="You must be at least {age} years old to view this product."
data-age-gate-confirm="I am {age} or older"
data-age-gate-deny="I am under {age}"
data-age-gate-denied-url="/age-restricted"
></script>
The {age} placeholder is replaced with the actual minimum age from the compliance check.
CSS Customization
The widget uses CSS custom properties (variables) for full visual customization. Override them on the #hempdata-widget container or globally.
All CSS Custom Properties
#hempdata-widget {
/* Badge colors */
--hd-green-bg: #16a34a;
--hd-green-text: #ffffff;
--hd-green-border: #15803d;
--hd-yellow-bg: #eab308;
--hd-yellow-text: #1a1a1a;
--hd-yellow-border: #ca8a04;
--hd-red-bg: #dc2626;
--hd-red-text: #ffffff;
--hd-red-border: #b91c1c;
/* Badge layout */
--hd-badge-padding: 12px 16px;
--hd-badge-border-radius: 8px;
--hd-badge-font-size: 14px;
--hd-badge-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
--hd-badge-font-weight: 600;
--hd-badge-max-width: 400px;
--hd-badge-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
/* Badge icon */
--hd-icon-size: 20px;
--hd-icon-gap: 8px;
/* Restrictions list */
--hd-restrictions-font-size: 12px;
--hd-restrictions-color: #555555;
--hd-restrictions-margin-top: 8px;
--hd-restrictions-line-height: 1.5;
/* Confidence indicator */
--hd-confidence-show: block; /* set to 'none' to hide */
--hd-confidence-font-size: 11px;
--hd-confidence-color: #888888;
/* Last verified timestamp */
--hd-verified-show: block; /* set to 'none' to hide */
--hd-verified-font-size: 10px;
--hd-verified-color: #aaaaaa;
/* Age gate modal */
--hd-modal-overlay-bg: rgba(0, 0, 0, 0.6);
--hd-modal-bg: #ffffff;
--hd-modal-text-color: #1a1a1a;
--hd-modal-border-radius: 12px;
--hd-modal-padding: 32px;
--hd-modal-max-width: 480px;
--hd-modal-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
--hd-modal-title-font-size: 20px;
--hd-modal-message-font-size: 16px;
--hd-modal-button-confirm-bg: #16a34a;
--hd-modal-button-confirm-text: #ffffff;
--hd-modal-button-deny-bg: #e5e7eb;
--hd-modal-button-deny-text: #374151;
--hd-modal-button-border-radius: 6px;
--hd-modal-button-padding: 12px 24px;
--hd-modal-button-font-size: 14px;
/* Powered-by footer */
--hd-footer-show: block; /* set to 'none' to hide on Enterprise tier */
--hd-footer-font-size: 10px;
--hd-footer-color: #cccccc;
}
Example: Dark Theme
#hempdata-widget {
--hd-green-bg: #22c55e;
--hd-green-text: #000000;
--hd-yellow-bg: #facc15;
--hd-yellow-text: #000000;
--hd-red-bg: #ef4444;
--hd-red-text: #000000;
--hd-badge-shadow: 0 1px 3px rgba(255, 255, 255, 0.05);
--hd-restrictions-color: #cccccc;
--hd-confidence-color: #999999;
--hd-verified-color: #777777;
--hd-modal-bg: #1f2937;
--hd-modal-text-color: #f3f4f6;
--hd-modal-shadow: 0 20px 60px rgba(0, 0, 0, 0.6);
}
Widget Events
The widget emits custom DOM events on the container element for integration with your application:
const widget = document.getElementById('hempdata-widget');
widget.addEventListener('hempdata:loaded', (e) => {
console.log('Widget loaded:', e.detail);
// e.detail.legal_status, e.detail.badge_color, etc.
});
widget.addEventListener('hempdata:age-confirmed', (e) => {
console.log('User confirmed age:', e.detail.minimum_age);
});
widget.addEventListener('hempdata:age-denied', () => {
console.log('User denied age requirement');
});
widget.addEventListener('hempdata:error', (e) => {
console.error('Widget error:', e.detail.message);
});
Multiple Widgets on One Page
Use unique container IDs and the data-container attribute:
<div id="widget-edibles"></div>
<div id="widget-topicals"></div>
<script
src="https://cdn.hempdataapi.com/widget/v1/hempdata-widget.js"
data-api-key="YOUR_PUBLIC_API_KEY"
data-container="widget-edibles"
data-substance="delta-9-thc"
data-product-type="edibles"
data-auto-detect-state="true"
></script>
<script
src="https://cdn.hempdataapi.com/widget/v1/hempdata-widget.js"
data-api-key="YOUR_PUBLIC_API_KEY"
data-container="widget-topicals"
data-substance="cbd"
data-product-type="topicals"
data-auto-detect-state="true"
></script>